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->init_delay_action = -1;
1301 g->anim_delay_fixed = 0;
1302 g->anim_delay_random = 0;
1303 g->anim_delay_action = -1;
1304 g->post_delay_fixed = 0;
1305 g->post_delay_random = 0;
1306 g->post_delay_action = -1;
1307 g->init_event = ANIM_EVENT_UNDEFINED;
1308 g->anim_event = ANIM_EVENT_UNDEFINED;
1309 g->init_event_action = -1;
1310 g->anim_event_action = -1;
1311 g->draw_masked = FALSE;
1313 g->fade_mode = FADE_MODE_DEFAULT;
1317 g->align = ALIGN_CENTER; // default for title screens
1318 g->valign = VALIGN_MIDDLE; // default for title screens
1319 g->sort_priority = 0; // default for title screens
1321 g->style = STYLE_DEFAULT;
1323 g->bitmaps = src_bitmaps;
1324 g->bitmap = src_bitmap;
1326 // optional zoom factor for scaling up the image to a larger size
1327 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1328 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1329 if (g->scale_up_factor < 1)
1330 g->scale_up_factor = 1; // no scaling
1332 // optional tile size for using non-standard image size
1333 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1335 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1338 // CHECK: should tile sizes less than standard tile size be allowed?
1339 if (g->tile_size < TILESIZE)
1340 g->tile_size = TILESIZE; // standard tile size
1343 // when setting tile size, also set width and height accordingly
1344 g->width = g->tile_size;
1345 g->height = g->tile_size;
1348 if (g->use_image_size)
1350 // set new default bitmap size (with scaling, but without small images)
1351 g->width = get_scaled_graphic_width(graphic);
1352 g->height = get_scaled_graphic_height(graphic);
1355 // optional width and height of each animation frame
1356 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1357 g->width = parameter[GFX_ARG_WIDTH];
1358 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1359 g->height = parameter[GFX_ARG_HEIGHT];
1361 // optional x and y tile position of animation frame sequence
1362 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1363 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1364 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1365 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1367 // optional x and y pixel position of animation frame sequence
1368 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1369 g->src_x = parameter[GFX_ARG_X];
1370 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1371 g->src_y = parameter[GFX_ARG_Y];
1377 Error(ERR_INFO_LINE, "-");
1378 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1379 g->width, getTokenFromImageID(graphic), TILEX);
1380 Error(ERR_INFO_LINE, "-");
1382 g->width = TILEX; // will be checked to be inside bitmap later
1387 Error(ERR_INFO_LINE, "-");
1388 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1389 g->height, getTokenFromImageID(graphic), TILEY);
1390 Error(ERR_INFO_LINE, "-");
1392 g->height = TILEY; // will be checked to be inside bitmap later
1398 // get final bitmap size (with scaling, but without small images)
1399 int src_image_width = get_scaled_graphic_width(graphic);
1400 int src_image_height = get_scaled_graphic_height(graphic);
1402 if (src_image_width == 0 || src_image_height == 0)
1404 // only happens when loaded outside artwork system (like "global.busy")
1405 src_image_width = src_bitmap->width;
1406 src_image_height = src_bitmap->height;
1409 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1411 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1412 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1416 anim_frames_per_row = MAX(1, src_image_width / g->width);
1417 anim_frames_per_col = MAX(1, src_image_height / g->height);
1420 g->src_image_width = src_image_width;
1421 g->src_image_height = src_image_height;
1424 // correct x or y offset dependent of vertical or horizontal frame order
1425 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1427 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1428 parameter[GFX_ARG_OFFSET] : g->height);
1429 anim_frames_per_line = anim_frames_per_col;
1431 else // frames are ordered horizontally
1433 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1434 parameter[GFX_ARG_OFFSET] : g->width);
1435 anim_frames_per_line = anim_frames_per_row;
1438 // optionally, the x and y offset of frames can be specified directly
1439 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1440 g->offset_x = parameter[GFX_ARG_XOFFSET];
1441 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1442 g->offset_y = parameter[GFX_ARG_YOFFSET];
1444 // optionally, moving animations may have separate start and end graphics
1445 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1447 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1448 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1450 // correct x or y offset2 dependent of vertical or horizontal frame order
1451 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1452 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1453 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1454 else // frames are ordered horizontally
1455 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1456 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1458 // optionally, the x and y offset of 2nd graphic can be specified directly
1459 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1460 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1461 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1462 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1464 // optionally, the second movement tile can be specified as start tile
1465 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1466 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1468 // automatically determine correct number of frames, if not defined
1469 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1470 g->anim_frames = parameter[GFX_ARG_FRAMES];
1471 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1472 g->anim_frames = anim_frames_per_row;
1473 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1474 g->anim_frames = anim_frames_per_col;
1478 if (g->anim_frames == 0) // frames must be at least 1
1481 g->anim_frames_per_line =
1482 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1483 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1485 g->anim_delay = parameter[GFX_ARG_DELAY];
1486 if (g->anim_delay == 0) // delay must be at least 1
1489 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1491 // automatically determine correct start frame, if not defined
1492 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1493 g->anim_start_frame = 0;
1494 else if (g->anim_mode & ANIM_REVERSE)
1495 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1497 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1499 // animation synchronized with global frame counter, not move position
1500 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1502 // optional element for cloning crumble graphics
1503 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1504 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1506 // optional element for cloning digging graphics
1507 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1508 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1510 // optional border size for "crumbling" diggable graphics
1511 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1512 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1514 // used for global animations and player "boring" and "sleeping" actions
1515 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1516 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1517 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1518 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1519 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1520 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1521 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1522 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1523 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1524 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1525 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1526 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1528 // used for global animations
1529 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1530 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1531 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1532 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1533 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1534 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1535 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1536 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1537 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1538 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1539 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1540 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1541 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1542 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1544 // used for toon animations and global animations
1545 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1546 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1547 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1548 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1549 g->direction = parameter[GFX_ARG_DIRECTION];
1550 g->position = parameter[GFX_ARG_POSITION];
1551 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1552 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1554 // this is only used for drawing font characters
1555 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1556 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1558 // use a different default value for global animations and toons
1559 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1560 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1561 g->draw_masked = TRUE;
1563 // this is used for drawing envelopes, global animations and toons
1564 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1565 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1567 // used for toon animations and global animations
1568 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1569 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1571 // optional graphic for cloning all graphics settings
1572 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1573 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1575 // optional settings for drawing title screens and title messages
1576 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1577 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1578 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1579 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1580 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1581 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1582 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1583 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1584 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1585 g->align = parameter[GFX_ARG_ALIGN];
1586 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1587 g->valign = parameter[GFX_ARG_VALIGN];
1588 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1589 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1591 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1592 g->class = parameter[GFX_ARG_CLASS];
1593 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1594 g->style = parameter[GFX_ARG_STYLE];
1596 // this is only used for drawing menu buttons and text
1597 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1598 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1599 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1600 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1603 static void set_graphic_parameters(int graphic)
1605 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1606 char **parameter_raw = image->parameter;
1607 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1608 int parameter[NUM_GFX_ARGS];
1611 // if fallback to default artwork is done, also use the default parameters
1612 if (image->fallback_to_default)
1613 parameter_raw = image->default_parameter;
1615 // get integer values from string parameters
1616 for (i = 0; i < NUM_GFX_ARGS; i++)
1617 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1618 image_config_suffix[i].token,
1619 image_config_suffix[i].type);
1621 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1623 UPDATE_BUSY_STATE();
1626 static void set_cloned_graphic_parameters(int graphic)
1628 int fallback_graphic = IMG_CHAR_EXCLAM;
1629 int max_num_images = getImageListSize();
1630 int clone_graphic = graphic_info[graphic].clone_from;
1631 int num_references_followed = 1;
1633 while (graphic_info[clone_graphic].clone_from != -1 &&
1634 num_references_followed < max_num_images)
1636 clone_graphic = graphic_info[clone_graphic].clone_from;
1638 num_references_followed++;
1641 if (num_references_followed >= max_num_images)
1643 Error(ERR_INFO_LINE, "-");
1644 Error(ERR_INFO, "warning: error found in config file:");
1645 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1646 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1647 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1648 Error(ERR_INFO, "custom graphic rejected for this element/action");
1650 if (graphic == fallback_graphic)
1651 Error(ERR_EXIT, "no fallback graphic available");
1653 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1654 Error(ERR_INFO_LINE, "-");
1656 graphic_info[graphic] = graphic_info[fallback_graphic];
1660 graphic_info[graphic] = graphic_info[clone_graphic];
1661 graphic_info[graphic].clone_from = clone_graphic;
1665 static void InitGraphicInfo(void)
1667 int fallback_graphic = IMG_CHAR_EXCLAM;
1668 int num_images = getImageListSize();
1671 // use image size as default values for width and height for these images
1672 static int full_size_graphics[] =
1675 IMG_GLOBAL_BORDER_MAIN,
1676 IMG_GLOBAL_BORDER_SCORES,
1677 IMG_GLOBAL_BORDER_EDITOR,
1678 IMG_GLOBAL_BORDER_PLAYING,
1681 IMG_BACKGROUND_ENVELOPE_1,
1682 IMG_BACKGROUND_ENVELOPE_2,
1683 IMG_BACKGROUND_ENVELOPE_3,
1684 IMG_BACKGROUND_ENVELOPE_4,
1685 IMG_BACKGROUND_REQUEST,
1688 IMG_BACKGROUND_TITLE_INITIAL,
1689 IMG_BACKGROUND_TITLE,
1690 IMG_BACKGROUND_MAIN,
1691 IMG_BACKGROUND_LEVELS,
1692 IMG_BACKGROUND_LEVELNR,
1693 IMG_BACKGROUND_SCORES,
1694 IMG_BACKGROUND_EDITOR,
1695 IMG_BACKGROUND_INFO,
1696 IMG_BACKGROUND_INFO_ELEMENTS,
1697 IMG_BACKGROUND_INFO_MUSIC,
1698 IMG_BACKGROUND_INFO_CREDITS,
1699 IMG_BACKGROUND_INFO_PROGRAM,
1700 IMG_BACKGROUND_INFO_VERSION,
1701 IMG_BACKGROUND_INFO_LEVELSET,
1702 IMG_BACKGROUND_SETUP,
1703 IMG_BACKGROUND_PLAYING,
1704 IMG_BACKGROUND_DOOR,
1705 IMG_BACKGROUND_TAPE,
1706 IMG_BACKGROUND_PANEL,
1707 IMG_BACKGROUND_PALETTE,
1708 IMG_BACKGROUND_TOOLBOX,
1710 IMG_TITLESCREEN_INITIAL_1,
1711 IMG_TITLESCREEN_INITIAL_2,
1712 IMG_TITLESCREEN_INITIAL_3,
1713 IMG_TITLESCREEN_INITIAL_4,
1714 IMG_TITLESCREEN_INITIAL_5,
1721 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1722 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1723 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1724 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1725 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1726 IMG_BACKGROUND_TITLEMESSAGE_1,
1727 IMG_BACKGROUND_TITLEMESSAGE_2,
1728 IMG_BACKGROUND_TITLEMESSAGE_3,
1729 IMG_BACKGROUND_TITLEMESSAGE_4,
1730 IMG_BACKGROUND_TITLEMESSAGE_5,
1735 FreeGlobalAnimEventInfo();
1737 checked_free(graphic_info);
1739 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1741 // initialize "use_image_size" flag with default value
1742 for (i = 0; i < num_images; i++)
1743 graphic_info[i].use_image_size = FALSE;
1745 // initialize "use_image_size" flag from static configuration above
1746 for (i = 0; full_size_graphics[i] != -1; i++)
1747 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1749 // first set all graphic paramaters ...
1750 for (i = 0; i < num_images; i++)
1751 set_graphic_parameters(i);
1753 // ... then copy these parameters for cloned graphics
1754 for (i = 0; i < num_images; i++)
1755 if (graphic_info[i].clone_from != -1)
1756 set_cloned_graphic_parameters(i);
1758 for (i = 0; i < num_images; i++)
1760 Bitmap *src_bitmap = graphic_info[i].bitmap;
1764 int src_bitmap_width, src_bitmap_height;
1766 // now check if no animation frames are outside of the loaded image
1768 if (graphic_info[i].bitmap == NULL)
1769 continue; // skip check for optional images that are undefined
1771 // get image size (this can differ from the standard element tile size!)
1772 width = graphic_info[i].width;
1773 height = graphic_info[i].height;
1775 // get final bitmap size (with scaling, but without small images)
1776 src_bitmap_width = graphic_info[i].src_image_width;
1777 src_bitmap_height = graphic_info[i].src_image_height;
1779 // check if first animation frame is inside specified bitmap
1781 // do not use getGraphicSourceXY() here to get position of first frame;
1782 // this avoids calculating wrong start position for out-of-bounds frame
1783 src_x = graphic_info[i].src_x;
1784 src_y = graphic_info[i].src_y;
1786 if (program.headless)
1789 if (src_x < 0 || src_y < 0 ||
1790 src_x + width > src_bitmap_width ||
1791 src_y + height > src_bitmap_height)
1793 Error(ERR_INFO_LINE, "-");
1794 Error(ERR_INFO, "warning: error found in config file:");
1795 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1796 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1797 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1798 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1800 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1801 src_x, src_y, src_bitmap_width, src_bitmap_height);
1802 Error(ERR_INFO, "custom graphic rejected for this element/action");
1804 if (i == fallback_graphic)
1805 Error(ERR_EXIT, "no fallback graphic available");
1807 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1808 Error(ERR_INFO_LINE, "-");
1810 graphic_info[i] = graphic_info[fallback_graphic];
1812 // if first frame out of bounds, do not check last frame anymore
1816 // check if last animation frame is inside specified bitmap
1818 last_frame = graphic_info[i].anim_frames - 1;
1819 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1821 if (src_x < 0 || src_y < 0 ||
1822 src_x + width > src_bitmap_width ||
1823 src_y + height > src_bitmap_height)
1825 Error(ERR_INFO_LINE, "-");
1826 Error(ERR_INFO, "warning: error found in config file:");
1827 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1828 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1829 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1830 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1832 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1833 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1834 Error(ERR_INFO, "custom graphic rejected for this element/action");
1836 if (i == fallback_graphic)
1837 Error(ERR_EXIT, "no fallback graphic available");
1839 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1840 Error(ERR_INFO_LINE, "-");
1842 graphic_info[i] = graphic_info[fallback_graphic];
1847 static void InitGraphicCompatibilityInfo(void)
1849 struct FileInfo *fi_global_door =
1850 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1851 int num_images = getImageListSize();
1854 /* the following compatibility handling is needed for the following case:
1855 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1856 graphics mainly used for door and panel graphics, like editor, tape and
1857 in-game buttons with hard-coded bitmap positions and button sizes; as
1858 these graphics now have individual definitions, redefining "global.door"
1859 to change all these graphics at once like before does not work anymore
1860 (because all those individual definitions still have their default values);
1861 to solve this, remap all those individual definitions that are not
1862 redefined to the new bitmap of "global.door" if it was redefined */
1864 // special compatibility handling if image "global.door" was redefined
1865 if (fi_global_door->redefined)
1867 for (i = 0; i < num_images; i++)
1869 struct FileInfo *fi = getImageListEntryFromImageID(i);
1871 // process only those images that still use the default settings
1874 // process all images which default to same image as "global.door"
1875 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1877 // printf("::: special treatment needed for token '%s'\n", fi->token);
1879 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1880 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1886 InitGraphicCompatibilityInfo_Doors();
1889 static void InitElementSoundInfo(void)
1891 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1892 int num_property_mappings = getSoundListPropertyMappingSize();
1895 // set values to -1 to identify later as "uninitialized" values
1896 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1897 for (act = 0; act < NUM_ACTIONS; act++)
1898 element_info[i].sound[act] = -1;
1900 // initialize element/sound mapping from static configuration
1901 for (i = 0; element_to_sound[i].element > -1; i++)
1903 int element = element_to_sound[i].element;
1904 int action = element_to_sound[i].action;
1905 int sound = element_to_sound[i].sound;
1906 boolean is_class = element_to_sound[i].is_class;
1909 action = ACTION_DEFAULT;
1912 element_info[element].sound[action] = sound;
1914 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1915 if (strEqual(element_info[j].class_name,
1916 element_info[element].class_name))
1917 element_info[j].sound[action] = sound;
1920 // initialize element class/sound mapping from dynamic configuration
1921 for (i = 0; i < num_property_mappings; i++)
1923 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1924 int action = property_mapping[i].ext1_index;
1925 int sound = property_mapping[i].artwork_index;
1927 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1931 action = ACTION_DEFAULT;
1933 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1934 if (strEqual(element_info[j].class_name,
1935 element_info[element_class].class_name))
1936 element_info[j].sound[action] = sound;
1939 // initialize element/sound mapping from dynamic configuration
1940 for (i = 0; i < num_property_mappings; i++)
1942 int element = property_mapping[i].base_index;
1943 int action = property_mapping[i].ext1_index;
1944 int sound = property_mapping[i].artwork_index;
1946 if (element >= MAX_NUM_ELEMENTS)
1950 action = ACTION_DEFAULT;
1952 element_info[element].sound[action] = sound;
1955 // now set all '-1' values to element specific default values
1956 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1958 for (act = 0; act < NUM_ACTIONS; act++)
1960 // generic default action sound (defined by "[default]" directive)
1961 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1963 // look for special default action sound (classic game specific)
1964 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1965 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1966 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1967 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1968 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1969 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1970 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1971 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1973 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1974 // !!! make this better !!!
1975 if (i == EL_EMPTY_SPACE)
1976 default_action_sound = element_info[EL_DEFAULT].sound[act];
1978 // no sound for this specific action -- use default action sound
1979 if (element_info[i].sound[act] == -1)
1980 element_info[i].sound[act] = default_action_sound;
1984 // copy sound settings to some elements that are only stored in level file
1985 // in native R'n'D levels, but are used by game engine in native EM levels
1986 for (i = 0; copy_properties[i][0] != -1; i++)
1987 for (j = 1; j <= 4; j++)
1988 for (act = 0; act < NUM_ACTIONS; act++)
1989 element_info[copy_properties[i][j]].sound[act] =
1990 element_info[copy_properties[i][0]].sound[act];
1993 static void InitGameModeSoundInfo(void)
1997 // set values to -1 to identify later as "uninitialized" values
1998 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2001 // initialize gamemode/sound mapping from static configuration
2002 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2004 int gamemode = gamemode_to_sound[i].gamemode;
2005 int sound = gamemode_to_sound[i].sound;
2008 gamemode = GAME_MODE_DEFAULT;
2010 menu.sound[gamemode] = sound;
2013 // now set all '-1' values to levelset specific default values
2014 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2015 if (menu.sound[i] == -1)
2016 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2019 static void set_sound_parameters(int sound, char **parameter_raw)
2021 int parameter[NUM_SND_ARGS];
2024 // get integer values from string parameters
2025 for (i = 0; i < NUM_SND_ARGS; i++)
2027 get_parameter_value(parameter_raw[i],
2028 sound_config_suffix[i].token,
2029 sound_config_suffix[i].type);
2031 // explicit loop mode setting in configuration overrides default value
2032 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2033 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2035 // sound volume to change the original volume when loading the sound file
2036 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2038 // sound priority to give certain sounds a higher or lower priority
2039 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2042 static void InitSoundInfo(void)
2044 int *sound_effect_properties;
2045 int num_sounds = getSoundListSize();
2048 checked_free(sound_info);
2050 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2051 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2053 // initialize sound effect for all elements to "no sound"
2054 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2055 for (j = 0; j < NUM_ACTIONS; j++)
2056 element_info[i].sound[j] = SND_UNDEFINED;
2058 for (i = 0; i < num_sounds; i++)
2060 struct FileInfo *sound = getSoundListEntry(i);
2061 int len_effect_text = strlen(sound->token);
2063 sound_effect_properties[i] = ACTION_OTHER;
2064 sound_info[i].loop = FALSE; // default: play sound only once
2066 // determine all loop sounds and identify certain sound classes
2068 for (j = 0; element_action_info[j].suffix; j++)
2070 int len_action_text = strlen(element_action_info[j].suffix);
2072 if (len_action_text < len_effect_text &&
2073 strEqual(&sound->token[len_effect_text - len_action_text],
2074 element_action_info[j].suffix))
2076 sound_effect_properties[i] = element_action_info[j].value;
2077 sound_info[i].loop = element_action_info[j].is_loop_sound;
2083 // associate elements and some selected sound actions
2085 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2087 if (element_info[j].class_name)
2089 int len_class_text = strlen(element_info[j].class_name);
2091 if (len_class_text + 1 < len_effect_text &&
2092 strncmp(sound->token,
2093 element_info[j].class_name, len_class_text) == 0 &&
2094 sound->token[len_class_text] == '.')
2096 int sound_action_value = sound_effect_properties[i];
2098 element_info[j].sound[sound_action_value] = i;
2103 set_sound_parameters(i, sound->parameter);
2106 free(sound_effect_properties);
2109 static void InitGameModeMusicInfo(void)
2111 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2112 int num_property_mappings = getMusicListPropertyMappingSize();
2113 int default_levelset_music = -1;
2116 // set values to -1 to identify later as "uninitialized" values
2117 for (i = 0; i < MAX_LEVELS; i++)
2118 levelset.music[i] = -1;
2119 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2122 // initialize gamemode/music mapping from static configuration
2123 for (i = 0; gamemode_to_music[i].music > -1; i++)
2125 int gamemode = gamemode_to_music[i].gamemode;
2126 int music = gamemode_to_music[i].music;
2129 gamemode = GAME_MODE_DEFAULT;
2131 menu.music[gamemode] = music;
2134 // initialize gamemode/music mapping from dynamic configuration
2135 for (i = 0; i < num_property_mappings; i++)
2137 int prefix = property_mapping[i].base_index;
2138 int gamemode = property_mapping[i].ext2_index;
2139 int level = property_mapping[i].ext3_index;
2140 int music = property_mapping[i].artwork_index;
2142 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2146 gamemode = GAME_MODE_DEFAULT;
2148 // level specific music only allowed for in-game music
2149 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2150 gamemode = GAME_MODE_PLAYING;
2155 default_levelset_music = music;
2158 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2159 levelset.music[level] = music;
2160 if (gamemode != GAME_MODE_PLAYING)
2161 menu.music[gamemode] = music;
2164 // now set all '-1' values to menu specific default values
2165 // (undefined values of "levelset.music[]" might stay at "-1" to
2166 // allow dynamic selection of music files from music directory!)
2167 for (i = 0; i < MAX_LEVELS; i++)
2168 if (levelset.music[i] == -1)
2169 levelset.music[i] = default_levelset_music;
2170 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2171 if (menu.music[i] == -1)
2172 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2175 static void set_music_parameters(int music, char **parameter_raw)
2177 int parameter[NUM_MUS_ARGS];
2180 // get integer values from string parameters
2181 for (i = 0; i < NUM_MUS_ARGS; i++)
2183 get_parameter_value(parameter_raw[i],
2184 music_config_suffix[i].token,
2185 music_config_suffix[i].type);
2187 // explicit loop mode setting in configuration overrides default value
2188 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2189 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2192 static void InitMusicInfo(void)
2194 int num_music = getMusicListSize();
2197 checked_free(music_info);
2199 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2201 for (i = 0; i < num_music; i++)
2203 struct FileInfo *music = getMusicListEntry(i);
2204 int len_music_text = strlen(music->token);
2206 music_info[i].loop = TRUE; // default: play music in loop mode
2208 // determine all loop music
2210 for (j = 0; music_prefix_info[j].prefix; j++)
2212 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2214 if (len_prefix_text < len_music_text &&
2215 strncmp(music->token,
2216 music_prefix_info[j].prefix, len_prefix_text) == 0)
2218 music_info[i].loop = music_prefix_info[j].is_loop_music;
2224 set_music_parameters(i, music->parameter);
2228 static void ReinitializeGraphics(void)
2230 print_timestamp_init("ReinitializeGraphics");
2232 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2234 InitGraphicInfo(); // graphic properties mapping
2235 print_timestamp_time("InitGraphicInfo");
2236 InitElementGraphicInfo(); // element game graphic mapping
2237 print_timestamp_time("InitElementGraphicInfo");
2238 InitElementSpecialGraphicInfo(); // element special graphic mapping
2239 print_timestamp_time("InitElementSpecialGraphicInfo");
2241 InitElementSmallImages(); // scale elements to all needed sizes
2242 print_timestamp_time("InitElementSmallImages");
2243 InitScaledImages(); // scale all other images, if needed
2244 print_timestamp_time("InitScaledImages");
2245 InitBitmapPointers(); // set standard size bitmap pointers
2246 print_timestamp_time("InitBitmapPointers");
2247 InitFontGraphicInfo(); // initialize text drawing functions
2248 print_timestamp_time("InitFontGraphicInfo");
2249 InitGlobalAnimGraphicInfo(); // initialize global animation config
2250 print_timestamp_time("InitGlobalAnimGraphicInfo");
2252 InitImageTextures(); // create textures for certain images
2253 print_timestamp_time("InitImageTextures");
2255 InitGraphicInfo_EM(); // graphic mapping for EM engine
2256 print_timestamp_time("InitGraphicInfo_EM");
2258 InitGraphicCompatibilityInfo();
2259 print_timestamp_time("InitGraphicCompatibilityInfo");
2261 SetMainBackgroundImage(IMG_BACKGROUND);
2262 print_timestamp_time("SetMainBackgroundImage");
2263 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2264 print_timestamp_time("SetDoorBackgroundImage");
2267 print_timestamp_time("InitGadgets");
2269 print_timestamp_time("InitDoors");
2271 print_timestamp_done("ReinitializeGraphics");
2274 static void ReinitializeSounds(void)
2276 InitSoundInfo(); // sound properties mapping
2277 InitElementSoundInfo(); // element game sound mapping
2278 InitGameModeSoundInfo(); // game mode sound mapping
2279 InitGlobalAnimSoundInfo(); // global animation sound settings
2281 InitPlayLevelSound(); // internal game sound settings
2284 static void ReinitializeMusic(void)
2286 InitMusicInfo(); // music properties mapping
2287 InitGameModeMusicInfo(); // game mode music mapping
2288 InitGlobalAnimMusicInfo(); // global animation music settings
2291 static int get_special_property_bit(int element, int property_bit_nr)
2293 struct PropertyBitInfo
2299 static struct PropertyBitInfo pb_can_move_into_acid[] =
2301 // the player may be able fall into acid when gravity is activated
2306 { EL_SP_MURPHY, 0 },
2307 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2309 // all elements that can move may be able to also move into acid
2312 { EL_BUG_RIGHT, 1 },
2315 { EL_SPACESHIP, 2 },
2316 { EL_SPACESHIP_LEFT, 2 },
2317 { EL_SPACESHIP_RIGHT, 2 },
2318 { EL_SPACESHIP_UP, 2 },
2319 { EL_SPACESHIP_DOWN, 2 },
2320 { EL_BD_BUTTERFLY, 3 },
2321 { EL_BD_BUTTERFLY_LEFT, 3 },
2322 { EL_BD_BUTTERFLY_RIGHT, 3 },
2323 { EL_BD_BUTTERFLY_UP, 3 },
2324 { EL_BD_BUTTERFLY_DOWN, 3 },
2325 { EL_BD_FIREFLY, 4 },
2326 { EL_BD_FIREFLY_LEFT, 4 },
2327 { EL_BD_FIREFLY_RIGHT, 4 },
2328 { EL_BD_FIREFLY_UP, 4 },
2329 { EL_BD_FIREFLY_DOWN, 4 },
2331 { EL_YAMYAM_LEFT, 5 },
2332 { EL_YAMYAM_RIGHT, 5 },
2333 { EL_YAMYAM_UP, 5 },
2334 { EL_YAMYAM_DOWN, 5 },
2335 { EL_DARK_YAMYAM, 6 },
2338 { EL_PACMAN_LEFT, 8 },
2339 { EL_PACMAN_RIGHT, 8 },
2340 { EL_PACMAN_UP, 8 },
2341 { EL_PACMAN_DOWN, 8 },
2343 { EL_MOLE_LEFT, 9 },
2344 { EL_MOLE_RIGHT, 9 },
2346 { EL_MOLE_DOWN, 9 },
2350 { EL_SATELLITE, 13 },
2351 { EL_SP_SNIKSNAK, 14 },
2352 { EL_SP_ELECTRON, 15 },
2355 { EL_EMC_ANDROID, 18 },
2360 static struct PropertyBitInfo pb_dont_collide_with[] =
2362 { EL_SP_SNIKSNAK, 0 },
2363 { EL_SP_ELECTRON, 1 },
2371 struct PropertyBitInfo *pb_info;
2374 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2375 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2380 struct PropertyBitInfo *pb_info = NULL;
2383 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2384 if (pb_definition[i].bit_nr == property_bit_nr)
2385 pb_info = pb_definition[i].pb_info;
2387 if (pb_info == NULL)
2390 for (i = 0; pb_info[i].element != -1; i++)
2391 if (pb_info[i].element == element)
2392 return pb_info[i].bit_nr;
2397 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2398 boolean property_value)
2400 int bit_nr = get_special_property_bit(element, property_bit_nr);
2405 *bitfield |= (1 << bit_nr);
2407 *bitfield &= ~(1 << bit_nr);
2411 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2413 int bit_nr = get_special_property_bit(element, property_bit_nr);
2416 return ((*bitfield & (1 << bit_nr)) != 0);
2421 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2423 static int group_nr;
2424 static struct ElementGroupInfo *group;
2425 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2428 if (actual_group == NULL) // not yet initialized
2431 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2433 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2434 group_element - EL_GROUP_START + 1);
2436 // replace element which caused too deep recursion by question mark
2437 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2442 if (recursion_depth == 0) // initialization
2444 group = actual_group;
2445 group_nr = GROUP_NR(group_element);
2447 group->num_elements_resolved = 0;
2448 group->choice_pos = 0;
2450 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2451 element_info[i].in_group[group_nr] = FALSE;
2454 for (i = 0; i < actual_group->num_elements; i++)
2456 int element = actual_group->element[i];
2458 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2461 if (IS_GROUP_ELEMENT(element))
2462 ResolveGroupElementExt(element, recursion_depth + 1);
2465 group->element_resolved[group->num_elements_resolved++] = element;
2466 element_info[element].in_group[group_nr] = TRUE;
2471 void ResolveGroupElement(int group_element)
2473 ResolveGroupElementExt(group_element, 0);
2476 void InitElementPropertiesStatic(void)
2478 static boolean clipboard_elements_initialized = FALSE;
2480 static int ep_diggable[] =
2485 EL_SP_BUGGY_BASE_ACTIVATING,
2488 EL_INVISIBLE_SAND_ACTIVE,
2491 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2492 // (if amoeba can grow into anything diggable, maybe keep these out)
2497 EL_SP_BUGGY_BASE_ACTIVE,
2504 static int ep_collectible_only[] =
2526 EL_DYNABOMB_INCREASE_NUMBER,
2527 EL_DYNABOMB_INCREASE_SIZE,
2528 EL_DYNABOMB_INCREASE_POWER,
2546 // !!! handle separately !!!
2547 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2553 static int ep_dont_run_into[] =
2555 // same elements as in 'ep_dont_touch'
2561 // same elements as in 'ep_dont_collide_with'
2573 // !!! maybe this should better be handled by 'ep_diggable' !!!
2578 EL_SP_BUGGY_BASE_ACTIVE,
2585 static int ep_dont_collide_with[] =
2587 // same elements as in 'ep_dont_touch'
2604 static int ep_dont_touch[] =
2614 static int ep_indestructible[] =
2618 EL_ACID_POOL_TOPLEFT,
2619 EL_ACID_POOL_TOPRIGHT,
2620 EL_ACID_POOL_BOTTOMLEFT,
2621 EL_ACID_POOL_BOTTOM,
2622 EL_ACID_POOL_BOTTOMRIGHT,
2623 EL_SP_HARDWARE_GRAY,
2624 EL_SP_HARDWARE_GREEN,
2625 EL_SP_HARDWARE_BLUE,
2627 EL_SP_HARDWARE_YELLOW,
2628 EL_SP_HARDWARE_BASE_1,
2629 EL_SP_HARDWARE_BASE_2,
2630 EL_SP_HARDWARE_BASE_3,
2631 EL_SP_HARDWARE_BASE_4,
2632 EL_SP_HARDWARE_BASE_5,
2633 EL_SP_HARDWARE_BASE_6,
2634 EL_INVISIBLE_STEELWALL,
2635 EL_INVISIBLE_STEELWALL_ACTIVE,
2636 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2637 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2638 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2639 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2640 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2641 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2642 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2643 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2644 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2645 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2646 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2647 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2649 EL_LIGHT_SWITCH_ACTIVE,
2650 EL_SIGN_EXCLAMATION,
2651 EL_SIGN_RADIOACTIVITY,
2658 EL_SIGN_ENTRY_FORBIDDEN,
2659 EL_SIGN_EMERGENCY_EXIT,
2667 EL_STEEL_EXIT_CLOSED,
2669 EL_STEEL_EXIT_OPENING,
2670 EL_STEEL_EXIT_CLOSING,
2671 EL_EM_STEEL_EXIT_CLOSED,
2672 EL_EM_STEEL_EXIT_OPEN,
2673 EL_EM_STEEL_EXIT_OPENING,
2674 EL_EM_STEEL_EXIT_CLOSING,
2675 EL_DC_STEELWALL_1_LEFT,
2676 EL_DC_STEELWALL_1_RIGHT,
2677 EL_DC_STEELWALL_1_TOP,
2678 EL_DC_STEELWALL_1_BOTTOM,
2679 EL_DC_STEELWALL_1_HORIZONTAL,
2680 EL_DC_STEELWALL_1_VERTICAL,
2681 EL_DC_STEELWALL_1_TOPLEFT,
2682 EL_DC_STEELWALL_1_TOPRIGHT,
2683 EL_DC_STEELWALL_1_BOTTOMLEFT,
2684 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2685 EL_DC_STEELWALL_1_TOPLEFT_2,
2686 EL_DC_STEELWALL_1_TOPRIGHT_2,
2687 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2688 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2689 EL_DC_STEELWALL_2_LEFT,
2690 EL_DC_STEELWALL_2_RIGHT,
2691 EL_DC_STEELWALL_2_TOP,
2692 EL_DC_STEELWALL_2_BOTTOM,
2693 EL_DC_STEELWALL_2_HORIZONTAL,
2694 EL_DC_STEELWALL_2_VERTICAL,
2695 EL_DC_STEELWALL_2_MIDDLE,
2696 EL_DC_STEELWALL_2_SINGLE,
2697 EL_STEELWALL_SLIPPERY,
2711 EL_GATE_1_GRAY_ACTIVE,
2712 EL_GATE_2_GRAY_ACTIVE,
2713 EL_GATE_3_GRAY_ACTIVE,
2714 EL_GATE_4_GRAY_ACTIVE,
2723 EL_EM_GATE_1_GRAY_ACTIVE,
2724 EL_EM_GATE_2_GRAY_ACTIVE,
2725 EL_EM_GATE_3_GRAY_ACTIVE,
2726 EL_EM_GATE_4_GRAY_ACTIVE,
2735 EL_EMC_GATE_5_GRAY_ACTIVE,
2736 EL_EMC_GATE_6_GRAY_ACTIVE,
2737 EL_EMC_GATE_7_GRAY_ACTIVE,
2738 EL_EMC_GATE_8_GRAY_ACTIVE,
2740 EL_DC_GATE_WHITE_GRAY,
2741 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2742 EL_DC_GATE_FAKE_GRAY,
2744 EL_SWITCHGATE_OPENING,
2745 EL_SWITCHGATE_CLOSED,
2746 EL_SWITCHGATE_CLOSING,
2747 EL_DC_SWITCHGATE_SWITCH_UP,
2748 EL_DC_SWITCHGATE_SWITCH_DOWN,
2750 EL_TIMEGATE_OPENING,
2752 EL_TIMEGATE_CLOSING,
2753 EL_DC_TIMEGATE_SWITCH,
2754 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2758 EL_TUBE_VERTICAL_LEFT,
2759 EL_TUBE_VERTICAL_RIGHT,
2760 EL_TUBE_HORIZONTAL_UP,
2761 EL_TUBE_HORIZONTAL_DOWN,
2766 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2767 EL_EXPANDABLE_STEELWALL_VERTICAL,
2768 EL_EXPANDABLE_STEELWALL_ANY,
2773 static int ep_slippery[] =
2787 EL_ROBOT_WHEEL_ACTIVE,
2793 EL_ACID_POOL_TOPLEFT,
2794 EL_ACID_POOL_TOPRIGHT,
2804 EL_STEELWALL_SLIPPERY,
2807 EL_EMC_WALL_SLIPPERY_1,
2808 EL_EMC_WALL_SLIPPERY_2,
2809 EL_EMC_WALL_SLIPPERY_3,
2810 EL_EMC_WALL_SLIPPERY_4,
2812 EL_EMC_MAGIC_BALL_ACTIVE,
2817 static int ep_can_change[] =
2822 static int ep_can_move[] =
2824 // same elements as in 'pb_can_move_into_acid'
2847 static int ep_can_fall[] =
2861 EL_QUICKSAND_FAST_FULL,
2863 EL_BD_MAGIC_WALL_FULL,
2864 EL_DC_MAGIC_WALL_FULL,
2878 static int ep_can_smash_player[] =
2904 static int ep_can_smash_enemies[] =
2913 static int ep_can_smash_everything[] =
2922 static int ep_explodes_by_fire[] =
2924 // same elements as in 'ep_explodes_impact'
2929 // same elements as in 'ep_explodes_smashed'
2939 EL_EM_DYNAMITE_ACTIVE,
2940 EL_DYNABOMB_PLAYER_1_ACTIVE,
2941 EL_DYNABOMB_PLAYER_2_ACTIVE,
2942 EL_DYNABOMB_PLAYER_3_ACTIVE,
2943 EL_DYNABOMB_PLAYER_4_ACTIVE,
2944 EL_DYNABOMB_INCREASE_NUMBER,
2945 EL_DYNABOMB_INCREASE_SIZE,
2946 EL_DYNABOMB_INCREASE_POWER,
2947 EL_SP_DISK_RED_ACTIVE,
2961 static int ep_explodes_smashed[] =
2963 // same elements as in 'ep_explodes_impact'
2977 static int ep_explodes_impact[] =
2986 static int ep_walkable_over[] =
2990 EL_SOKOBAN_FIELD_EMPTY,
2997 EL_EM_STEEL_EXIT_OPEN,
2998 EL_EM_STEEL_EXIT_OPENING,
3007 EL_GATE_1_GRAY_ACTIVE,
3008 EL_GATE_2_GRAY_ACTIVE,
3009 EL_GATE_3_GRAY_ACTIVE,
3010 EL_GATE_4_GRAY_ACTIVE,
3018 static int ep_walkable_inside[] =
3023 EL_TUBE_VERTICAL_LEFT,
3024 EL_TUBE_VERTICAL_RIGHT,
3025 EL_TUBE_HORIZONTAL_UP,
3026 EL_TUBE_HORIZONTAL_DOWN,
3035 static int ep_walkable_under[] =
3040 static int ep_passable_over[] =
3050 EL_EM_GATE_1_GRAY_ACTIVE,
3051 EL_EM_GATE_2_GRAY_ACTIVE,
3052 EL_EM_GATE_3_GRAY_ACTIVE,
3053 EL_EM_GATE_4_GRAY_ACTIVE,
3062 EL_EMC_GATE_5_GRAY_ACTIVE,
3063 EL_EMC_GATE_6_GRAY_ACTIVE,
3064 EL_EMC_GATE_7_GRAY_ACTIVE,
3065 EL_EMC_GATE_8_GRAY_ACTIVE,
3067 EL_DC_GATE_WHITE_GRAY,
3068 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3075 static int ep_passable_inside[] =
3081 EL_SP_PORT_HORIZONTAL,
3082 EL_SP_PORT_VERTICAL,
3084 EL_SP_GRAVITY_PORT_LEFT,
3085 EL_SP_GRAVITY_PORT_RIGHT,
3086 EL_SP_GRAVITY_PORT_UP,
3087 EL_SP_GRAVITY_PORT_DOWN,
3088 EL_SP_GRAVITY_ON_PORT_LEFT,
3089 EL_SP_GRAVITY_ON_PORT_RIGHT,
3090 EL_SP_GRAVITY_ON_PORT_UP,
3091 EL_SP_GRAVITY_ON_PORT_DOWN,
3092 EL_SP_GRAVITY_OFF_PORT_LEFT,
3093 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3094 EL_SP_GRAVITY_OFF_PORT_UP,
3095 EL_SP_GRAVITY_OFF_PORT_DOWN,
3100 static int ep_passable_under[] =
3105 static int ep_droppable[] =
3110 static int ep_explodes_1x1_old[] =
3115 static int ep_pushable[] =
3127 EL_SOKOBAN_FIELD_FULL,
3136 static int ep_explodes_cross_old[] =
3141 static int ep_protected[] =
3143 // same elements as in 'ep_walkable_inside'
3147 EL_TUBE_VERTICAL_LEFT,
3148 EL_TUBE_VERTICAL_RIGHT,
3149 EL_TUBE_HORIZONTAL_UP,
3150 EL_TUBE_HORIZONTAL_DOWN,
3156 // same elements as in 'ep_passable_over'
3165 EL_EM_GATE_1_GRAY_ACTIVE,
3166 EL_EM_GATE_2_GRAY_ACTIVE,
3167 EL_EM_GATE_3_GRAY_ACTIVE,
3168 EL_EM_GATE_4_GRAY_ACTIVE,
3177 EL_EMC_GATE_5_GRAY_ACTIVE,
3178 EL_EMC_GATE_6_GRAY_ACTIVE,
3179 EL_EMC_GATE_7_GRAY_ACTIVE,
3180 EL_EMC_GATE_8_GRAY_ACTIVE,
3182 EL_DC_GATE_WHITE_GRAY,
3183 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3187 // same elements as in 'ep_passable_inside'
3192 EL_SP_PORT_HORIZONTAL,
3193 EL_SP_PORT_VERTICAL,
3195 EL_SP_GRAVITY_PORT_LEFT,
3196 EL_SP_GRAVITY_PORT_RIGHT,
3197 EL_SP_GRAVITY_PORT_UP,
3198 EL_SP_GRAVITY_PORT_DOWN,
3199 EL_SP_GRAVITY_ON_PORT_LEFT,
3200 EL_SP_GRAVITY_ON_PORT_RIGHT,
3201 EL_SP_GRAVITY_ON_PORT_UP,
3202 EL_SP_GRAVITY_ON_PORT_DOWN,
3203 EL_SP_GRAVITY_OFF_PORT_LEFT,
3204 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3205 EL_SP_GRAVITY_OFF_PORT_UP,
3206 EL_SP_GRAVITY_OFF_PORT_DOWN,
3211 static int ep_throwable[] =
3216 static int ep_can_explode[] =
3218 // same elements as in 'ep_explodes_impact'
3223 // same elements as in 'ep_explodes_smashed'
3229 // elements that can explode by explosion or by dragonfire
3233 EL_EM_DYNAMITE_ACTIVE,
3234 EL_DYNABOMB_PLAYER_1_ACTIVE,
3235 EL_DYNABOMB_PLAYER_2_ACTIVE,
3236 EL_DYNABOMB_PLAYER_3_ACTIVE,
3237 EL_DYNABOMB_PLAYER_4_ACTIVE,
3238 EL_DYNABOMB_INCREASE_NUMBER,
3239 EL_DYNABOMB_INCREASE_SIZE,
3240 EL_DYNABOMB_INCREASE_POWER,
3241 EL_SP_DISK_RED_ACTIVE,
3249 // elements that can explode only by explosion
3255 static int ep_gravity_reachable[] =
3261 EL_INVISIBLE_SAND_ACTIVE,
3266 EL_SP_PORT_HORIZONTAL,
3267 EL_SP_PORT_VERTICAL,
3269 EL_SP_GRAVITY_PORT_LEFT,
3270 EL_SP_GRAVITY_PORT_RIGHT,
3271 EL_SP_GRAVITY_PORT_UP,
3272 EL_SP_GRAVITY_PORT_DOWN,
3273 EL_SP_GRAVITY_ON_PORT_LEFT,
3274 EL_SP_GRAVITY_ON_PORT_RIGHT,
3275 EL_SP_GRAVITY_ON_PORT_UP,
3276 EL_SP_GRAVITY_ON_PORT_DOWN,
3277 EL_SP_GRAVITY_OFF_PORT_LEFT,
3278 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3279 EL_SP_GRAVITY_OFF_PORT_UP,
3280 EL_SP_GRAVITY_OFF_PORT_DOWN,
3286 static int ep_player[] =
3293 EL_SOKOBAN_FIELD_PLAYER,
3299 static int ep_can_pass_magic_wall[] =
3313 static int ep_can_pass_dc_magic_wall[] =
3329 static int ep_switchable[] =
3333 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3334 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3335 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3336 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3337 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3338 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3339 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3340 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3341 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3342 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3343 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3344 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3345 EL_SWITCHGATE_SWITCH_UP,
3346 EL_SWITCHGATE_SWITCH_DOWN,
3347 EL_DC_SWITCHGATE_SWITCH_UP,
3348 EL_DC_SWITCHGATE_SWITCH_DOWN,
3350 EL_LIGHT_SWITCH_ACTIVE,
3352 EL_DC_TIMEGATE_SWITCH,
3353 EL_BALLOON_SWITCH_LEFT,
3354 EL_BALLOON_SWITCH_RIGHT,
3355 EL_BALLOON_SWITCH_UP,
3356 EL_BALLOON_SWITCH_DOWN,
3357 EL_BALLOON_SWITCH_ANY,
3358 EL_BALLOON_SWITCH_NONE,
3361 EL_EMC_MAGIC_BALL_SWITCH,
3362 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3367 static int ep_bd_element[] =
3401 static int ep_sp_element[] =
3403 // should always be valid
3406 // standard classic Supaplex elements
3413 EL_SP_HARDWARE_GRAY,
3421 EL_SP_GRAVITY_PORT_RIGHT,
3422 EL_SP_GRAVITY_PORT_DOWN,
3423 EL_SP_GRAVITY_PORT_LEFT,
3424 EL_SP_GRAVITY_PORT_UP,
3429 EL_SP_PORT_VERTICAL,
3430 EL_SP_PORT_HORIZONTAL,
3436 EL_SP_HARDWARE_BASE_1,
3437 EL_SP_HARDWARE_GREEN,
3438 EL_SP_HARDWARE_BLUE,
3440 EL_SP_HARDWARE_YELLOW,
3441 EL_SP_HARDWARE_BASE_2,
3442 EL_SP_HARDWARE_BASE_3,
3443 EL_SP_HARDWARE_BASE_4,
3444 EL_SP_HARDWARE_BASE_5,
3445 EL_SP_HARDWARE_BASE_6,
3449 // additional elements that appeared in newer Supaplex levels
3452 // additional gravity port elements (not switching, but setting gravity)
3453 EL_SP_GRAVITY_ON_PORT_LEFT,
3454 EL_SP_GRAVITY_ON_PORT_RIGHT,
3455 EL_SP_GRAVITY_ON_PORT_UP,
3456 EL_SP_GRAVITY_ON_PORT_DOWN,
3457 EL_SP_GRAVITY_OFF_PORT_LEFT,
3458 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3459 EL_SP_GRAVITY_OFF_PORT_UP,
3460 EL_SP_GRAVITY_OFF_PORT_DOWN,
3462 // more than one Murphy in a level results in an inactive clone
3465 // runtime Supaplex elements
3466 EL_SP_DISK_RED_ACTIVE,
3467 EL_SP_TERMINAL_ACTIVE,
3468 EL_SP_BUGGY_BASE_ACTIVATING,
3469 EL_SP_BUGGY_BASE_ACTIVE,
3476 static int ep_sb_element[] =
3481 EL_SOKOBAN_FIELD_EMPTY,
3482 EL_SOKOBAN_FIELD_FULL,
3483 EL_SOKOBAN_FIELD_PLAYER,
3488 EL_INVISIBLE_STEELWALL,
3493 static int ep_gem[] =
3505 static int ep_food_dark_yamyam[] =
3533 static int ep_food_penguin[] =
3547 static int ep_food_pig[] =
3559 static int ep_historic_wall[] =
3570 EL_GATE_1_GRAY_ACTIVE,
3571 EL_GATE_2_GRAY_ACTIVE,
3572 EL_GATE_3_GRAY_ACTIVE,
3573 EL_GATE_4_GRAY_ACTIVE,
3582 EL_EM_GATE_1_GRAY_ACTIVE,
3583 EL_EM_GATE_2_GRAY_ACTIVE,
3584 EL_EM_GATE_3_GRAY_ACTIVE,
3585 EL_EM_GATE_4_GRAY_ACTIVE,
3592 EL_EXPANDABLE_WALL_HORIZONTAL,
3593 EL_EXPANDABLE_WALL_VERTICAL,
3594 EL_EXPANDABLE_WALL_ANY,
3595 EL_EXPANDABLE_WALL_GROWING,
3596 EL_BD_EXPANDABLE_WALL,
3603 EL_SP_HARDWARE_GRAY,
3604 EL_SP_HARDWARE_GREEN,
3605 EL_SP_HARDWARE_BLUE,
3607 EL_SP_HARDWARE_YELLOW,
3608 EL_SP_HARDWARE_BASE_1,
3609 EL_SP_HARDWARE_BASE_2,
3610 EL_SP_HARDWARE_BASE_3,
3611 EL_SP_HARDWARE_BASE_4,
3612 EL_SP_HARDWARE_BASE_5,
3613 EL_SP_HARDWARE_BASE_6,
3615 EL_SP_TERMINAL_ACTIVE,
3618 EL_INVISIBLE_STEELWALL,
3619 EL_INVISIBLE_STEELWALL_ACTIVE,
3621 EL_INVISIBLE_WALL_ACTIVE,
3622 EL_STEELWALL_SLIPPERY,
3639 static int ep_historic_solid[] =
3643 EL_EXPANDABLE_WALL_HORIZONTAL,
3644 EL_EXPANDABLE_WALL_VERTICAL,
3645 EL_EXPANDABLE_WALL_ANY,
3646 EL_BD_EXPANDABLE_WALL,
3659 EL_QUICKSAND_FILLING,
3660 EL_QUICKSAND_EMPTYING,
3662 EL_MAGIC_WALL_ACTIVE,
3663 EL_MAGIC_WALL_EMPTYING,
3664 EL_MAGIC_WALL_FILLING,
3668 EL_BD_MAGIC_WALL_ACTIVE,
3669 EL_BD_MAGIC_WALL_EMPTYING,
3670 EL_BD_MAGIC_WALL_FULL,
3671 EL_BD_MAGIC_WALL_FILLING,
3672 EL_BD_MAGIC_WALL_DEAD,
3681 EL_SP_TERMINAL_ACTIVE,
3685 EL_INVISIBLE_WALL_ACTIVE,
3686 EL_SWITCHGATE_SWITCH_UP,
3687 EL_SWITCHGATE_SWITCH_DOWN,
3689 EL_TIMEGATE_SWITCH_ACTIVE,
3701 // the following elements are a direct copy of "indestructible" elements,
3702 // except "EL_ACID", which is "indestructible", but not "solid"!
3707 EL_ACID_POOL_TOPLEFT,
3708 EL_ACID_POOL_TOPRIGHT,
3709 EL_ACID_POOL_BOTTOMLEFT,
3710 EL_ACID_POOL_BOTTOM,
3711 EL_ACID_POOL_BOTTOMRIGHT,
3712 EL_SP_HARDWARE_GRAY,
3713 EL_SP_HARDWARE_GREEN,
3714 EL_SP_HARDWARE_BLUE,
3716 EL_SP_HARDWARE_YELLOW,
3717 EL_SP_HARDWARE_BASE_1,
3718 EL_SP_HARDWARE_BASE_2,
3719 EL_SP_HARDWARE_BASE_3,
3720 EL_SP_HARDWARE_BASE_4,
3721 EL_SP_HARDWARE_BASE_5,
3722 EL_SP_HARDWARE_BASE_6,
3723 EL_INVISIBLE_STEELWALL,
3724 EL_INVISIBLE_STEELWALL_ACTIVE,
3725 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3726 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3727 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3728 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3729 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3730 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3731 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3732 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3733 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3734 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3735 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3736 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3738 EL_LIGHT_SWITCH_ACTIVE,
3739 EL_SIGN_EXCLAMATION,
3740 EL_SIGN_RADIOACTIVITY,
3747 EL_SIGN_ENTRY_FORBIDDEN,
3748 EL_SIGN_EMERGENCY_EXIT,
3756 EL_STEEL_EXIT_CLOSED,
3758 EL_STEEL_EXIT_OPENING,
3759 EL_STEEL_EXIT_CLOSING,
3760 EL_EM_STEEL_EXIT_CLOSED,
3761 EL_EM_STEEL_EXIT_OPEN,
3762 EL_EM_STEEL_EXIT_OPENING,
3763 EL_EM_STEEL_EXIT_CLOSING,
3764 EL_DC_STEELWALL_1_LEFT,
3765 EL_DC_STEELWALL_1_RIGHT,
3766 EL_DC_STEELWALL_1_TOP,
3767 EL_DC_STEELWALL_1_BOTTOM,
3768 EL_DC_STEELWALL_1_HORIZONTAL,
3769 EL_DC_STEELWALL_1_VERTICAL,
3770 EL_DC_STEELWALL_1_TOPLEFT,
3771 EL_DC_STEELWALL_1_TOPRIGHT,
3772 EL_DC_STEELWALL_1_BOTTOMLEFT,
3773 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3774 EL_DC_STEELWALL_1_TOPLEFT_2,
3775 EL_DC_STEELWALL_1_TOPRIGHT_2,
3776 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3777 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3778 EL_DC_STEELWALL_2_LEFT,
3779 EL_DC_STEELWALL_2_RIGHT,
3780 EL_DC_STEELWALL_2_TOP,
3781 EL_DC_STEELWALL_2_BOTTOM,
3782 EL_DC_STEELWALL_2_HORIZONTAL,
3783 EL_DC_STEELWALL_2_VERTICAL,
3784 EL_DC_STEELWALL_2_MIDDLE,
3785 EL_DC_STEELWALL_2_SINGLE,
3786 EL_STEELWALL_SLIPPERY,
3800 EL_GATE_1_GRAY_ACTIVE,
3801 EL_GATE_2_GRAY_ACTIVE,
3802 EL_GATE_3_GRAY_ACTIVE,
3803 EL_GATE_4_GRAY_ACTIVE,
3812 EL_EM_GATE_1_GRAY_ACTIVE,
3813 EL_EM_GATE_2_GRAY_ACTIVE,
3814 EL_EM_GATE_3_GRAY_ACTIVE,
3815 EL_EM_GATE_4_GRAY_ACTIVE,
3824 EL_EMC_GATE_5_GRAY_ACTIVE,
3825 EL_EMC_GATE_6_GRAY_ACTIVE,
3826 EL_EMC_GATE_7_GRAY_ACTIVE,
3827 EL_EMC_GATE_8_GRAY_ACTIVE,
3829 EL_DC_GATE_WHITE_GRAY,
3830 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3831 EL_DC_GATE_FAKE_GRAY,
3833 EL_SWITCHGATE_OPENING,
3834 EL_SWITCHGATE_CLOSED,
3835 EL_SWITCHGATE_CLOSING,
3836 EL_DC_SWITCHGATE_SWITCH_UP,
3837 EL_DC_SWITCHGATE_SWITCH_DOWN,
3839 EL_TIMEGATE_OPENING,
3841 EL_TIMEGATE_CLOSING,
3842 EL_DC_TIMEGATE_SWITCH,
3843 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3847 EL_TUBE_VERTICAL_LEFT,
3848 EL_TUBE_VERTICAL_RIGHT,
3849 EL_TUBE_HORIZONTAL_UP,
3850 EL_TUBE_HORIZONTAL_DOWN,
3855 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3856 EL_EXPANDABLE_STEELWALL_VERTICAL,
3857 EL_EXPANDABLE_STEELWALL_ANY,
3862 static int ep_classic_enemy[] =
3879 static int ep_belt[] =
3881 EL_CONVEYOR_BELT_1_LEFT,
3882 EL_CONVEYOR_BELT_1_MIDDLE,
3883 EL_CONVEYOR_BELT_1_RIGHT,
3884 EL_CONVEYOR_BELT_2_LEFT,
3885 EL_CONVEYOR_BELT_2_MIDDLE,
3886 EL_CONVEYOR_BELT_2_RIGHT,
3887 EL_CONVEYOR_BELT_3_LEFT,
3888 EL_CONVEYOR_BELT_3_MIDDLE,
3889 EL_CONVEYOR_BELT_3_RIGHT,
3890 EL_CONVEYOR_BELT_4_LEFT,
3891 EL_CONVEYOR_BELT_4_MIDDLE,
3892 EL_CONVEYOR_BELT_4_RIGHT,
3897 static int ep_belt_active[] =
3899 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3900 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3901 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3902 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3903 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3904 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3905 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3906 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3907 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3908 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3909 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3910 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3915 static int ep_belt_switch[] =
3917 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3918 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3919 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3920 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3921 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3922 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3923 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3924 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3925 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3926 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3927 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3928 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3933 static int ep_tube[] =
3940 EL_TUBE_HORIZONTAL_UP,
3941 EL_TUBE_HORIZONTAL_DOWN,
3943 EL_TUBE_VERTICAL_LEFT,
3944 EL_TUBE_VERTICAL_RIGHT,
3950 static int ep_acid_pool[] =
3952 EL_ACID_POOL_TOPLEFT,
3953 EL_ACID_POOL_TOPRIGHT,
3954 EL_ACID_POOL_BOTTOMLEFT,
3955 EL_ACID_POOL_BOTTOM,
3956 EL_ACID_POOL_BOTTOMRIGHT,
3961 static int ep_keygate[] =
3971 EL_GATE_1_GRAY_ACTIVE,
3972 EL_GATE_2_GRAY_ACTIVE,
3973 EL_GATE_3_GRAY_ACTIVE,
3974 EL_GATE_4_GRAY_ACTIVE,
3983 EL_EM_GATE_1_GRAY_ACTIVE,
3984 EL_EM_GATE_2_GRAY_ACTIVE,
3985 EL_EM_GATE_3_GRAY_ACTIVE,
3986 EL_EM_GATE_4_GRAY_ACTIVE,
3995 EL_EMC_GATE_5_GRAY_ACTIVE,
3996 EL_EMC_GATE_6_GRAY_ACTIVE,
3997 EL_EMC_GATE_7_GRAY_ACTIVE,
3998 EL_EMC_GATE_8_GRAY_ACTIVE,
4000 EL_DC_GATE_WHITE_GRAY,
4001 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4006 static int ep_amoeboid[] =
4018 static int ep_amoebalive[] =
4029 static int ep_has_editor_content[] =
4035 EL_SOKOBAN_FIELD_PLAYER,
4052 static int ep_can_turn_each_move[] =
4054 // !!! do something with this one !!!
4058 static int ep_can_grow[] =
4072 static int ep_active_bomb[] =
4075 EL_EM_DYNAMITE_ACTIVE,
4076 EL_DYNABOMB_PLAYER_1_ACTIVE,
4077 EL_DYNABOMB_PLAYER_2_ACTIVE,
4078 EL_DYNABOMB_PLAYER_3_ACTIVE,
4079 EL_DYNABOMB_PLAYER_4_ACTIVE,
4080 EL_SP_DISK_RED_ACTIVE,
4085 static int ep_inactive[] =
4095 EL_QUICKSAND_FAST_EMPTY,
4118 EL_GATE_1_GRAY_ACTIVE,
4119 EL_GATE_2_GRAY_ACTIVE,
4120 EL_GATE_3_GRAY_ACTIVE,
4121 EL_GATE_4_GRAY_ACTIVE,
4130 EL_EM_GATE_1_GRAY_ACTIVE,
4131 EL_EM_GATE_2_GRAY_ACTIVE,
4132 EL_EM_GATE_3_GRAY_ACTIVE,
4133 EL_EM_GATE_4_GRAY_ACTIVE,
4142 EL_EMC_GATE_5_GRAY_ACTIVE,
4143 EL_EMC_GATE_6_GRAY_ACTIVE,
4144 EL_EMC_GATE_7_GRAY_ACTIVE,
4145 EL_EMC_GATE_8_GRAY_ACTIVE,
4147 EL_DC_GATE_WHITE_GRAY,
4148 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4149 EL_DC_GATE_FAKE_GRAY,
4152 EL_INVISIBLE_STEELWALL,
4160 EL_WALL_EMERALD_YELLOW,
4161 EL_DYNABOMB_INCREASE_NUMBER,
4162 EL_DYNABOMB_INCREASE_SIZE,
4163 EL_DYNABOMB_INCREASE_POWER,
4167 EL_SOKOBAN_FIELD_EMPTY,
4168 EL_SOKOBAN_FIELD_FULL,
4169 EL_WALL_EMERALD_RED,
4170 EL_WALL_EMERALD_PURPLE,
4171 EL_ACID_POOL_TOPLEFT,
4172 EL_ACID_POOL_TOPRIGHT,
4173 EL_ACID_POOL_BOTTOMLEFT,
4174 EL_ACID_POOL_BOTTOM,
4175 EL_ACID_POOL_BOTTOMRIGHT,
4179 EL_BD_MAGIC_WALL_DEAD,
4181 EL_DC_MAGIC_WALL_DEAD,
4182 EL_AMOEBA_TO_DIAMOND,
4190 EL_SP_GRAVITY_PORT_RIGHT,
4191 EL_SP_GRAVITY_PORT_DOWN,
4192 EL_SP_GRAVITY_PORT_LEFT,
4193 EL_SP_GRAVITY_PORT_UP,
4194 EL_SP_PORT_HORIZONTAL,
4195 EL_SP_PORT_VERTICAL,
4206 EL_SP_HARDWARE_GRAY,
4207 EL_SP_HARDWARE_GREEN,
4208 EL_SP_HARDWARE_BLUE,
4210 EL_SP_HARDWARE_YELLOW,
4211 EL_SP_HARDWARE_BASE_1,
4212 EL_SP_HARDWARE_BASE_2,
4213 EL_SP_HARDWARE_BASE_3,
4214 EL_SP_HARDWARE_BASE_4,
4215 EL_SP_HARDWARE_BASE_5,
4216 EL_SP_HARDWARE_BASE_6,
4217 EL_SP_GRAVITY_ON_PORT_LEFT,
4218 EL_SP_GRAVITY_ON_PORT_RIGHT,
4219 EL_SP_GRAVITY_ON_PORT_UP,
4220 EL_SP_GRAVITY_ON_PORT_DOWN,
4221 EL_SP_GRAVITY_OFF_PORT_LEFT,
4222 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4223 EL_SP_GRAVITY_OFF_PORT_UP,
4224 EL_SP_GRAVITY_OFF_PORT_DOWN,
4225 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4226 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4227 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4228 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4229 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4230 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4231 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4232 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4233 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4234 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4235 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4236 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4237 EL_SIGN_EXCLAMATION,
4238 EL_SIGN_RADIOACTIVITY,
4245 EL_SIGN_ENTRY_FORBIDDEN,
4246 EL_SIGN_EMERGENCY_EXIT,
4254 EL_DC_STEELWALL_1_LEFT,
4255 EL_DC_STEELWALL_1_RIGHT,
4256 EL_DC_STEELWALL_1_TOP,
4257 EL_DC_STEELWALL_1_BOTTOM,
4258 EL_DC_STEELWALL_1_HORIZONTAL,
4259 EL_DC_STEELWALL_1_VERTICAL,
4260 EL_DC_STEELWALL_1_TOPLEFT,
4261 EL_DC_STEELWALL_1_TOPRIGHT,
4262 EL_DC_STEELWALL_1_BOTTOMLEFT,
4263 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4264 EL_DC_STEELWALL_1_TOPLEFT_2,
4265 EL_DC_STEELWALL_1_TOPRIGHT_2,
4266 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4267 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4268 EL_DC_STEELWALL_2_LEFT,
4269 EL_DC_STEELWALL_2_RIGHT,
4270 EL_DC_STEELWALL_2_TOP,
4271 EL_DC_STEELWALL_2_BOTTOM,
4272 EL_DC_STEELWALL_2_HORIZONTAL,
4273 EL_DC_STEELWALL_2_VERTICAL,
4274 EL_DC_STEELWALL_2_MIDDLE,
4275 EL_DC_STEELWALL_2_SINGLE,
4276 EL_STEELWALL_SLIPPERY,
4281 EL_EMC_WALL_SLIPPERY_1,
4282 EL_EMC_WALL_SLIPPERY_2,
4283 EL_EMC_WALL_SLIPPERY_3,
4284 EL_EMC_WALL_SLIPPERY_4,
4305 static int ep_em_slippery_wall[] =
4310 static int ep_gfx_crumbled[] =
4321 static int ep_editor_cascade_active[] =
4323 EL_INTERNAL_CASCADE_BD_ACTIVE,
4324 EL_INTERNAL_CASCADE_EM_ACTIVE,
4325 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4326 EL_INTERNAL_CASCADE_RND_ACTIVE,
4327 EL_INTERNAL_CASCADE_SB_ACTIVE,
4328 EL_INTERNAL_CASCADE_SP_ACTIVE,
4329 EL_INTERNAL_CASCADE_DC_ACTIVE,
4330 EL_INTERNAL_CASCADE_DX_ACTIVE,
4331 EL_INTERNAL_CASCADE_MM_ACTIVE,
4332 EL_INTERNAL_CASCADE_DF_ACTIVE,
4333 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4334 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4335 EL_INTERNAL_CASCADE_CE_ACTIVE,
4336 EL_INTERNAL_CASCADE_GE_ACTIVE,
4337 EL_INTERNAL_CASCADE_REF_ACTIVE,
4338 EL_INTERNAL_CASCADE_USER_ACTIVE,
4339 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4344 static int ep_editor_cascade_inactive[] =
4346 EL_INTERNAL_CASCADE_BD,
4347 EL_INTERNAL_CASCADE_EM,
4348 EL_INTERNAL_CASCADE_EMC,
4349 EL_INTERNAL_CASCADE_RND,
4350 EL_INTERNAL_CASCADE_SB,
4351 EL_INTERNAL_CASCADE_SP,
4352 EL_INTERNAL_CASCADE_DC,
4353 EL_INTERNAL_CASCADE_DX,
4354 EL_INTERNAL_CASCADE_MM,
4355 EL_INTERNAL_CASCADE_DF,
4356 EL_INTERNAL_CASCADE_CHARS,
4357 EL_INTERNAL_CASCADE_STEEL_CHARS,
4358 EL_INTERNAL_CASCADE_CE,
4359 EL_INTERNAL_CASCADE_GE,
4360 EL_INTERNAL_CASCADE_REF,
4361 EL_INTERNAL_CASCADE_USER,
4362 EL_INTERNAL_CASCADE_DYNAMIC,
4367 static int ep_obsolete[] =
4371 EL_EM_KEY_1_FILE_OBSOLETE,
4372 EL_EM_KEY_2_FILE_OBSOLETE,
4373 EL_EM_KEY_3_FILE_OBSOLETE,
4374 EL_EM_KEY_4_FILE_OBSOLETE,
4375 EL_ENVELOPE_OBSOLETE,
4384 } element_properties[] =
4386 { ep_diggable, EP_DIGGABLE },
4387 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4388 { ep_dont_run_into, EP_DONT_RUN_INTO },
4389 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4390 { ep_dont_touch, EP_DONT_TOUCH },
4391 { ep_indestructible, EP_INDESTRUCTIBLE },
4392 { ep_slippery, EP_SLIPPERY },
4393 { ep_can_change, EP_CAN_CHANGE },
4394 { ep_can_move, EP_CAN_MOVE },
4395 { ep_can_fall, EP_CAN_FALL },
4396 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4397 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4398 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4399 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4400 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4401 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4402 { ep_walkable_over, EP_WALKABLE_OVER },
4403 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4404 { ep_walkable_under, EP_WALKABLE_UNDER },
4405 { ep_passable_over, EP_PASSABLE_OVER },
4406 { ep_passable_inside, EP_PASSABLE_INSIDE },
4407 { ep_passable_under, EP_PASSABLE_UNDER },
4408 { ep_droppable, EP_DROPPABLE },
4409 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4410 { ep_pushable, EP_PUSHABLE },
4411 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4412 { ep_protected, EP_PROTECTED },
4413 { ep_throwable, EP_THROWABLE },
4414 { ep_can_explode, EP_CAN_EXPLODE },
4415 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4417 { ep_player, EP_PLAYER },
4418 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4419 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4420 { ep_switchable, EP_SWITCHABLE },
4421 { ep_bd_element, EP_BD_ELEMENT },
4422 { ep_sp_element, EP_SP_ELEMENT },
4423 { ep_sb_element, EP_SB_ELEMENT },
4425 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4426 { ep_food_penguin, EP_FOOD_PENGUIN },
4427 { ep_food_pig, EP_FOOD_PIG },
4428 { ep_historic_wall, EP_HISTORIC_WALL },
4429 { ep_historic_solid, EP_HISTORIC_SOLID },
4430 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4431 { ep_belt, EP_BELT },
4432 { ep_belt_active, EP_BELT_ACTIVE },
4433 { ep_belt_switch, EP_BELT_SWITCH },
4434 { ep_tube, EP_TUBE },
4435 { ep_acid_pool, EP_ACID_POOL },
4436 { ep_keygate, EP_KEYGATE },
4437 { ep_amoeboid, EP_AMOEBOID },
4438 { ep_amoebalive, EP_AMOEBALIVE },
4439 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4440 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4441 { ep_can_grow, EP_CAN_GROW },
4442 { ep_active_bomb, EP_ACTIVE_BOMB },
4443 { ep_inactive, EP_INACTIVE },
4445 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4447 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4449 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4450 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4452 { ep_obsolete, EP_OBSOLETE },
4459 // always start with reliable default values (element has no properties)
4460 // (but never initialize clipboard elements after the very first time)
4461 // (to be able to use clipboard elements between several levels)
4462 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4463 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4464 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4465 SET_PROPERTY(i, j, FALSE);
4467 // set all base element properties from above array definitions
4468 for (i = 0; element_properties[i].elements != NULL; i++)
4469 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4470 SET_PROPERTY((element_properties[i].elements)[j],
4471 element_properties[i].property, TRUE);
4473 // copy properties to some elements that are only stored in level file
4474 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4475 for (j = 0; copy_properties[j][0] != -1; j++)
4476 if (HAS_PROPERTY(copy_properties[j][0], i))
4477 for (k = 1; k <= 4; k++)
4478 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4480 // set static element properties that are not listed in array definitions
4481 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4482 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4484 clipboard_elements_initialized = TRUE;
4487 void InitElementPropertiesEngine(int engine_version)
4489 static int no_wall_properties[] =
4492 EP_COLLECTIBLE_ONLY,
4494 EP_DONT_COLLIDE_WITH,
4497 EP_CAN_SMASH_PLAYER,
4498 EP_CAN_SMASH_ENEMIES,
4499 EP_CAN_SMASH_EVERYTHING,
4504 EP_FOOD_DARK_YAMYAM,
4520 /* important: after initialization in InitElementPropertiesStatic(), the
4521 elements are not again initialized to a default value; therefore all
4522 changes have to make sure that they leave the element with a defined
4523 property (which means that conditional property changes must be set to
4524 a reliable default value before) */
4526 // resolve group elements
4527 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4528 ResolveGroupElement(EL_GROUP_START + i);
4530 // set all special, combined or engine dependent element properties
4531 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4533 // do not change (already initialized) clipboard elements here
4534 if (IS_CLIPBOARD_ELEMENT(i))
4537 // ---------- INACTIVE ----------------------------------------------------
4538 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4539 i <= EL_CHAR_END) ||
4540 (i >= EL_STEEL_CHAR_START &&
4541 i <= EL_STEEL_CHAR_END)));
4543 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4544 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4545 IS_WALKABLE_INSIDE(i) ||
4546 IS_WALKABLE_UNDER(i)));
4548 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4549 IS_PASSABLE_INSIDE(i) ||
4550 IS_PASSABLE_UNDER(i)));
4552 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4553 IS_PASSABLE_OVER(i)));
4555 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4556 IS_PASSABLE_INSIDE(i)));
4558 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4559 IS_PASSABLE_UNDER(i)));
4561 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4564 // ---------- COLLECTIBLE -------------------------------------------------
4565 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4569 // ---------- SNAPPABLE ---------------------------------------------------
4570 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4571 IS_COLLECTIBLE(i) ||
4575 // ---------- WALL --------------------------------------------------------
4576 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4578 for (j = 0; no_wall_properties[j] != -1; j++)
4579 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4580 i >= EL_FIRST_RUNTIME_UNREAL)
4581 SET_PROPERTY(i, EP_WALL, FALSE);
4583 if (IS_HISTORIC_WALL(i))
4584 SET_PROPERTY(i, EP_WALL, TRUE);
4586 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4587 if (engine_version < VERSION_IDENT(2,2,0,0))
4588 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4590 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4592 !IS_COLLECTIBLE(i)));
4594 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4595 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4596 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4598 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4601 // ---------- EXPLOSION_PROOF ---------------------------------------------
4603 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4604 else if (engine_version < VERSION_IDENT(2,2,0,0))
4605 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4607 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4611 if (IS_CUSTOM_ELEMENT(i))
4613 // these are additional properties which are initially false when set
4615 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4617 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4618 if (DONT_COLLIDE_WITH(i))
4619 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4621 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4622 if (CAN_SMASH_EVERYTHING(i))
4623 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4624 if (CAN_SMASH_ENEMIES(i))
4625 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4628 // ---------- CAN_SMASH ---------------------------------------------------
4629 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4630 CAN_SMASH_ENEMIES(i) ||
4631 CAN_SMASH_EVERYTHING(i)));
4633 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4634 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4635 EXPLODES_BY_FIRE(i)));
4637 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4638 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4639 EXPLODES_SMASHED(i)));
4641 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4642 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4643 EXPLODES_IMPACT(i)));
4645 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4646 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4648 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4649 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4650 i == EL_BLACK_ORB));
4652 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4653 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4655 IS_CUSTOM_ELEMENT(i)));
4657 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4658 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4659 i == EL_SP_ELECTRON));
4661 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4662 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4663 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4664 getMoveIntoAcidProperty(&level, i));
4666 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4667 if (MAYBE_DONT_COLLIDE_WITH(i))
4668 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4669 getDontCollideWithProperty(&level, i));
4671 // ---------- SP_PORT -----------------------------------------------------
4672 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4673 IS_PASSABLE_INSIDE(i)));
4675 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4676 for (j = 0; j < level.num_android_clone_elements; j++)
4677 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4679 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4681 // ---------- CAN_CHANGE --------------------------------------------------
4682 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4683 for (j = 0; j < element_info[i].num_change_pages; j++)
4684 if (element_info[i].change_page[j].can_change)
4685 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4687 // ---------- HAS_ACTION --------------------------------------------------
4688 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4689 for (j = 0; j < element_info[i].num_change_pages; j++)
4690 if (element_info[i].change_page[j].has_action)
4691 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4693 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4694 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4697 // ---------- GFX_CRUMBLED ------------------------------------------------
4698 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4699 element_info[i].crumbled[ACTION_DEFAULT] !=
4700 element_info[i].graphic[ACTION_DEFAULT]);
4702 // ---------- EDITOR_CASCADE ----------------------------------------------
4703 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4704 IS_EDITOR_CASCADE_INACTIVE(i)));
4707 // dynamically adjust element properties according to game engine version
4709 static int ep_em_slippery_wall[] =
4714 EL_EXPANDABLE_WALL_HORIZONTAL,
4715 EL_EXPANDABLE_WALL_VERTICAL,
4716 EL_EXPANDABLE_WALL_ANY,
4717 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4718 EL_EXPANDABLE_STEELWALL_VERTICAL,
4719 EL_EXPANDABLE_STEELWALL_ANY,
4720 EL_EXPANDABLE_STEELWALL_GROWING,
4724 static int ep_em_explodes_by_fire[] =
4727 EL_EM_DYNAMITE_ACTIVE,
4732 // special EM style gems behaviour
4733 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4734 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4735 level.em_slippery_gems);
4737 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4738 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4739 (level.em_slippery_gems &&
4740 engine_version > VERSION_IDENT(2,0,1,0)));
4742 // special EM style explosion behaviour regarding chain reactions
4743 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4744 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4745 level.em_explodes_by_fire);
4748 // this is needed because some graphics depend on element properties
4749 if (game_status == GAME_MODE_PLAYING)
4750 InitElementGraphicInfo();
4753 void InitElementPropertiesGfxElement(void)
4757 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4759 struct ElementInfo *ei = &element_info[i];
4761 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4765 static void InitGlobal(void)
4770 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4772 // check if element_name_info entry defined for each element in "main.h"
4773 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4774 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4776 element_info[i].token_name = element_name_info[i].token_name;
4777 element_info[i].class_name = element_name_info[i].class_name;
4778 element_info[i].editor_description= element_name_info[i].editor_description;
4781 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4783 // check if global_anim_name_info defined for each entry in "main.h"
4784 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4785 global_anim_name_info[i].token_name == NULL)
4786 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4788 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4791 // create hash from image config list
4792 image_config_hash = newSetupFileHash();
4793 for (i = 0; image_config[i].token != NULL; i++)
4794 setHashEntry(image_config_hash,
4795 image_config[i].token,
4796 image_config[i].value);
4798 // create hash from element token list
4799 element_token_hash = newSetupFileHash();
4800 for (i = 0; element_name_info[i].token_name != NULL; i++)
4801 setHashEntry(element_token_hash,
4802 element_name_info[i].token_name,
4805 // create hash from graphic token list
4806 graphic_token_hash = newSetupFileHash();
4807 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4808 if (strSuffix(image_config[i].value, ".png") ||
4809 strSuffix(image_config[i].value, ".pcx") ||
4810 strSuffix(image_config[i].value, ".wav") ||
4811 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4812 setHashEntry(graphic_token_hash,
4813 image_config[i].token,
4814 int2str(graphic++, 0));
4816 // create hash from font token list
4817 font_token_hash = newSetupFileHash();
4818 for (i = 0; font_info[i].token_name != NULL; i++)
4819 setHashEntry(font_token_hash,
4820 font_info[i].token_name,
4823 // set default filenames for all cloned graphics in static configuration
4824 for (i = 0; image_config[i].token != NULL; i++)
4826 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4828 char *token = image_config[i].token;
4829 char *token_clone_from = getStringCat2(token, ".clone_from");
4830 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4832 if (token_cloned != NULL)
4834 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4836 if (value_cloned != NULL)
4838 // set default filename in static configuration
4839 image_config[i].value = value_cloned;
4841 // set default filename in image config hash
4842 setHashEntry(image_config_hash, token, value_cloned);
4846 free(token_clone_from);
4850 // always start with reliable default values (all elements)
4851 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4852 ActiveElement[i] = i;
4854 // now add all entries that have an active state (active elements)
4855 for (i = 0; element_with_active_state[i].element != -1; i++)
4857 int element = element_with_active_state[i].element;
4858 int element_active = element_with_active_state[i].element_active;
4860 ActiveElement[element] = element_active;
4863 // always start with reliable default values (all buttons)
4864 for (i = 0; i < NUM_IMAGE_FILES; i++)
4865 ActiveButton[i] = i;
4867 // now add all entries that have an active state (active buttons)
4868 for (i = 0; button_with_active_state[i].button != -1; i++)
4870 int button = button_with_active_state[i].button;
4871 int button_active = button_with_active_state[i].button_active;
4873 ActiveButton[button] = button_active;
4876 // always start with reliable default values (all fonts)
4877 for (i = 0; i < NUM_FONTS; i++)
4880 // now add all entries that have an active state (active fonts)
4881 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4883 int font = font_with_active_state[i].font_nr;
4884 int font_active = font_with_active_state[i].font_nr_active;
4886 ActiveFont[font] = font_active;
4889 global.autoplay_leveldir = NULL;
4890 global.convert_leveldir = NULL;
4891 global.create_images_dir = NULL;
4893 global.frames_per_second = 0;
4894 global.show_frames_per_second = FALSE;
4896 global.border_status = GAME_MODE_LOADING;
4897 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4899 global.use_envelope_request = FALSE;
4902 static void Execute_Command(char *command)
4906 if (strEqual(command, "print graphicsinfo.conf"))
4908 Print("# You can configure additional/alternative image files here.\n");
4909 Print("# (The entries below are default and therefore commented out.)\n");
4911 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4913 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4916 for (i = 0; image_config[i].token != NULL; i++)
4917 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4918 image_config[i].value));
4922 else if (strEqual(command, "print soundsinfo.conf"))
4924 Print("# You can configure additional/alternative sound files here.\n");
4925 Print("# (The entries below are default and therefore commented out.)\n");
4927 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4929 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4932 for (i = 0; sound_config[i].token != NULL; i++)
4933 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4934 sound_config[i].value));
4938 else if (strEqual(command, "print musicinfo.conf"))
4940 Print("# You can configure additional/alternative music files here.\n");
4941 Print("# (The entries below are default and therefore commented out.)\n");
4943 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4945 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4948 for (i = 0; music_config[i].token != NULL; i++)
4949 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4950 music_config[i].value));
4954 else if (strEqual(command, "print editorsetup.conf"))
4956 Print("# You can configure your personal editor element list here.\n");
4957 Print("# (The entries below are default and therefore commented out.)\n");
4960 // this is needed to be able to check element list for cascade elements
4961 InitElementPropertiesStatic();
4962 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4964 PrintEditorElementList();
4968 else if (strEqual(command, "print helpanim.conf"))
4970 Print("# You can configure different element help animations here.\n");
4971 Print("# (The entries below are default and therefore commented out.)\n");
4974 for (i = 0; helpanim_config[i].token != NULL; i++)
4976 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4977 helpanim_config[i].value));
4979 if (strEqual(helpanim_config[i].token, "end"))
4985 else if (strEqual(command, "print helptext.conf"))
4987 Print("# You can configure different element help text here.\n");
4988 Print("# (The entries below are default and therefore commented out.)\n");
4991 for (i = 0; helptext_config[i].token != NULL; i++)
4992 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4993 helptext_config[i].value));
4997 else if (strPrefix(command, "dump level "))
4999 char *filename = &command[11];
5001 if (!fileExists(filename))
5002 Error(ERR_EXIT, "cannot open file '%s'", filename);
5004 LoadLevelFromFilename(&level, filename);
5009 else if (strPrefix(command, "dump tape "))
5011 char *filename = &command[10];
5013 if (!fileExists(filename))
5014 Error(ERR_EXIT, "cannot open file '%s'", filename);
5016 LoadTapeFromFilename(filename);
5021 else if (strPrefix(command, "autotest ") ||
5022 strPrefix(command, "autoplay ") ||
5023 strPrefix(command, "autoffwd ") ||
5024 strPrefix(command, "autowarp "))
5026 char *str_ptr = getStringCopy(&command[9]); // read command parameters
5028 global.autoplay_mode =
5029 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5030 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5031 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5032 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5033 AUTOPLAY_MODE_NONE);
5035 while (*str_ptr != '\0') // continue parsing string
5037 // cut leading whitespace from string, replace it by string terminator
5038 while (*str_ptr == ' ' || *str_ptr == '\t')
5041 if (*str_ptr == '\0') // end of string reached
5044 if (global.autoplay_leveldir == NULL) // read level set string
5046 global.autoplay_leveldir = str_ptr;
5047 global.autoplay_all = TRUE; // default: play all tapes
5049 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5050 global.autoplay_level[i] = FALSE;
5052 else // read level number string
5054 int level_nr = atoi(str_ptr); // get level_nr value
5056 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5057 global.autoplay_level[level_nr] = TRUE;
5059 global.autoplay_all = FALSE;
5062 // advance string pointer to the next whitespace (or end of string)
5063 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5067 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5068 program.headless = TRUE;
5070 else if (strPrefix(command, "convert "))
5072 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5073 char *str_ptr = strchr(str_copy, ' ');
5075 global.convert_leveldir = str_copy;
5076 global.convert_level_nr = -1;
5078 if (str_ptr != NULL) // level number follows
5080 *str_ptr++ = '\0'; // terminate leveldir string
5081 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5084 program.headless = TRUE;
5086 else if (strPrefix(command, "create images "))
5088 global.create_images_dir = getStringCopy(&command[14]);
5090 if (access(global.create_images_dir, W_OK) != 0)
5091 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5092 global.create_images_dir);
5094 else if (strPrefix(command, "create CE image "))
5096 CreateCustomElementImages(&command[16]);
5102 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5105 // disable networking if any valid command was recognized
5106 options.network = setup.network_mode = FALSE;
5109 static void InitSetup(void)
5111 LoadSetup(); // global setup info
5112 LoadSetup_AutoSetup(); // global auto setup info
5114 // set some options from setup file
5116 if (setup.options.verbose)
5117 options.verbose = TRUE;
5119 if (setup.debug.show_frames_per_second)
5120 global.show_frames_per_second = TRUE;
5123 static void InitGameInfo(void)
5125 game.restart_level = FALSE;
5126 game.restart_game_message = NULL;
5127 game.request_active = FALSE;
5130 static void InitPlayerInfo(void)
5134 // choose default local player
5135 local_player = &stored_player[0];
5137 for (i = 0; i < MAX_PLAYERS; i++)
5139 stored_player[i].connected_locally = FALSE;
5140 stored_player[i].connected_network = FALSE;
5143 local_player->connected_locally = TRUE;
5146 static void InitArtworkInfo(void)
5151 static char *get_string_in_brackets(char *string)
5153 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5155 sprintf(string_in_brackets, "[%s]", string);
5157 return string_in_brackets;
5160 static char *get_level_id_suffix(int id_nr)
5162 char *id_suffix = checked_malloc(1 + 3 + 1);
5164 if (id_nr < 0 || id_nr > 999)
5167 sprintf(id_suffix, ".%03d", id_nr);
5172 static void InitArtworkConfig(void)
5174 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5176 NUM_GLOBAL_ANIM_TOKENS + 1];
5177 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5178 NUM_GLOBAL_ANIM_TOKENS + 1];
5179 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5180 NUM_GLOBAL_ANIM_TOKENS + 1];
5181 static char *action_id_suffix[NUM_ACTIONS + 1];
5182 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5183 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5184 static char *level_id_suffix[MAX_LEVELS + 1];
5185 static char *dummy[1] = { NULL };
5186 static char *ignore_generic_tokens[] =
5191 "program_copyright",
5196 static char **ignore_image_tokens;
5197 static char **ignore_sound_tokens;
5198 static char **ignore_music_tokens;
5199 int num_ignore_generic_tokens;
5200 int num_ignore_image_tokens;
5201 int num_ignore_sound_tokens;
5202 int num_ignore_music_tokens;
5205 // dynamically determine list of generic tokens to be ignored
5206 num_ignore_generic_tokens = 0;
5207 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5208 num_ignore_generic_tokens++;
5210 // dynamically determine list of image tokens to be ignored
5211 num_ignore_image_tokens = num_ignore_generic_tokens;
5212 for (i = 0; image_config_vars[i].token != NULL; i++)
5213 num_ignore_image_tokens++;
5214 ignore_image_tokens =
5215 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5216 for (i = 0; i < num_ignore_generic_tokens; i++)
5217 ignore_image_tokens[i] = ignore_generic_tokens[i];
5218 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5219 ignore_image_tokens[num_ignore_generic_tokens + i] =
5220 image_config_vars[i].token;
5221 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5223 // dynamically determine list of sound tokens to be ignored
5224 num_ignore_sound_tokens = num_ignore_generic_tokens;
5225 ignore_sound_tokens =
5226 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5227 for (i = 0; i < num_ignore_generic_tokens; i++)
5228 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5229 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5231 // dynamically determine list of music tokens to be ignored
5232 num_ignore_music_tokens = num_ignore_generic_tokens;
5233 ignore_music_tokens =
5234 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5235 for (i = 0; i < num_ignore_generic_tokens; i++)
5236 ignore_music_tokens[i] = ignore_generic_tokens[i];
5237 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5239 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5240 image_id_prefix[i] = element_info[i].token_name;
5241 for (i = 0; i < NUM_FONTS; i++)
5242 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5243 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5244 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5245 global_anim_info[i].token_name;
5246 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5248 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5249 sound_id_prefix[i] = element_info[i].token_name;
5250 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5251 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5252 get_string_in_brackets(element_info[i].class_name);
5253 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5254 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5255 global_anim_info[i].token_name;
5256 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5258 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5259 music_id_prefix[i] = music_prefix_info[i].prefix;
5260 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5261 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5262 global_anim_info[i].token_name;
5263 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5265 for (i = 0; i < NUM_ACTIONS; i++)
5266 action_id_suffix[i] = element_action_info[i].suffix;
5267 action_id_suffix[NUM_ACTIONS] = NULL;
5269 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5270 direction_id_suffix[i] = element_direction_info[i].suffix;
5271 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5273 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5274 special_id_suffix[i] = special_suffix_info[i].suffix;
5275 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5277 for (i = 0; i < MAX_LEVELS; i++)
5278 level_id_suffix[i] = get_level_id_suffix(i);
5279 level_id_suffix[MAX_LEVELS] = NULL;
5281 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5282 image_id_prefix, action_id_suffix, direction_id_suffix,
5283 special_id_suffix, ignore_image_tokens);
5284 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5285 sound_id_prefix, action_id_suffix, dummy,
5286 special_id_suffix, ignore_sound_tokens);
5287 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5288 music_id_prefix, action_id_suffix, special_id_suffix,
5289 level_id_suffix, ignore_music_tokens);
5292 static void InitMixer(void)
5299 static void InitVideoOverlay(void)
5301 // if virtual buttons are not loaded from setup file, repeat initializing
5302 // virtual buttons grid with default values now that video is initialized
5303 if (!setup.touch.grid_initialized)
5306 InitTileCursorInfo();
5310 void InitGfxBuffers(void)
5312 static int win_xsize_last = -1;
5313 static int win_ysize_last = -1;
5315 // create additional image buffers for double-buffering and cross-fading
5317 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5319 // used to temporarily store the backbuffer -- only re-create if changed
5320 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5321 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5323 win_xsize_last = WIN_XSIZE;
5324 win_ysize_last = WIN_YSIZE;
5327 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5328 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5329 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5330 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5332 // initialize screen properties
5333 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5334 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5336 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5337 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5338 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5339 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5340 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5341 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5343 // required if door size definitions have changed
5344 InitGraphicCompatibilityInfo_Doors();
5346 InitGfxBuffers_EM();
5347 InitGfxBuffers_SP();
5350 static void InitGfx(void)
5352 struct GraphicInfo *graphic_info_last = graphic_info;
5353 char *filename_font_initial = NULL;
5354 char *filename_anim_initial = NULL;
5355 Bitmap *bitmap_font_initial = NULL;
5358 // determine settings for initial font (for displaying startup messages)
5359 for (i = 0; image_config[i].token != NULL; i++)
5361 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5363 char font_token[128];
5366 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5367 len_font_token = strlen(font_token);
5369 if (strEqual(image_config[i].token, font_token))
5370 filename_font_initial = image_config[i].value;
5371 else if (strlen(image_config[i].token) > len_font_token &&
5372 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5374 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5375 font_initial[j].src_x = atoi(image_config[i].value);
5376 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5377 font_initial[j].src_y = atoi(image_config[i].value);
5378 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5379 font_initial[j].width = atoi(image_config[i].value);
5380 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5381 font_initial[j].height = atoi(image_config[i].value);
5386 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5388 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5389 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5392 if (filename_font_initial == NULL) // should not happen
5393 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5396 InitGfxCustomArtworkInfo();
5397 InitGfxOtherSettings();
5399 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5401 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5402 font_initial[j].bitmap = bitmap_font_initial;
5404 InitFontGraphicInfo();
5408 DrawInitText("Loading graphics", 120, FC_GREEN);
5410 // initialize settings for busy animation with default values
5411 int parameter[NUM_GFX_ARGS];
5412 for (i = 0; i < NUM_GFX_ARGS; i++)
5413 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5414 image_config_suffix[i].token,
5415 image_config_suffix[i].type);
5417 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5418 int len_anim_token = strlen(anim_token);
5420 // read settings for busy animation from default custom artwork config
5421 char *gfx_config_filename = getPath3(options.graphics_directory,
5423 GRAPHICSINFO_FILENAME);
5425 if (fileExists(gfx_config_filename))
5427 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5429 if (setup_file_hash)
5431 char *filename = getHashEntry(setup_file_hash, anim_token);
5435 filename_anim_initial = getStringCopy(filename);
5437 for (j = 0; image_config_suffix[j].token != NULL; j++)
5439 int type = image_config_suffix[j].type;
5440 char *suffix = image_config_suffix[j].token;
5441 char *token = getStringCat2(anim_token, suffix);
5442 char *value = getHashEntry(setup_file_hash, token);
5444 checked_free(token);
5447 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5451 freeSetupFileHash(setup_file_hash);
5455 if (filename_anim_initial == NULL)
5457 // read settings for busy animation from static default artwork config
5458 for (i = 0; image_config[i].token != NULL; i++)
5460 if (strEqual(image_config[i].token, anim_token))
5461 filename_anim_initial = getStringCopy(image_config[i].value);
5462 else if (strlen(image_config[i].token) > len_anim_token &&
5463 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5465 for (j = 0; image_config_suffix[j].token != NULL; j++)
5467 if (strEqual(&image_config[i].token[len_anim_token],
5468 image_config_suffix[j].token))
5470 get_graphic_parameter_value(image_config[i].value,
5471 image_config_suffix[j].token,
5472 image_config_suffix[j].type);
5478 if (filename_anim_initial == NULL) // should not happen
5479 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5481 anim_initial.bitmaps =
5482 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5484 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5485 LoadCustomImage(filename_anim_initial);
5487 checked_free(filename_anim_initial);
5489 graphic_info = &anim_initial; // graphic == 0 => anim_initial
5491 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5493 graphic_info = graphic_info_last;
5495 init.busy.width = anim_initial.width;
5496 init.busy.height = anim_initial.height;
5498 InitMenuDesignSettings_Static();
5500 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5501 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5502 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5503 InitGfxDrawTileCursorFunction(DrawTileCursor);
5505 gfx.fade_border_source_status = global.border_status;
5506 gfx.fade_border_target_status = global.border_status;
5507 gfx.masked_border_bitmap_ptr = backbuffer;
5509 // use copy of busy animation to prevent change while reloading artwork
5513 static void InitGfxBackground(void)
5515 fieldbuffer = bitmap_db_field;
5516 SetDrawtoField(DRAW_TO_BACKBUFFER);
5518 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5520 redraw_mask = REDRAW_ALL;
5523 static void InitLevelInfo(void)
5525 LoadLevelInfo(); // global level info
5526 LoadLevelSetup_LastSeries(); // last played series info
5527 LoadLevelSetup_SeriesInfo(); // last played level info
5529 if (global.autoplay_leveldir &&
5530 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5532 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5533 global.autoplay_leveldir);
5534 if (leveldir_current == NULL)
5535 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5538 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5541 static void InitLevelArtworkInfo(void)
5543 LoadLevelArtworkInfo();
5546 static void InitImages(void)
5548 print_timestamp_init("InitImages");
5551 printf("::: leveldir_current->identifier == '%s'\n",
5552 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5553 printf("::: leveldir_current->graphics_path == '%s'\n",
5554 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5555 printf("::: leveldir_current->graphics_set == '%s'\n",
5556 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5557 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5558 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5561 setLevelArtworkDir(artwork.gfx_first);
5564 printf("::: leveldir_current->identifier == '%s'\n",
5565 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5566 printf("::: leveldir_current->graphics_path == '%s'\n",
5567 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5568 printf("::: leveldir_current->graphics_set == '%s'\n",
5569 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5570 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5571 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5575 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5576 leveldir_current->identifier,
5577 artwork.gfx_current_identifier,
5578 artwork.gfx_current->identifier,
5579 leveldir_current->graphics_set,
5580 leveldir_current->graphics_path);
5583 UPDATE_BUSY_STATE();
5585 ReloadCustomImages();
5586 print_timestamp_time("ReloadCustomImages");
5588 UPDATE_BUSY_STATE();
5590 LoadCustomElementDescriptions();
5591 print_timestamp_time("LoadCustomElementDescriptions");
5593 UPDATE_BUSY_STATE();
5595 LoadMenuDesignSettings();
5596 print_timestamp_time("LoadMenuDesignSettings");
5598 UPDATE_BUSY_STATE();
5600 ReinitializeGraphics();
5601 print_timestamp_time("ReinitializeGraphics");
5603 LoadMenuDesignSettings_AfterGraphics();
5604 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5606 UPDATE_BUSY_STATE();
5608 print_timestamp_done("InitImages");
5611 static void InitSound(char *identifier)
5613 print_timestamp_init("InitSound");
5615 if (identifier == NULL)
5616 identifier = artwork.snd_current->identifier;
5618 // set artwork path to send it to the sound server process
5619 setLevelArtworkDir(artwork.snd_first);
5621 InitReloadCustomSounds(identifier);
5622 print_timestamp_time("InitReloadCustomSounds");
5624 ReinitializeSounds();
5625 print_timestamp_time("ReinitializeSounds");
5627 print_timestamp_done("InitSound");
5630 static void InitMusic(char *identifier)
5632 print_timestamp_init("InitMusic");
5634 if (identifier == NULL)
5635 identifier = artwork.mus_current->identifier;
5637 // set artwork path to send it to the sound server process
5638 setLevelArtworkDir(artwork.mus_first);
5640 InitReloadCustomMusic(identifier);
5641 print_timestamp_time("InitReloadCustomMusic");
5643 ReinitializeMusic();
5644 print_timestamp_time("ReinitializeMusic");
5646 print_timestamp_done("InitMusic");
5649 static void InitArtworkDone(void)
5651 if (program.headless)
5654 InitGlobalAnimations();
5657 static void InitNetworkSettings(void)
5659 boolean network_enabled = (options.network || setup.network_mode);
5660 char *network_server = (options.server_host != NULL ? options.server_host :
5661 setup.network_server_hostname);
5663 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5664 network_server = NULL;
5666 InitNetworkInfo(network_enabled,
5670 options.server_port);
5673 void InitNetworkServer(void)
5675 if (!network.enabled || network.connected)
5678 LimitScreenUpdates(FALSE);
5680 if (game_status == GAME_MODE_LOADING)
5683 if (!ConnectToServer(network.server_host, network.server_port))
5685 network.enabled = FALSE;
5687 setup.network_mode = FALSE;
5691 SendToServer_ProtocolVersion();
5692 SendToServer_PlayerName(setup.player_name);
5693 SendToServer_NrWanted(setup.network_player_nr + 1);
5695 network.connected = TRUE;
5698 // short time to recognize result of network initialization
5699 if (game_status == GAME_MODE_LOADING)
5700 Delay_WithScreenUpdates(1000);
5703 static boolean CheckArtworkConfigForCustomElements(char *filename)
5705 SetupFileHash *setup_file_hash;
5706 boolean redefined_ce_found = FALSE;
5708 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5710 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5712 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5714 char *token = HASH_ITERATION_TOKEN(itr);
5716 if (strPrefix(token, "custom_"))
5718 redefined_ce_found = TRUE;
5723 END_HASH_ITERATION(setup_file_hash, itr)
5725 freeSetupFileHash(setup_file_hash);
5728 return redefined_ce_found;
5731 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5733 char *filename_base, *filename_local;
5734 boolean redefined_ce_found = FALSE;
5736 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5739 printf("::: leveldir_current->identifier == '%s'\n",
5740 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5741 printf("::: leveldir_current->graphics_path == '%s'\n",
5742 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5743 printf("::: leveldir_current->graphics_set == '%s'\n",
5744 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5745 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5746 leveldir_current == NULL ? "[NULL]" :
5747 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5750 // first look for special artwork configured in level series config
5751 filename_base = getCustomArtworkLevelConfigFilename(type);
5754 printf("::: filename_base == '%s'\n", filename_base);
5757 if (fileExists(filename_base))
5758 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5760 filename_local = getCustomArtworkConfigFilename(type);
5763 printf("::: filename_local == '%s'\n", filename_local);
5766 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5767 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5770 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5773 return redefined_ce_found;
5776 static void InitOverrideArtwork(void)
5778 boolean redefined_ce_found = FALSE;
5780 // to check if this level set redefines any CEs, do not use overriding
5781 gfx.override_level_graphics = FALSE;
5782 gfx.override_level_sounds = FALSE;
5783 gfx.override_level_music = FALSE;
5785 // now check if this level set has definitions for custom elements
5786 if (setup.override_level_graphics == AUTO ||
5787 setup.override_level_sounds == AUTO ||
5788 setup.override_level_music == AUTO)
5789 redefined_ce_found =
5790 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5791 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5792 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5795 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5798 if (redefined_ce_found)
5800 // this level set has CE definitions: change "AUTO" to "FALSE"
5801 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5802 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5803 gfx.override_level_music = (setup.override_level_music == TRUE);
5807 // this level set has no CE definitions: change "AUTO" to "TRUE"
5808 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5809 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5810 gfx.override_level_music = (setup.override_level_music != FALSE);
5814 printf("::: => %d, %d, %d\n",
5815 gfx.override_level_graphics,
5816 gfx.override_level_sounds,
5817 gfx.override_level_music);
5821 static char *getNewArtworkIdentifier(int type)
5823 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5824 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5825 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5826 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5827 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5828 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5829 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5830 char *leveldir_identifier = leveldir_current->identifier;
5831 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
5832 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5833 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5834 char *artwork_current_identifier;
5835 char *artwork_new_identifier = NULL; // default: nothing has changed
5837 // leveldir_current may be invalid (level group, parent link)
5838 if (!validLevelSeries(leveldir_current))
5841 /* 1st step: determine artwork set to be activated in descending order:
5842 --------------------------------------------------------------------
5843 1. setup artwork (when configured to override everything else)
5844 2. artwork set configured in "levelinfo.conf" of current level set
5845 (artwork in level directory will have priority when loading later)
5846 3. artwork in level directory (stored in artwork sub-directory)
5847 4. setup artwork (currently configured in setup menu) */
5849 if (setup_override_artwork)
5850 artwork_current_identifier = setup_artwork_set;
5851 else if (leveldir_artwork_set != NULL)
5852 artwork_current_identifier = leveldir_artwork_set;
5853 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5854 artwork_current_identifier = leveldir_identifier;
5856 artwork_current_identifier = setup_artwork_set;
5859 /* 2nd step: check if it is really needed to reload artwork set
5860 ------------------------------------------------------------ */
5862 // ---------- reload if level set and also artwork set has changed ----------
5863 if (leveldir_current_identifier[type] != leveldir_identifier &&
5864 (last_has_level_artwork_set[type] || has_level_artwork_set))
5865 artwork_new_identifier = artwork_current_identifier;
5867 leveldir_current_identifier[type] = leveldir_identifier;
5868 last_has_level_artwork_set[type] = has_level_artwork_set;
5870 // ---------- reload if "override artwork" setting has changed --------------
5871 if (last_override_level_artwork[type] != setup_override_artwork)
5872 artwork_new_identifier = artwork_current_identifier;
5874 last_override_level_artwork[type] = setup_override_artwork;
5876 // ---------- reload if current artwork identifier has changed --------------
5877 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5878 artwork_current_identifier))
5879 artwork_new_identifier = artwork_current_identifier;
5881 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5883 // ---------- do not reload directly after starting -------------------------
5884 if (!initialized[type])
5885 artwork_new_identifier = NULL;
5887 initialized[type] = TRUE;
5889 return artwork_new_identifier;
5892 void ReloadCustomArtwork(int force_reload)
5894 int last_game_status = game_status; // save current game status
5895 char *gfx_new_identifier;
5896 char *snd_new_identifier;
5897 char *mus_new_identifier;
5898 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5899 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5900 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5901 boolean reload_needed;
5903 InitOverrideArtwork();
5905 force_reload_gfx |= AdjustGraphicsForEMC();
5907 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5908 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5909 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5911 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5912 snd_new_identifier != NULL || force_reload_snd ||
5913 mus_new_identifier != NULL || force_reload_mus);
5918 print_timestamp_init("ReloadCustomArtwork");
5920 SetGameStatus(GAME_MODE_LOADING);
5922 FadeOut(REDRAW_ALL);
5924 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5925 print_timestamp_time("ClearRectangle");
5929 if (gfx_new_identifier != NULL || force_reload_gfx)
5932 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5933 artwork.gfx_current_identifier,
5935 artwork.gfx_current->identifier,
5936 leveldir_current->graphics_set);
5940 print_timestamp_time("InitImages");
5943 if (snd_new_identifier != NULL || force_reload_snd)
5945 InitSound(snd_new_identifier);
5946 print_timestamp_time("InitSound");
5949 if (mus_new_identifier != NULL || force_reload_mus)
5951 InitMusic(mus_new_identifier);
5952 print_timestamp_time("InitMusic");
5957 SetGameStatus(last_game_status); // restore current game status
5959 init_last = init; // switch to new busy animation
5961 FadeOut(REDRAW_ALL);
5963 RedrawGlobalBorder();
5965 // force redraw of (open or closed) door graphics
5966 SetDoorState(DOOR_OPEN_ALL);
5967 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5969 FadeSetEnterScreen();
5970 FadeSkipNextFadeOut();
5972 print_timestamp_done("ReloadCustomArtwork");
5974 LimitScreenUpdates(FALSE);
5977 void KeyboardAutoRepeatOffUnlessAutoplay(void)
5979 if (global.autoplay_leveldir == NULL)
5980 KeyboardAutoRepeatOff();
5983 void DisplayExitMessage(char *format, va_list ap)
5985 // also check for initialized video (headless flag may be temporarily unset)
5986 if (program.headless || !video.initialized)
5989 // check if draw buffer and fonts for exit message are already available
5990 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5993 int font_1 = FC_RED;
5994 int font_2 = FC_YELLOW;
5995 int font_3 = FC_BLUE;
5996 int font_width = getFontWidth(font_2);
5997 int font_height = getFontHeight(font_2);
6000 int sxsize = WIN_XSIZE - 2 * sx;
6001 int sysize = WIN_YSIZE - 2 * sy;
6002 int line_length = sxsize / font_width;
6003 int max_lines = sysize / font_height;
6004 int num_lines_printed;
6008 gfx.sxsize = sxsize;
6009 gfx.sysize = sysize;
6013 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6015 DrawTextSCentered(sy, font_1, "Fatal error:");
6016 sy += 3 * font_height;;
6019 DrawTextBufferVA(sx, sy, format, ap, font_2,
6020 line_length, line_length, max_lines,
6021 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6022 sy += (num_lines_printed + 3) * font_height;
6024 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6025 sy += 3 * font_height;
6028 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6029 line_length, line_length, max_lines,
6030 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6032 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6034 redraw_mask = REDRAW_ALL;
6036 // force drawing exit message even if screen updates are currently limited
6037 LimitScreenUpdates(FALSE);
6041 // deactivate toons on error message screen
6042 setup.toons = FALSE;
6044 WaitForEventToContinue();
6048 // ============================================================================
6050 // ============================================================================
6054 print_timestamp_init("OpenAll");
6056 SetGameStatus(GAME_MODE_LOADING);
6060 InitGlobal(); // initialize some global variables
6062 print_timestamp_time("[init global stuff]");
6066 print_timestamp_time("[init setup/config stuff (1)]");
6070 if (options.execute_command)
6071 Execute_Command(options.execute_command);
6073 InitNetworkSettings();
6077 if (network.serveronly)
6079 #if defined(PLATFORM_UNIX)
6080 NetworkServer(network.server_port, TRUE);
6082 Error(ERR_WARN, "networking only supported in Unix version");
6085 exit(0); // never reached, server loops forever
6089 print_timestamp_time("[init setup/config stuff (2)]");
6091 print_timestamp_time("[init setup/config stuff (3)]");
6092 InitArtworkInfo(); // needed before loading gfx, sound & music
6093 print_timestamp_time("[init setup/config stuff (4)]");
6094 InitArtworkConfig(); // needed before forking sound child process
6095 print_timestamp_time("[init setup/config stuff (5)]");
6097 print_timestamp_time("[init setup/config stuff (6)]");
6099 InitRND(NEW_RANDOMIZE);
6100 InitSimpleRandom(NEW_RANDOMIZE);
6104 print_timestamp_time("[init setup/config stuff]");
6106 InitVideoDefaults();
6108 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6111 InitEventFilter(FilterMouseMotionEvents);
6113 print_timestamp_time("[init video stuff]");
6115 InitElementPropertiesStatic();
6116 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6117 InitElementPropertiesGfxElement();
6119 print_timestamp_time("[init element properties stuff]");
6123 print_timestamp_time("InitGfx");
6126 print_timestamp_time("InitLevelInfo");
6128 InitLevelArtworkInfo();
6129 print_timestamp_time("InitLevelArtworkInfo");
6131 InitOverrideArtwork(); // needs to know current level directory
6132 print_timestamp_time("InitOverrideArtwork");
6134 InitImages(); // needs to know current level directory
6135 print_timestamp_time("InitImages");
6137 InitSound(NULL); // needs to know current level directory
6138 print_timestamp_time("InitSound");
6140 InitMusic(NULL); // needs to know current level directory
6141 print_timestamp_time("InitMusic");
6145 InitGfxBackground();
6151 if (global.autoplay_leveldir)
6156 else if (global.convert_leveldir)
6161 else if (global.create_images_dir)
6163 CreateLevelSketchImages();
6167 InitNetworkServer();
6169 SetGameStatus(GAME_MODE_MAIN);
6171 FadeSetEnterScreen();
6172 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6173 FadeSkipNextFadeOut();
6175 print_timestamp_time("[post-artwork]");
6177 print_timestamp_done("OpenAll");
6182 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6184 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6185 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6186 #if defined(PLATFORM_ANDROID)
6187 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6188 SDL_AndroidGetInternalStoragePath());
6189 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6190 SDL_AndroidGetExternalStoragePath());
6191 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6192 (SDL_AndroidGetExternalStorageState() &
6193 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6194 SDL_AndroidGetExternalStorageState() &
6195 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6200 void CloseAllAndExit(int exit_value)
6205 CloseAudio(); // called after freeing sounds (needed for SDL)
6213 // set a flag to tell the network server thread to quit and wait for it
6214 // using SDL_WaitThread()
6216 // Code used with SDL 1.2:
6217 // if (network_server) // terminate network server
6218 // SDL_KillThread(server_thread);
6220 CloseVideoDisplay();
6221 ClosePlatformDependentStuff();
6223 if (exit_value != 0 && !options.execute_command)
6225 // fall back to default level set (current set may have caused an error)
6226 SaveLevelSetup_LastSeries_Deactivate();
6228 // tell user where to find error log file which may contain more details
6229 // (error notification now directly displayed on screen inside R'n'D
6230 // NotifyUserAboutErrorFile(); // currently only works for Windows