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->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1318 g->align = ALIGN_CENTER; // default for title screens
1319 g->valign = VALIGN_MIDDLE; // default for title screens
1320 g->sort_priority = 0; // default for title screens
1322 g->style = STYLE_DEFAULT;
1324 g->bitmaps = src_bitmaps;
1325 g->bitmap = src_bitmap;
1327 // optional zoom factor for scaling up the image to a larger size
1328 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1329 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1330 if (g->scale_up_factor < 1)
1331 g->scale_up_factor = 1; // no scaling
1333 // optional tile size for using non-standard image size
1334 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1336 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1339 // CHECK: should tile sizes less than standard tile size be allowed?
1340 if (g->tile_size < TILESIZE)
1341 g->tile_size = TILESIZE; // standard tile size
1344 // when setting tile size, also set width and height accordingly
1345 g->width = g->tile_size;
1346 g->height = g->tile_size;
1349 if (g->use_image_size)
1351 // set new default bitmap size (with scaling, but without small images)
1352 g->width = get_scaled_graphic_width(graphic);
1353 g->height = get_scaled_graphic_height(graphic);
1356 // optional width and height of each animation frame
1357 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1358 g->width = parameter[GFX_ARG_WIDTH];
1359 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1360 g->height = parameter[GFX_ARG_HEIGHT];
1362 // optional x and y tile position of animation frame sequence
1363 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1364 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1365 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1366 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1368 // optional x and y pixel position of animation frame sequence
1369 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1370 g->src_x = parameter[GFX_ARG_X];
1371 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1372 g->src_y = parameter[GFX_ARG_Y];
1378 Error(ERR_INFO_LINE, "-");
1379 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1380 g->width, getTokenFromImageID(graphic), TILEX);
1381 Error(ERR_INFO_LINE, "-");
1383 g->width = TILEX; // will be checked to be inside bitmap later
1388 Error(ERR_INFO_LINE, "-");
1389 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1390 g->height, getTokenFromImageID(graphic), TILEY);
1391 Error(ERR_INFO_LINE, "-");
1393 g->height = TILEY; // will be checked to be inside bitmap later
1399 // get final bitmap size (with scaling, but without small images)
1400 int src_image_width = get_scaled_graphic_width(graphic);
1401 int src_image_height = get_scaled_graphic_height(graphic);
1403 if (src_image_width == 0 || src_image_height == 0)
1405 // only happens when loaded outside artwork system (like "global.busy")
1406 src_image_width = src_bitmap->width;
1407 src_image_height = src_bitmap->height;
1410 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1412 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1413 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1417 anim_frames_per_row = MAX(1, src_image_width / g->width);
1418 anim_frames_per_col = MAX(1, src_image_height / g->height);
1421 g->src_image_width = src_image_width;
1422 g->src_image_height = src_image_height;
1425 // correct x or y offset dependent of vertical or horizontal frame order
1426 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1428 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1429 parameter[GFX_ARG_OFFSET] : g->height);
1430 anim_frames_per_line = anim_frames_per_col;
1432 else // frames are ordered horizontally
1434 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1435 parameter[GFX_ARG_OFFSET] : g->width);
1436 anim_frames_per_line = anim_frames_per_row;
1439 // optionally, the x and y offset of frames can be specified directly
1440 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1441 g->offset_x = parameter[GFX_ARG_XOFFSET];
1442 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1443 g->offset_y = parameter[GFX_ARG_YOFFSET];
1445 // optionally, moving animations may have separate start and end graphics
1446 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1448 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1449 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1451 // correct x or y offset2 dependent of vertical or horizontal frame order
1452 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1453 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1454 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1455 else // frames are ordered horizontally
1456 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1457 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1459 // optionally, the x and y offset of 2nd graphic can be specified directly
1460 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1461 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1462 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1463 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1465 // optionally, the second movement tile can be specified as start tile
1466 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1467 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1469 // automatically determine correct number of frames, if not defined
1470 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1471 g->anim_frames = parameter[GFX_ARG_FRAMES];
1472 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1473 g->anim_frames = anim_frames_per_row;
1474 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1475 g->anim_frames = anim_frames_per_col;
1479 if (g->anim_frames < 1) // frames must be at least 1
1482 g->anim_frames_per_line =
1483 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1484 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1486 g->anim_delay = parameter[GFX_ARG_DELAY];
1487 if (g->anim_delay < 1) // delay must be at least 1
1490 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1492 // automatically determine correct start frame, if not defined
1493 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1494 g->anim_start_frame = 0;
1495 else if (g->anim_mode & ANIM_REVERSE)
1496 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1498 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1500 // animation synchronized with global frame counter, not move position
1501 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1503 // optional element for cloning crumble graphics
1504 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1505 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1507 // optional element for cloning digging graphics
1508 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1509 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1511 // optional border size for "crumbling" diggable graphics
1512 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1513 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1515 // used for global animations and player "boring" and "sleeping" actions
1516 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1517 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1518 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1519 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1520 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1521 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1522 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1523 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1524 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1525 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1526 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1527 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1529 // used for global animations
1530 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1531 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1532 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1533 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1534 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1535 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1536 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1537 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1538 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1539 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1540 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1541 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1542 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1543 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1545 // used for toon animations and global animations
1546 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1547 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1548 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1549 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1550 g->direction = parameter[GFX_ARG_DIRECTION];
1551 g->position = parameter[GFX_ARG_POSITION];
1552 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1553 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1555 if (g->step_delay < 1) // delay must be at least 1
1558 // this is only used for drawing font characters
1559 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1560 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1562 // use a different default value for global animations and toons
1563 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1564 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1565 g->draw_masked = TRUE;
1567 // this is used for drawing envelopes, global animations and toons
1568 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1569 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1571 // used for toon animations and global animations
1572 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1573 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1575 // optional graphic for cloning all graphics settings
1576 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1577 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1579 // optional settings for drawing title screens and title messages
1580 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1581 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1582 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1583 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1584 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1585 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1586 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1587 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1588 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1589 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1590 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1591 g->align = parameter[GFX_ARG_ALIGN];
1592 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1593 g->valign = parameter[GFX_ARG_VALIGN];
1594 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1595 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1597 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1598 g->class = parameter[GFX_ARG_CLASS];
1599 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1600 g->style = parameter[GFX_ARG_STYLE];
1602 // this is only used for drawing menu buttons and text
1603 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1604 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1605 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1606 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1609 static void set_graphic_parameters(int graphic)
1611 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1612 char **parameter_raw = image->parameter;
1613 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1614 int parameter[NUM_GFX_ARGS];
1617 // if fallback to default artwork is done, also use the default parameters
1618 if (image->fallback_to_default)
1619 parameter_raw = image->default_parameter;
1621 // get integer values from string parameters
1622 for (i = 0; i < NUM_GFX_ARGS; i++)
1623 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1624 image_config_suffix[i].token,
1625 image_config_suffix[i].type);
1627 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1629 UPDATE_BUSY_STATE();
1632 static void set_cloned_graphic_parameters(int graphic)
1634 int fallback_graphic = IMG_CHAR_EXCLAM;
1635 int max_num_images = getImageListSize();
1636 int clone_graphic = graphic_info[graphic].clone_from;
1637 int num_references_followed = 1;
1639 while (graphic_info[clone_graphic].clone_from != -1 &&
1640 num_references_followed < max_num_images)
1642 clone_graphic = graphic_info[clone_graphic].clone_from;
1644 num_references_followed++;
1647 if (num_references_followed >= max_num_images)
1649 Error(ERR_INFO_LINE, "-");
1650 Error(ERR_INFO, "warning: error found in config file:");
1651 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1652 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1653 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1654 Error(ERR_INFO, "custom graphic rejected for this element/action");
1656 if (graphic == fallback_graphic)
1657 Error(ERR_EXIT, "no fallback graphic available");
1659 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1660 Error(ERR_INFO_LINE, "-");
1662 graphic_info[graphic] = graphic_info[fallback_graphic];
1666 graphic_info[graphic] = graphic_info[clone_graphic];
1667 graphic_info[graphic].clone_from = clone_graphic;
1671 static void InitGraphicInfo(void)
1673 int fallback_graphic = IMG_CHAR_EXCLAM;
1674 int num_images = getImageListSize();
1677 // use image size as default values for width and height for these images
1678 static int full_size_graphics[] =
1681 IMG_GLOBAL_BORDER_MAIN,
1682 IMG_GLOBAL_BORDER_SCORES,
1683 IMG_GLOBAL_BORDER_EDITOR,
1684 IMG_GLOBAL_BORDER_PLAYING,
1687 IMG_BACKGROUND_ENVELOPE_1,
1688 IMG_BACKGROUND_ENVELOPE_2,
1689 IMG_BACKGROUND_ENVELOPE_3,
1690 IMG_BACKGROUND_ENVELOPE_4,
1691 IMG_BACKGROUND_REQUEST,
1694 IMG_BACKGROUND_TITLE_INITIAL,
1695 IMG_BACKGROUND_TITLE,
1696 IMG_BACKGROUND_MAIN,
1697 IMG_BACKGROUND_LEVELS,
1698 IMG_BACKGROUND_LEVELNR,
1699 IMG_BACKGROUND_SCORES,
1700 IMG_BACKGROUND_EDITOR,
1701 IMG_BACKGROUND_INFO,
1702 IMG_BACKGROUND_INFO_ELEMENTS,
1703 IMG_BACKGROUND_INFO_MUSIC,
1704 IMG_BACKGROUND_INFO_CREDITS,
1705 IMG_BACKGROUND_INFO_PROGRAM,
1706 IMG_BACKGROUND_INFO_VERSION,
1707 IMG_BACKGROUND_INFO_LEVELSET,
1708 IMG_BACKGROUND_SETUP,
1709 IMG_BACKGROUND_PLAYING,
1710 IMG_BACKGROUND_DOOR,
1711 IMG_BACKGROUND_TAPE,
1712 IMG_BACKGROUND_PANEL,
1713 IMG_BACKGROUND_PALETTE,
1714 IMG_BACKGROUND_TOOLBOX,
1716 IMG_TITLESCREEN_INITIAL_1,
1717 IMG_TITLESCREEN_INITIAL_2,
1718 IMG_TITLESCREEN_INITIAL_3,
1719 IMG_TITLESCREEN_INITIAL_4,
1720 IMG_TITLESCREEN_INITIAL_5,
1727 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1728 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1729 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1730 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1731 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1732 IMG_BACKGROUND_TITLEMESSAGE_1,
1733 IMG_BACKGROUND_TITLEMESSAGE_2,
1734 IMG_BACKGROUND_TITLEMESSAGE_3,
1735 IMG_BACKGROUND_TITLEMESSAGE_4,
1736 IMG_BACKGROUND_TITLEMESSAGE_5,
1741 FreeGlobalAnimEventInfo();
1743 checked_free(graphic_info);
1745 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1747 // initialize "use_image_size" flag with default value
1748 for (i = 0; i < num_images; i++)
1749 graphic_info[i].use_image_size = FALSE;
1751 // initialize "use_image_size" flag from static configuration above
1752 for (i = 0; full_size_graphics[i] != -1; i++)
1753 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1755 // first set all graphic paramaters ...
1756 for (i = 0; i < num_images; i++)
1757 set_graphic_parameters(i);
1759 // ... then copy these parameters for cloned graphics
1760 for (i = 0; i < num_images; i++)
1761 if (graphic_info[i].clone_from != -1)
1762 set_cloned_graphic_parameters(i);
1764 for (i = 0; i < num_images; i++)
1766 Bitmap *src_bitmap = graphic_info[i].bitmap;
1770 int src_bitmap_width, src_bitmap_height;
1772 // now check if no animation frames are outside of the loaded image
1774 if (graphic_info[i].bitmap == NULL)
1775 continue; // skip check for optional images that are undefined
1777 // get image size (this can differ from the standard element tile size!)
1778 width = graphic_info[i].width;
1779 height = graphic_info[i].height;
1781 // get final bitmap size (with scaling, but without small images)
1782 src_bitmap_width = graphic_info[i].src_image_width;
1783 src_bitmap_height = graphic_info[i].src_image_height;
1785 // check if first animation frame is inside specified bitmap
1787 // do not use getGraphicSourceXY() here to get position of first frame;
1788 // this avoids calculating wrong start position for out-of-bounds frame
1789 src_x = graphic_info[i].src_x;
1790 src_y = graphic_info[i].src_y;
1792 if (program.headless)
1795 if (src_x < 0 || src_y < 0 ||
1796 src_x + width > src_bitmap_width ||
1797 src_y + height > src_bitmap_height)
1799 Error(ERR_INFO_LINE, "-");
1800 Error(ERR_INFO, "warning: error found in config file:");
1801 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1802 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1803 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1804 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1806 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1807 src_x, src_y, src_bitmap_width, src_bitmap_height);
1808 Error(ERR_INFO, "custom graphic rejected for this element/action");
1810 if (i == fallback_graphic)
1811 Error(ERR_EXIT, "no fallback graphic available");
1813 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1814 Error(ERR_INFO_LINE, "-");
1816 graphic_info[i] = graphic_info[fallback_graphic];
1818 // if first frame out of bounds, do not check last frame anymore
1822 // check if last animation frame is inside specified bitmap
1824 last_frame = graphic_info[i].anim_frames - 1;
1825 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1827 if (src_x < 0 || src_y < 0 ||
1828 src_x + width > src_bitmap_width ||
1829 src_y + height > src_bitmap_height)
1831 Error(ERR_INFO_LINE, "-");
1832 Error(ERR_INFO, "warning: error found in config file:");
1833 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1834 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1835 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1836 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1838 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1839 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1840 Error(ERR_INFO, "custom graphic rejected for this element/action");
1842 if (i == fallback_graphic)
1843 Error(ERR_EXIT, "no fallback graphic available");
1845 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1846 Error(ERR_INFO_LINE, "-");
1848 graphic_info[i] = graphic_info[fallback_graphic];
1853 static void InitGraphicCompatibilityInfo(void)
1855 struct FileInfo *fi_global_door =
1856 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1857 int num_images = getImageListSize();
1860 /* the following compatibility handling is needed for the following case:
1861 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1862 graphics mainly used for door and panel graphics, like editor, tape and
1863 in-game buttons with hard-coded bitmap positions and button sizes; as
1864 these graphics now have individual definitions, redefining "global.door"
1865 to change all these graphics at once like before does not work anymore
1866 (because all those individual definitions still have their default values);
1867 to solve this, remap all those individual definitions that are not
1868 redefined to the new bitmap of "global.door" if it was redefined */
1870 // special compatibility handling if image "global.door" was redefined
1871 if (fi_global_door->redefined)
1873 for (i = 0; i < num_images; i++)
1875 struct FileInfo *fi = getImageListEntryFromImageID(i);
1877 // process only those images that still use the default settings
1880 // process all images which default to same image as "global.door"
1881 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1883 // printf("::: special treatment needed for token '%s'\n", fi->token);
1885 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1886 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1892 InitGraphicCompatibilityInfo_Doors();
1895 static void InitElementSoundInfo(void)
1897 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1898 int num_property_mappings = getSoundListPropertyMappingSize();
1901 // set values to -1 to identify later as "uninitialized" values
1902 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1903 for (act = 0; act < NUM_ACTIONS; act++)
1904 element_info[i].sound[act] = -1;
1906 // initialize element/sound mapping from static configuration
1907 for (i = 0; element_to_sound[i].element > -1; i++)
1909 int element = element_to_sound[i].element;
1910 int action = element_to_sound[i].action;
1911 int sound = element_to_sound[i].sound;
1912 boolean is_class = element_to_sound[i].is_class;
1915 action = ACTION_DEFAULT;
1918 element_info[element].sound[action] = sound;
1920 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1921 if (strEqual(element_info[j].class_name,
1922 element_info[element].class_name))
1923 element_info[j].sound[action] = sound;
1926 // initialize element class/sound mapping from dynamic configuration
1927 for (i = 0; i < num_property_mappings; i++)
1929 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1930 int action = property_mapping[i].ext1_index;
1931 int sound = property_mapping[i].artwork_index;
1933 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1937 action = ACTION_DEFAULT;
1939 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1940 if (strEqual(element_info[j].class_name,
1941 element_info[element_class].class_name))
1942 element_info[j].sound[action] = sound;
1945 // initialize element/sound mapping from dynamic configuration
1946 for (i = 0; i < num_property_mappings; i++)
1948 int element = property_mapping[i].base_index;
1949 int action = property_mapping[i].ext1_index;
1950 int sound = property_mapping[i].artwork_index;
1952 if (element >= MAX_NUM_ELEMENTS)
1956 action = ACTION_DEFAULT;
1958 element_info[element].sound[action] = sound;
1961 // now set all '-1' values to element specific default values
1962 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1964 for (act = 0; act < NUM_ACTIONS; act++)
1966 // generic default action sound (defined by "[default]" directive)
1967 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1969 // look for special default action sound (classic game specific)
1970 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1971 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1972 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1973 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1974 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1975 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1976 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1977 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1979 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1980 // !!! make this better !!!
1981 if (i == EL_EMPTY_SPACE)
1982 default_action_sound = element_info[EL_DEFAULT].sound[act];
1984 // no sound for this specific action -- use default action sound
1985 if (element_info[i].sound[act] == -1)
1986 element_info[i].sound[act] = default_action_sound;
1990 // copy sound settings to some elements that are only stored in level file
1991 // in native R'n'D levels, but are used by game engine in native EM levels
1992 for (i = 0; copy_properties[i][0] != -1; i++)
1993 for (j = 1; j <= 4; j++)
1994 for (act = 0; act < NUM_ACTIONS; act++)
1995 element_info[copy_properties[i][j]].sound[act] =
1996 element_info[copy_properties[i][0]].sound[act];
1999 static void InitGameModeSoundInfo(void)
2003 // set values to -1 to identify later as "uninitialized" values
2004 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2007 // initialize gamemode/sound mapping from static configuration
2008 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2010 int gamemode = gamemode_to_sound[i].gamemode;
2011 int sound = gamemode_to_sound[i].sound;
2014 gamemode = GAME_MODE_DEFAULT;
2016 menu.sound[gamemode] = sound;
2019 // now set all '-1' values to levelset specific default values
2020 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2021 if (menu.sound[i] == -1)
2022 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2025 static void set_sound_parameters(int sound, char **parameter_raw)
2027 int parameter[NUM_SND_ARGS];
2030 // get integer values from string parameters
2031 for (i = 0; i < NUM_SND_ARGS; i++)
2033 get_parameter_value(parameter_raw[i],
2034 sound_config_suffix[i].token,
2035 sound_config_suffix[i].type);
2037 // explicit loop mode setting in configuration overrides default value
2038 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2039 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2041 // sound volume to change the original volume when loading the sound file
2042 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2044 // sound priority to give certain sounds a higher or lower priority
2045 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2048 static void InitSoundInfo(void)
2050 int *sound_effect_properties;
2051 int num_sounds = getSoundListSize();
2054 checked_free(sound_info);
2056 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2057 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2059 // initialize sound effect for all elements to "no sound"
2060 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2061 for (j = 0; j < NUM_ACTIONS; j++)
2062 element_info[i].sound[j] = SND_UNDEFINED;
2064 for (i = 0; i < num_sounds; i++)
2066 struct FileInfo *sound = getSoundListEntry(i);
2067 int len_effect_text = strlen(sound->token);
2069 sound_effect_properties[i] = ACTION_OTHER;
2070 sound_info[i].loop = FALSE; // default: play sound only once
2072 // determine all loop sounds and identify certain sound classes
2074 for (j = 0; element_action_info[j].suffix; j++)
2076 int len_action_text = strlen(element_action_info[j].suffix);
2078 if (len_action_text < len_effect_text &&
2079 strEqual(&sound->token[len_effect_text - len_action_text],
2080 element_action_info[j].suffix))
2082 sound_effect_properties[i] = element_action_info[j].value;
2083 sound_info[i].loop = element_action_info[j].is_loop_sound;
2089 // associate elements and some selected sound actions
2091 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2093 if (element_info[j].class_name)
2095 int len_class_text = strlen(element_info[j].class_name);
2097 if (len_class_text + 1 < len_effect_text &&
2098 strncmp(sound->token,
2099 element_info[j].class_name, len_class_text) == 0 &&
2100 sound->token[len_class_text] == '.')
2102 int sound_action_value = sound_effect_properties[i];
2104 element_info[j].sound[sound_action_value] = i;
2109 set_sound_parameters(i, sound->parameter);
2112 free(sound_effect_properties);
2115 static void InitGameModeMusicInfo(void)
2117 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2118 int num_property_mappings = getMusicListPropertyMappingSize();
2119 int default_levelset_music = -1;
2122 // set values to -1 to identify later as "uninitialized" values
2123 for (i = 0; i < MAX_LEVELS; i++)
2124 levelset.music[i] = -1;
2125 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2128 // initialize gamemode/music mapping from static configuration
2129 for (i = 0; gamemode_to_music[i].music > -1; i++)
2131 int gamemode = gamemode_to_music[i].gamemode;
2132 int music = gamemode_to_music[i].music;
2135 gamemode = GAME_MODE_DEFAULT;
2137 menu.music[gamemode] = music;
2140 // initialize gamemode/music mapping from dynamic configuration
2141 for (i = 0; i < num_property_mappings; i++)
2143 int prefix = property_mapping[i].base_index;
2144 int gamemode = property_mapping[i].ext2_index;
2145 int level = property_mapping[i].ext3_index;
2146 int music = property_mapping[i].artwork_index;
2148 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2152 gamemode = GAME_MODE_DEFAULT;
2154 // level specific music only allowed for in-game music
2155 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2156 gamemode = GAME_MODE_PLAYING;
2161 default_levelset_music = music;
2164 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2165 levelset.music[level] = music;
2166 if (gamemode != GAME_MODE_PLAYING)
2167 menu.music[gamemode] = music;
2170 // now set all '-1' values to menu specific default values
2171 // (undefined values of "levelset.music[]" might stay at "-1" to
2172 // allow dynamic selection of music files from music directory!)
2173 for (i = 0; i < MAX_LEVELS; i++)
2174 if (levelset.music[i] == -1)
2175 levelset.music[i] = default_levelset_music;
2176 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2177 if (menu.music[i] == -1)
2178 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2181 static void set_music_parameters(int music, char **parameter_raw)
2183 int parameter[NUM_MUS_ARGS];
2186 // get integer values from string parameters
2187 for (i = 0; i < NUM_MUS_ARGS; i++)
2189 get_parameter_value(parameter_raw[i],
2190 music_config_suffix[i].token,
2191 music_config_suffix[i].type);
2193 // explicit loop mode setting in configuration overrides default value
2194 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2195 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2198 static void InitMusicInfo(void)
2200 int num_music = getMusicListSize();
2203 checked_free(music_info);
2205 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2207 for (i = 0; i < num_music; i++)
2209 struct FileInfo *music = getMusicListEntry(i);
2210 int len_music_text = strlen(music->token);
2212 music_info[i].loop = TRUE; // default: play music in loop mode
2214 // determine all loop music
2216 for (j = 0; music_prefix_info[j].prefix; j++)
2218 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2220 if (len_prefix_text < len_music_text &&
2221 strncmp(music->token,
2222 music_prefix_info[j].prefix, len_prefix_text) == 0)
2224 music_info[i].loop = music_prefix_info[j].is_loop_music;
2230 set_music_parameters(i, music->parameter);
2234 static void ReinitializeGraphics(void)
2236 print_timestamp_init("ReinitializeGraphics");
2238 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2240 InitGraphicInfo(); // graphic properties mapping
2241 print_timestamp_time("InitGraphicInfo");
2242 InitElementGraphicInfo(); // element game graphic mapping
2243 print_timestamp_time("InitElementGraphicInfo");
2244 InitElementSpecialGraphicInfo(); // element special graphic mapping
2245 print_timestamp_time("InitElementSpecialGraphicInfo");
2247 InitElementSmallImages(); // scale elements to all needed sizes
2248 print_timestamp_time("InitElementSmallImages");
2249 InitScaledImages(); // scale all other images, if needed
2250 print_timestamp_time("InitScaledImages");
2251 InitBitmapPointers(); // set standard size bitmap pointers
2252 print_timestamp_time("InitBitmapPointers");
2253 InitFontGraphicInfo(); // initialize text drawing functions
2254 print_timestamp_time("InitFontGraphicInfo");
2255 InitGlobalAnimGraphicInfo(); // initialize global animation config
2256 print_timestamp_time("InitGlobalAnimGraphicInfo");
2258 InitImageTextures(); // create textures for certain images
2259 print_timestamp_time("InitImageTextures");
2261 InitGraphicInfo_EM(); // graphic mapping for EM engine
2262 print_timestamp_time("InitGraphicInfo_EM");
2264 InitGraphicCompatibilityInfo();
2265 print_timestamp_time("InitGraphicCompatibilityInfo");
2267 SetMainBackgroundImage(IMG_BACKGROUND);
2268 print_timestamp_time("SetMainBackgroundImage");
2269 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2270 print_timestamp_time("SetDoorBackgroundImage");
2273 print_timestamp_time("InitGadgets");
2275 print_timestamp_time("InitDoors");
2277 print_timestamp_done("ReinitializeGraphics");
2280 static void ReinitializeSounds(void)
2282 InitSoundInfo(); // sound properties mapping
2283 InitElementSoundInfo(); // element game sound mapping
2284 InitGameModeSoundInfo(); // game mode sound mapping
2285 InitGlobalAnimSoundInfo(); // global animation sound settings
2287 InitPlayLevelSound(); // internal game sound settings
2290 static void ReinitializeMusic(void)
2292 InitMusicInfo(); // music properties mapping
2293 InitGameModeMusicInfo(); // game mode music mapping
2294 InitGlobalAnimMusicInfo(); // global animation music settings
2297 static int get_special_property_bit(int element, int property_bit_nr)
2299 struct PropertyBitInfo
2305 static struct PropertyBitInfo pb_can_move_into_acid[] =
2307 // the player may be able fall into acid when gravity is activated
2312 { EL_SP_MURPHY, 0 },
2313 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2315 // all elements that can move may be able to also move into acid
2318 { EL_BUG_RIGHT, 1 },
2321 { EL_SPACESHIP, 2 },
2322 { EL_SPACESHIP_LEFT, 2 },
2323 { EL_SPACESHIP_RIGHT, 2 },
2324 { EL_SPACESHIP_UP, 2 },
2325 { EL_SPACESHIP_DOWN, 2 },
2326 { EL_BD_BUTTERFLY, 3 },
2327 { EL_BD_BUTTERFLY_LEFT, 3 },
2328 { EL_BD_BUTTERFLY_RIGHT, 3 },
2329 { EL_BD_BUTTERFLY_UP, 3 },
2330 { EL_BD_BUTTERFLY_DOWN, 3 },
2331 { EL_BD_FIREFLY, 4 },
2332 { EL_BD_FIREFLY_LEFT, 4 },
2333 { EL_BD_FIREFLY_RIGHT, 4 },
2334 { EL_BD_FIREFLY_UP, 4 },
2335 { EL_BD_FIREFLY_DOWN, 4 },
2337 { EL_YAMYAM_LEFT, 5 },
2338 { EL_YAMYAM_RIGHT, 5 },
2339 { EL_YAMYAM_UP, 5 },
2340 { EL_YAMYAM_DOWN, 5 },
2341 { EL_DARK_YAMYAM, 6 },
2344 { EL_PACMAN_LEFT, 8 },
2345 { EL_PACMAN_RIGHT, 8 },
2346 { EL_PACMAN_UP, 8 },
2347 { EL_PACMAN_DOWN, 8 },
2349 { EL_MOLE_LEFT, 9 },
2350 { EL_MOLE_RIGHT, 9 },
2352 { EL_MOLE_DOWN, 9 },
2356 { EL_SATELLITE, 13 },
2357 { EL_SP_SNIKSNAK, 14 },
2358 { EL_SP_ELECTRON, 15 },
2361 { EL_EMC_ANDROID, 18 },
2366 static struct PropertyBitInfo pb_dont_collide_with[] =
2368 { EL_SP_SNIKSNAK, 0 },
2369 { EL_SP_ELECTRON, 1 },
2377 struct PropertyBitInfo *pb_info;
2380 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2381 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2386 struct PropertyBitInfo *pb_info = NULL;
2389 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2390 if (pb_definition[i].bit_nr == property_bit_nr)
2391 pb_info = pb_definition[i].pb_info;
2393 if (pb_info == NULL)
2396 for (i = 0; pb_info[i].element != -1; i++)
2397 if (pb_info[i].element == element)
2398 return pb_info[i].bit_nr;
2403 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2404 boolean property_value)
2406 int bit_nr = get_special_property_bit(element, property_bit_nr);
2411 *bitfield |= (1 << bit_nr);
2413 *bitfield &= ~(1 << bit_nr);
2417 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2419 int bit_nr = get_special_property_bit(element, property_bit_nr);
2422 return ((*bitfield & (1 << bit_nr)) != 0);
2427 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2429 static int group_nr;
2430 static struct ElementGroupInfo *group;
2431 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2434 if (actual_group == NULL) // not yet initialized
2437 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2439 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2440 group_element - EL_GROUP_START + 1);
2442 // replace element which caused too deep recursion by question mark
2443 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2448 if (recursion_depth == 0) // initialization
2450 group = actual_group;
2451 group_nr = GROUP_NR(group_element);
2453 group->num_elements_resolved = 0;
2454 group->choice_pos = 0;
2456 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2457 element_info[i].in_group[group_nr] = FALSE;
2460 for (i = 0; i < actual_group->num_elements; i++)
2462 int element = actual_group->element[i];
2464 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2467 if (IS_GROUP_ELEMENT(element))
2468 ResolveGroupElementExt(element, recursion_depth + 1);
2471 group->element_resolved[group->num_elements_resolved++] = element;
2472 element_info[element].in_group[group_nr] = TRUE;
2477 void ResolveGroupElement(int group_element)
2479 ResolveGroupElementExt(group_element, 0);
2482 void InitElementPropertiesStatic(void)
2484 static boolean clipboard_elements_initialized = FALSE;
2486 static int ep_diggable[] =
2491 EL_SP_BUGGY_BASE_ACTIVATING,
2494 EL_INVISIBLE_SAND_ACTIVE,
2497 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2498 // (if amoeba can grow into anything diggable, maybe keep these out)
2503 EL_SP_BUGGY_BASE_ACTIVE,
2510 static int ep_collectible_only[] =
2532 EL_DYNABOMB_INCREASE_NUMBER,
2533 EL_DYNABOMB_INCREASE_SIZE,
2534 EL_DYNABOMB_INCREASE_POWER,
2552 // !!! handle separately !!!
2553 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2559 static int ep_dont_run_into[] =
2561 // same elements as in 'ep_dont_touch'
2567 // same elements as in 'ep_dont_collide_with'
2579 // !!! maybe this should better be handled by 'ep_diggable' !!!
2584 EL_SP_BUGGY_BASE_ACTIVE,
2591 static int ep_dont_collide_with[] =
2593 // same elements as in 'ep_dont_touch'
2610 static int ep_dont_touch[] =
2620 static int ep_indestructible[] =
2624 EL_ACID_POOL_TOPLEFT,
2625 EL_ACID_POOL_TOPRIGHT,
2626 EL_ACID_POOL_BOTTOMLEFT,
2627 EL_ACID_POOL_BOTTOM,
2628 EL_ACID_POOL_BOTTOMRIGHT,
2629 EL_SP_HARDWARE_GRAY,
2630 EL_SP_HARDWARE_GREEN,
2631 EL_SP_HARDWARE_BLUE,
2633 EL_SP_HARDWARE_YELLOW,
2634 EL_SP_HARDWARE_BASE_1,
2635 EL_SP_HARDWARE_BASE_2,
2636 EL_SP_HARDWARE_BASE_3,
2637 EL_SP_HARDWARE_BASE_4,
2638 EL_SP_HARDWARE_BASE_5,
2639 EL_SP_HARDWARE_BASE_6,
2640 EL_INVISIBLE_STEELWALL,
2641 EL_INVISIBLE_STEELWALL_ACTIVE,
2642 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2643 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2644 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2645 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2646 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2647 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2648 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2649 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2650 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2651 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2652 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2653 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2655 EL_LIGHT_SWITCH_ACTIVE,
2656 EL_SIGN_EXCLAMATION,
2657 EL_SIGN_RADIOACTIVITY,
2664 EL_SIGN_ENTRY_FORBIDDEN,
2665 EL_SIGN_EMERGENCY_EXIT,
2673 EL_STEEL_EXIT_CLOSED,
2675 EL_STEEL_EXIT_OPENING,
2676 EL_STEEL_EXIT_CLOSING,
2677 EL_EM_STEEL_EXIT_CLOSED,
2678 EL_EM_STEEL_EXIT_OPEN,
2679 EL_EM_STEEL_EXIT_OPENING,
2680 EL_EM_STEEL_EXIT_CLOSING,
2681 EL_DC_STEELWALL_1_LEFT,
2682 EL_DC_STEELWALL_1_RIGHT,
2683 EL_DC_STEELWALL_1_TOP,
2684 EL_DC_STEELWALL_1_BOTTOM,
2685 EL_DC_STEELWALL_1_HORIZONTAL,
2686 EL_DC_STEELWALL_1_VERTICAL,
2687 EL_DC_STEELWALL_1_TOPLEFT,
2688 EL_DC_STEELWALL_1_TOPRIGHT,
2689 EL_DC_STEELWALL_1_BOTTOMLEFT,
2690 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2691 EL_DC_STEELWALL_1_TOPLEFT_2,
2692 EL_DC_STEELWALL_1_TOPRIGHT_2,
2693 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2694 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2695 EL_DC_STEELWALL_2_LEFT,
2696 EL_DC_STEELWALL_2_RIGHT,
2697 EL_DC_STEELWALL_2_TOP,
2698 EL_DC_STEELWALL_2_BOTTOM,
2699 EL_DC_STEELWALL_2_HORIZONTAL,
2700 EL_DC_STEELWALL_2_VERTICAL,
2701 EL_DC_STEELWALL_2_MIDDLE,
2702 EL_DC_STEELWALL_2_SINGLE,
2703 EL_STEELWALL_SLIPPERY,
2717 EL_GATE_1_GRAY_ACTIVE,
2718 EL_GATE_2_GRAY_ACTIVE,
2719 EL_GATE_3_GRAY_ACTIVE,
2720 EL_GATE_4_GRAY_ACTIVE,
2729 EL_EM_GATE_1_GRAY_ACTIVE,
2730 EL_EM_GATE_2_GRAY_ACTIVE,
2731 EL_EM_GATE_3_GRAY_ACTIVE,
2732 EL_EM_GATE_4_GRAY_ACTIVE,
2741 EL_EMC_GATE_5_GRAY_ACTIVE,
2742 EL_EMC_GATE_6_GRAY_ACTIVE,
2743 EL_EMC_GATE_7_GRAY_ACTIVE,
2744 EL_EMC_GATE_8_GRAY_ACTIVE,
2746 EL_DC_GATE_WHITE_GRAY,
2747 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2748 EL_DC_GATE_FAKE_GRAY,
2750 EL_SWITCHGATE_OPENING,
2751 EL_SWITCHGATE_CLOSED,
2752 EL_SWITCHGATE_CLOSING,
2753 EL_DC_SWITCHGATE_SWITCH_UP,
2754 EL_DC_SWITCHGATE_SWITCH_DOWN,
2756 EL_TIMEGATE_OPENING,
2758 EL_TIMEGATE_CLOSING,
2759 EL_DC_TIMEGATE_SWITCH,
2760 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2764 EL_TUBE_VERTICAL_LEFT,
2765 EL_TUBE_VERTICAL_RIGHT,
2766 EL_TUBE_HORIZONTAL_UP,
2767 EL_TUBE_HORIZONTAL_DOWN,
2772 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2773 EL_EXPANDABLE_STEELWALL_VERTICAL,
2774 EL_EXPANDABLE_STEELWALL_ANY,
2779 static int ep_slippery[] =
2793 EL_ROBOT_WHEEL_ACTIVE,
2799 EL_ACID_POOL_TOPLEFT,
2800 EL_ACID_POOL_TOPRIGHT,
2810 EL_STEELWALL_SLIPPERY,
2813 EL_EMC_WALL_SLIPPERY_1,
2814 EL_EMC_WALL_SLIPPERY_2,
2815 EL_EMC_WALL_SLIPPERY_3,
2816 EL_EMC_WALL_SLIPPERY_4,
2818 EL_EMC_MAGIC_BALL_ACTIVE,
2823 static int ep_can_change[] =
2828 static int ep_can_move[] =
2830 // same elements as in 'pb_can_move_into_acid'
2853 static int ep_can_fall[] =
2867 EL_QUICKSAND_FAST_FULL,
2869 EL_BD_MAGIC_WALL_FULL,
2870 EL_DC_MAGIC_WALL_FULL,
2884 static int ep_can_smash_player[] =
2910 static int ep_can_smash_enemies[] =
2919 static int ep_can_smash_everything[] =
2928 static int ep_explodes_by_fire[] =
2930 // same elements as in 'ep_explodes_impact'
2935 // same elements as in 'ep_explodes_smashed'
2945 EL_EM_DYNAMITE_ACTIVE,
2946 EL_DYNABOMB_PLAYER_1_ACTIVE,
2947 EL_DYNABOMB_PLAYER_2_ACTIVE,
2948 EL_DYNABOMB_PLAYER_3_ACTIVE,
2949 EL_DYNABOMB_PLAYER_4_ACTIVE,
2950 EL_DYNABOMB_INCREASE_NUMBER,
2951 EL_DYNABOMB_INCREASE_SIZE,
2952 EL_DYNABOMB_INCREASE_POWER,
2953 EL_SP_DISK_RED_ACTIVE,
2967 static int ep_explodes_smashed[] =
2969 // same elements as in 'ep_explodes_impact'
2983 static int ep_explodes_impact[] =
2992 static int ep_walkable_over[] =
2996 EL_SOKOBAN_FIELD_EMPTY,
3003 EL_EM_STEEL_EXIT_OPEN,
3004 EL_EM_STEEL_EXIT_OPENING,
3013 EL_GATE_1_GRAY_ACTIVE,
3014 EL_GATE_2_GRAY_ACTIVE,
3015 EL_GATE_3_GRAY_ACTIVE,
3016 EL_GATE_4_GRAY_ACTIVE,
3024 static int ep_walkable_inside[] =
3029 EL_TUBE_VERTICAL_LEFT,
3030 EL_TUBE_VERTICAL_RIGHT,
3031 EL_TUBE_HORIZONTAL_UP,
3032 EL_TUBE_HORIZONTAL_DOWN,
3041 static int ep_walkable_under[] =
3046 static int ep_passable_over[] =
3056 EL_EM_GATE_1_GRAY_ACTIVE,
3057 EL_EM_GATE_2_GRAY_ACTIVE,
3058 EL_EM_GATE_3_GRAY_ACTIVE,
3059 EL_EM_GATE_4_GRAY_ACTIVE,
3068 EL_EMC_GATE_5_GRAY_ACTIVE,
3069 EL_EMC_GATE_6_GRAY_ACTIVE,
3070 EL_EMC_GATE_7_GRAY_ACTIVE,
3071 EL_EMC_GATE_8_GRAY_ACTIVE,
3073 EL_DC_GATE_WHITE_GRAY,
3074 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3081 static int ep_passable_inside[] =
3087 EL_SP_PORT_HORIZONTAL,
3088 EL_SP_PORT_VERTICAL,
3090 EL_SP_GRAVITY_PORT_LEFT,
3091 EL_SP_GRAVITY_PORT_RIGHT,
3092 EL_SP_GRAVITY_PORT_UP,
3093 EL_SP_GRAVITY_PORT_DOWN,
3094 EL_SP_GRAVITY_ON_PORT_LEFT,
3095 EL_SP_GRAVITY_ON_PORT_RIGHT,
3096 EL_SP_GRAVITY_ON_PORT_UP,
3097 EL_SP_GRAVITY_ON_PORT_DOWN,
3098 EL_SP_GRAVITY_OFF_PORT_LEFT,
3099 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3100 EL_SP_GRAVITY_OFF_PORT_UP,
3101 EL_SP_GRAVITY_OFF_PORT_DOWN,
3106 static int ep_passable_under[] =
3111 static int ep_droppable[] =
3116 static int ep_explodes_1x1_old[] =
3121 static int ep_pushable[] =
3133 EL_SOKOBAN_FIELD_FULL,
3142 static int ep_explodes_cross_old[] =
3147 static int ep_protected[] =
3149 // same elements as in 'ep_walkable_inside'
3153 EL_TUBE_VERTICAL_LEFT,
3154 EL_TUBE_VERTICAL_RIGHT,
3155 EL_TUBE_HORIZONTAL_UP,
3156 EL_TUBE_HORIZONTAL_DOWN,
3162 // same elements as in 'ep_passable_over'
3171 EL_EM_GATE_1_GRAY_ACTIVE,
3172 EL_EM_GATE_2_GRAY_ACTIVE,
3173 EL_EM_GATE_3_GRAY_ACTIVE,
3174 EL_EM_GATE_4_GRAY_ACTIVE,
3183 EL_EMC_GATE_5_GRAY_ACTIVE,
3184 EL_EMC_GATE_6_GRAY_ACTIVE,
3185 EL_EMC_GATE_7_GRAY_ACTIVE,
3186 EL_EMC_GATE_8_GRAY_ACTIVE,
3188 EL_DC_GATE_WHITE_GRAY,
3189 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3193 // same elements as in 'ep_passable_inside'
3198 EL_SP_PORT_HORIZONTAL,
3199 EL_SP_PORT_VERTICAL,
3201 EL_SP_GRAVITY_PORT_LEFT,
3202 EL_SP_GRAVITY_PORT_RIGHT,
3203 EL_SP_GRAVITY_PORT_UP,
3204 EL_SP_GRAVITY_PORT_DOWN,
3205 EL_SP_GRAVITY_ON_PORT_LEFT,
3206 EL_SP_GRAVITY_ON_PORT_RIGHT,
3207 EL_SP_GRAVITY_ON_PORT_UP,
3208 EL_SP_GRAVITY_ON_PORT_DOWN,
3209 EL_SP_GRAVITY_OFF_PORT_LEFT,
3210 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3211 EL_SP_GRAVITY_OFF_PORT_UP,
3212 EL_SP_GRAVITY_OFF_PORT_DOWN,
3217 static int ep_throwable[] =
3222 static int ep_can_explode[] =
3224 // same elements as in 'ep_explodes_impact'
3229 // same elements as in 'ep_explodes_smashed'
3235 // elements that can explode by explosion or by dragonfire
3239 EL_EM_DYNAMITE_ACTIVE,
3240 EL_DYNABOMB_PLAYER_1_ACTIVE,
3241 EL_DYNABOMB_PLAYER_2_ACTIVE,
3242 EL_DYNABOMB_PLAYER_3_ACTIVE,
3243 EL_DYNABOMB_PLAYER_4_ACTIVE,
3244 EL_DYNABOMB_INCREASE_NUMBER,
3245 EL_DYNABOMB_INCREASE_SIZE,
3246 EL_DYNABOMB_INCREASE_POWER,
3247 EL_SP_DISK_RED_ACTIVE,
3255 // elements that can explode only by explosion
3261 static int ep_gravity_reachable[] =
3267 EL_INVISIBLE_SAND_ACTIVE,
3272 EL_SP_PORT_HORIZONTAL,
3273 EL_SP_PORT_VERTICAL,
3275 EL_SP_GRAVITY_PORT_LEFT,
3276 EL_SP_GRAVITY_PORT_RIGHT,
3277 EL_SP_GRAVITY_PORT_UP,
3278 EL_SP_GRAVITY_PORT_DOWN,
3279 EL_SP_GRAVITY_ON_PORT_LEFT,
3280 EL_SP_GRAVITY_ON_PORT_RIGHT,
3281 EL_SP_GRAVITY_ON_PORT_UP,
3282 EL_SP_GRAVITY_ON_PORT_DOWN,
3283 EL_SP_GRAVITY_OFF_PORT_LEFT,
3284 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3285 EL_SP_GRAVITY_OFF_PORT_UP,
3286 EL_SP_GRAVITY_OFF_PORT_DOWN,
3292 static int ep_player[] =
3299 EL_SOKOBAN_FIELD_PLAYER,
3305 static int ep_can_pass_magic_wall[] =
3319 static int ep_can_pass_dc_magic_wall[] =
3335 static int ep_switchable[] =
3339 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3340 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3341 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3342 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3343 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3344 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3345 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3346 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3347 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3348 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3349 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3350 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3351 EL_SWITCHGATE_SWITCH_UP,
3352 EL_SWITCHGATE_SWITCH_DOWN,
3353 EL_DC_SWITCHGATE_SWITCH_UP,
3354 EL_DC_SWITCHGATE_SWITCH_DOWN,
3356 EL_LIGHT_SWITCH_ACTIVE,
3358 EL_DC_TIMEGATE_SWITCH,
3359 EL_BALLOON_SWITCH_LEFT,
3360 EL_BALLOON_SWITCH_RIGHT,
3361 EL_BALLOON_SWITCH_UP,
3362 EL_BALLOON_SWITCH_DOWN,
3363 EL_BALLOON_SWITCH_ANY,
3364 EL_BALLOON_SWITCH_NONE,
3367 EL_EMC_MAGIC_BALL_SWITCH,
3368 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3373 static int ep_bd_element[] =
3407 static int ep_sp_element[] =
3409 // should always be valid
3412 // standard classic Supaplex elements
3419 EL_SP_HARDWARE_GRAY,
3427 EL_SP_GRAVITY_PORT_RIGHT,
3428 EL_SP_GRAVITY_PORT_DOWN,
3429 EL_SP_GRAVITY_PORT_LEFT,
3430 EL_SP_GRAVITY_PORT_UP,
3435 EL_SP_PORT_VERTICAL,
3436 EL_SP_PORT_HORIZONTAL,
3442 EL_SP_HARDWARE_BASE_1,
3443 EL_SP_HARDWARE_GREEN,
3444 EL_SP_HARDWARE_BLUE,
3446 EL_SP_HARDWARE_YELLOW,
3447 EL_SP_HARDWARE_BASE_2,
3448 EL_SP_HARDWARE_BASE_3,
3449 EL_SP_HARDWARE_BASE_4,
3450 EL_SP_HARDWARE_BASE_5,
3451 EL_SP_HARDWARE_BASE_6,
3455 // additional elements that appeared in newer Supaplex levels
3458 // additional gravity port elements (not switching, but setting gravity)
3459 EL_SP_GRAVITY_ON_PORT_LEFT,
3460 EL_SP_GRAVITY_ON_PORT_RIGHT,
3461 EL_SP_GRAVITY_ON_PORT_UP,
3462 EL_SP_GRAVITY_ON_PORT_DOWN,
3463 EL_SP_GRAVITY_OFF_PORT_LEFT,
3464 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3465 EL_SP_GRAVITY_OFF_PORT_UP,
3466 EL_SP_GRAVITY_OFF_PORT_DOWN,
3468 // more than one Murphy in a level results in an inactive clone
3471 // runtime Supaplex elements
3472 EL_SP_DISK_RED_ACTIVE,
3473 EL_SP_TERMINAL_ACTIVE,
3474 EL_SP_BUGGY_BASE_ACTIVATING,
3475 EL_SP_BUGGY_BASE_ACTIVE,
3482 static int ep_sb_element[] =
3487 EL_SOKOBAN_FIELD_EMPTY,
3488 EL_SOKOBAN_FIELD_FULL,
3489 EL_SOKOBAN_FIELD_PLAYER,
3494 EL_INVISIBLE_STEELWALL,
3499 static int ep_gem[] =
3511 static int ep_food_dark_yamyam[] =
3539 static int ep_food_penguin[] =
3553 static int ep_food_pig[] =
3565 static int ep_historic_wall[] =
3576 EL_GATE_1_GRAY_ACTIVE,
3577 EL_GATE_2_GRAY_ACTIVE,
3578 EL_GATE_3_GRAY_ACTIVE,
3579 EL_GATE_4_GRAY_ACTIVE,
3588 EL_EM_GATE_1_GRAY_ACTIVE,
3589 EL_EM_GATE_2_GRAY_ACTIVE,
3590 EL_EM_GATE_3_GRAY_ACTIVE,
3591 EL_EM_GATE_4_GRAY_ACTIVE,
3598 EL_EXPANDABLE_WALL_HORIZONTAL,
3599 EL_EXPANDABLE_WALL_VERTICAL,
3600 EL_EXPANDABLE_WALL_ANY,
3601 EL_EXPANDABLE_WALL_GROWING,
3602 EL_BD_EXPANDABLE_WALL,
3609 EL_SP_HARDWARE_GRAY,
3610 EL_SP_HARDWARE_GREEN,
3611 EL_SP_HARDWARE_BLUE,
3613 EL_SP_HARDWARE_YELLOW,
3614 EL_SP_HARDWARE_BASE_1,
3615 EL_SP_HARDWARE_BASE_2,
3616 EL_SP_HARDWARE_BASE_3,
3617 EL_SP_HARDWARE_BASE_4,
3618 EL_SP_HARDWARE_BASE_5,
3619 EL_SP_HARDWARE_BASE_6,
3621 EL_SP_TERMINAL_ACTIVE,
3624 EL_INVISIBLE_STEELWALL,
3625 EL_INVISIBLE_STEELWALL_ACTIVE,
3627 EL_INVISIBLE_WALL_ACTIVE,
3628 EL_STEELWALL_SLIPPERY,
3645 static int ep_historic_solid[] =
3649 EL_EXPANDABLE_WALL_HORIZONTAL,
3650 EL_EXPANDABLE_WALL_VERTICAL,
3651 EL_EXPANDABLE_WALL_ANY,
3652 EL_BD_EXPANDABLE_WALL,
3665 EL_QUICKSAND_FILLING,
3666 EL_QUICKSAND_EMPTYING,
3668 EL_MAGIC_WALL_ACTIVE,
3669 EL_MAGIC_WALL_EMPTYING,
3670 EL_MAGIC_WALL_FILLING,
3674 EL_BD_MAGIC_WALL_ACTIVE,
3675 EL_BD_MAGIC_WALL_EMPTYING,
3676 EL_BD_MAGIC_WALL_FULL,
3677 EL_BD_MAGIC_WALL_FILLING,
3678 EL_BD_MAGIC_WALL_DEAD,
3687 EL_SP_TERMINAL_ACTIVE,
3691 EL_INVISIBLE_WALL_ACTIVE,
3692 EL_SWITCHGATE_SWITCH_UP,
3693 EL_SWITCHGATE_SWITCH_DOWN,
3695 EL_TIMEGATE_SWITCH_ACTIVE,
3707 // the following elements are a direct copy of "indestructible" elements,
3708 // except "EL_ACID", which is "indestructible", but not "solid"!
3713 EL_ACID_POOL_TOPLEFT,
3714 EL_ACID_POOL_TOPRIGHT,
3715 EL_ACID_POOL_BOTTOMLEFT,
3716 EL_ACID_POOL_BOTTOM,
3717 EL_ACID_POOL_BOTTOMRIGHT,
3718 EL_SP_HARDWARE_GRAY,
3719 EL_SP_HARDWARE_GREEN,
3720 EL_SP_HARDWARE_BLUE,
3722 EL_SP_HARDWARE_YELLOW,
3723 EL_SP_HARDWARE_BASE_1,
3724 EL_SP_HARDWARE_BASE_2,
3725 EL_SP_HARDWARE_BASE_3,
3726 EL_SP_HARDWARE_BASE_4,
3727 EL_SP_HARDWARE_BASE_5,
3728 EL_SP_HARDWARE_BASE_6,
3729 EL_INVISIBLE_STEELWALL,
3730 EL_INVISIBLE_STEELWALL_ACTIVE,
3731 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3732 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3733 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3734 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3735 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3736 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3737 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3738 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3739 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3740 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3741 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3742 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3744 EL_LIGHT_SWITCH_ACTIVE,
3745 EL_SIGN_EXCLAMATION,
3746 EL_SIGN_RADIOACTIVITY,
3753 EL_SIGN_ENTRY_FORBIDDEN,
3754 EL_SIGN_EMERGENCY_EXIT,
3762 EL_STEEL_EXIT_CLOSED,
3764 EL_STEEL_EXIT_OPENING,
3765 EL_STEEL_EXIT_CLOSING,
3766 EL_EM_STEEL_EXIT_CLOSED,
3767 EL_EM_STEEL_EXIT_OPEN,
3768 EL_EM_STEEL_EXIT_OPENING,
3769 EL_EM_STEEL_EXIT_CLOSING,
3770 EL_DC_STEELWALL_1_LEFT,
3771 EL_DC_STEELWALL_1_RIGHT,
3772 EL_DC_STEELWALL_1_TOP,
3773 EL_DC_STEELWALL_1_BOTTOM,
3774 EL_DC_STEELWALL_1_HORIZONTAL,
3775 EL_DC_STEELWALL_1_VERTICAL,
3776 EL_DC_STEELWALL_1_TOPLEFT,
3777 EL_DC_STEELWALL_1_TOPRIGHT,
3778 EL_DC_STEELWALL_1_BOTTOMLEFT,
3779 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3780 EL_DC_STEELWALL_1_TOPLEFT_2,
3781 EL_DC_STEELWALL_1_TOPRIGHT_2,
3782 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3783 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3784 EL_DC_STEELWALL_2_LEFT,
3785 EL_DC_STEELWALL_2_RIGHT,
3786 EL_DC_STEELWALL_2_TOP,
3787 EL_DC_STEELWALL_2_BOTTOM,
3788 EL_DC_STEELWALL_2_HORIZONTAL,
3789 EL_DC_STEELWALL_2_VERTICAL,
3790 EL_DC_STEELWALL_2_MIDDLE,
3791 EL_DC_STEELWALL_2_SINGLE,
3792 EL_STEELWALL_SLIPPERY,
3806 EL_GATE_1_GRAY_ACTIVE,
3807 EL_GATE_2_GRAY_ACTIVE,
3808 EL_GATE_3_GRAY_ACTIVE,
3809 EL_GATE_4_GRAY_ACTIVE,
3818 EL_EM_GATE_1_GRAY_ACTIVE,
3819 EL_EM_GATE_2_GRAY_ACTIVE,
3820 EL_EM_GATE_3_GRAY_ACTIVE,
3821 EL_EM_GATE_4_GRAY_ACTIVE,
3830 EL_EMC_GATE_5_GRAY_ACTIVE,
3831 EL_EMC_GATE_6_GRAY_ACTIVE,
3832 EL_EMC_GATE_7_GRAY_ACTIVE,
3833 EL_EMC_GATE_8_GRAY_ACTIVE,
3835 EL_DC_GATE_WHITE_GRAY,
3836 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3837 EL_DC_GATE_FAKE_GRAY,
3839 EL_SWITCHGATE_OPENING,
3840 EL_SWITCHGATE_CLOSED,
3841 EL_SWITCHGATE_CLOSING,
3842 EL_DC_SWITCHGATE_SWITCH_UP,
3843 EL_DC_SWITCHGATE_SWITCH_DOWN,
3845 EL_TIMEGATE_OPENING,
3847 EL_TIMEGATE_CLOSING,
3848 EL_DC_TIMEGATE_SWITCH,
3849 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3853 EL_TUBE_VERTICAL_LEFT,
3854 EL_TUBE_VERTICAL_RIGHT,
3855 EL_TUBE_HORIZONTAL_UP,
3856 EL_TUBE_HORIZONTAL_DOWN,
3861 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3862 EL_EXPANDABLE_STEELWALL_VERTICAL,
3863 EL_EXPANDABLE_STEELWALL_ANY,
3868 static int ep_classic_enemy[] =
3885 static int ep_belt[] =
3887 EL_CONVEYOR_BELT_1_LEFT,
3888 EL_CONVEYOR_BELT_1_MIDDLE,
3889 EL_CONVEYOR_BELT_1_RIGHT,
3890 EL_CONVEYOR_BELT_2_LEFT,
3891 EL_CONVEYOR_BELT_2_MIDDLE,
3892 EL_CONVEYOR_BELT_2_RIGHT,
3893 EL_CONVEYOR_BELT_3_LEFT,
3894 EL_CONVEYOR_BELT_3_MIDDLE,
3895 EL_CONVEYOR_BELT_3_RIGHT,
3896 EL_CONVEYOR_BELT_4_LEFT,
3897 EL_CONVEYOR_BELT_4_MIDDLE,
3898 EL_CONVEYOR_BELT_4_RIGHT,
3903 static int ep_belt_active[] =
3905 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3906 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3907 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3908 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3909 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3910 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3911 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3912 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3913 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3914 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3915 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3916 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3921 static int ep_belt_switch[] =
3923 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3924 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3925 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3926 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3927 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3928 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3929 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3930 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3931 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3932 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3933 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3934 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3939 static int ep_tube[] =
3946 EL_TUBE_HORIZONTAL_UP,
3947 EL_TUBE_HORIZONTAL_DOWN,
3949 EL_TUBE_VERTICAL_LEFT,
3950 EL_TUBE_VERTICAL_RIGHT,
3956 static int ep_acid_pool[] =
3958 EL_ACID_POOL_TOPLEFT,
3959 EL_ACID_POOL_TOPRIGHT,
3960 EL_ACID_POOL_BOTTOMLEFT,
3961 EL_ACID_POOL_BOTTOM,
3962 EL_ACID_POOL_BOTTOMRIGHT,
3967 static int ep_keygate[] =
3977 EL_GATE_1_GRAY_ACTIVE,
3978 EL_GATE_2_GRAY_ACTIVE,
3979 EL_GATE_3_GRAY_ACTIVE,
3980 EL_GATE_4_GRAY_ACTIVE,
3989 EL_EM_GATE_1_GRAY_ACTIVE,
3990 EL_EM_GATE_2_GRAY_ACTIVE,
3991 EL_EM_GATE_3_GRAY_ACTIVE,
3992 EL_EM_GATE_4_GRAY_ACTIVE,
4001 EL_EMC_GATE_5_GRAY_ACTIVE,
4002 EL_EMC_GATE_6_GRAY_ACTIVE,
4003 EL_EMC_GATE_7_GRAY_ACTIVE,
4004 EL_EMC_GATE_8_GRAY_ACTIVE,
4006 EL_DC_GATE_WHITE_GRAY,
4007 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4012 static int ep_amoeboid[] =
4024 static int ep_amoebalive[] =
4035 static int ep_has_editor_content[] =
4041 EL_SOKOBAN_FIELD_PLAYER,
4058 static int ep_can_turn_each_move[] =
4060 // !!! do something with this one !!!
4064 static int ep_can_grow[] =
4078 static int ep_active_bomb[] =
4081 EL_EM_DYNAMITE_ACTIVE,
4082 EL_DYNABOMB_PLAYER_1_ACTIVE,
4083 EL_DYNABOMB_PLAYER_2_ACTIVE,
4084 EL_DYNABOMB_PLAYER_3_ACTIVE,
4085 EL_DYNABOMB_PLAYER_4_ACTIVE,
4086 EL_SP_DISK_RED_ACTIVE,
4091 static int ep_inactive[] =
4101 EL_QUICKSAND_FAST_EMPTY,
4124 EL_GATE_1_GRAY_ACTIVE,
4125 EL_GATE_2_GRAY_ACTIVE,
4126 EL_GATE_3_GRAY_ACTIVE,
4127 EL_GATE_4_GRAY_ACTIVE,
4136 EL_EM_GATE_1_GRAY_ACTIVE,
4137 EL_EM_GATE_2_GRAY_ACTIVE,
4138 EL_EM_GATE_3_GRAY_ACTIVE,
4139 EL_EM_GATE_4_GRAY_ACTIVE,
4148 EL_EMC_GATE_5_GRAY_ACTIVE,
4149 EL_EMC_GATE_6_GRAY_ACTIVE,
4150 EL_EMC_GATE_7_GRAY_ACTIVE,
4151 EL_EMC_GATE_8_GRAY_ACTIVE,
4153 EL_DC_GATE_WHITE_GRAY,
4154 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4155 EL_DC_GATE_FAKE_GRAY,
4158 EL_INVISIBLE_STEELWALL,
4166 EL_WALL_EMERALD_YELLOW,
4167 EL_DYNABOMB_INCREASE_NUMBER,
4168 EL_DYNABOMB_INCREASE_SIZE,
4169 EL_DYNABOMB_INCREASE_POWER,
4173 EL_SOKOBAN_FIELD_EMPTY,
4174 EL_SOKOBAN_FIELD_FULL,
4175 EL_WALL_EMERALD_RED,
4176 EL_WALL_EMERALD_PURPLE,
4177 EL_ACID_POOL_TOPLEFT,
4178 EL_ACID_POOL_TOPRIGHT,
4179 EL_ACID_POOL_BOTTOMLEFT,
4180 EL_ACID_POOL_BOTTOM,
4181 EL_ACID_POOL_BOTTOMRIGHT,
4185 EL_BD_MAGIC_WALL_DEAD,
4187 EL_DC_MAGIC_WALL_DEAD,
4188 EL_AMOEBA_TO_DIAMOND,
4196 EL_SP_GRAVITY_PORT_RIGHT,
4197 EL_SP_GRAVITY_PORT_DOWN,
4198 EL_SP_GRAVITY_PORT_LEFT,
4199 EL_SP_GRAVITY_PORT_UP,
4200 EL_SP_PORT_HORIZONTAL,
4201 EL_SP_PORT_VERTICAL,
4212 EL_SP_HARDWARE_GRAY,
4213 EL_SP_HARDWARE_GREEN,
4214 EL_SP_HARDWARE_BLUE,
4216 EL_SP_HARDWARE_YELLOW,
4217 EL_SP_HARDWARE_BASE_1,
4218 EL_SP_HARDWARE_BASE_2,
4219 EL_SP_HARDWARE_BASE_3,
4220 EL_SP_HARDWARE_BASE_4,
4221 EL_SP_HARDWARE_BASE_5,
4222 EL_SP_HARDWARE_BASE_6,
4223 EL_SP_GRAVITY_ON_PORT_LEFT,
4224 EL_SP_GRAVITY_ON_PORT_RIGHT,
4225 EL_SP_GRAVITY_ON_PORT_UP,
4226 EL_SP_GRAVITY_ON_PORT_DOWN,
4227 EL_SP_GRAVITY_OFF_PORT_LEFT,
4228 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4229 EL_SP_GRAVITY_OFF_PORT_UP,
4230 EL_SP_GRAVITY_OFF_PORT_DOWN,
4231 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4232 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4233 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4234 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4235 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4236 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4237 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4238 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4239 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4240 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4241 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4242 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4243 EL_SIGN_EXCLAMATION,
4244 EL_SIGN_RADIOACTIVITY,
4251 EL_SIGN_ENTRY_FORBIDDEN,
4252 EL_SIGN_EMERGENCY_EXIT,
4260 EL_DC_STEELWALL_1_LEFT,
4261 EL_DC_STEELWALL_1_RIGHT,
4262 EL_DC_STEELWALL_1_TOP,
4263 EL_DC_STEELWALL_1_BOTTOM,
4264 EL_DC_STEELWALL_1_HORIZONTAL,
4265 EL_DC_STEELWALL_1_VERTICAL,
4266 EL_DC_STEELWALL_1_TOPLEFT,
4267 EL_DC_STEELWALL_1_TOPRIGHT,
4268 EL_DC_STEELWALL_1_BOTTOMLEFT,
4269 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4270 EL_DC_STEELWALL_1_TOPLEFT_2,
4271 EL_DC_STEELWALL_1_TOPRIGHT_2,
4272 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4273 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4274 EL_DC_STEELWALL_2_LEFT,
4275 EL_DC_STEELWALL_2_RIGHT,
4276 EL_DC_STEELWALL_2_TOP,
4277 EL_DC_STEELWALL_2_BOTTOM,
4278 EL_DC_STEELWALL_2_HORIZONTAL,
4279 EL_DC_STEELWALL_2_VERTICAL,
4280 EL_DC_STEELWALL_2_MIDDLE,
4281 EL_DC_STEELWALL_2_SINGLE,
4282 EL_STEELWALL_SLIPPERY,
4287 EL_EMC_WALL_SLIPPERY_1,
4288 EL_EMC_WALL_SLIPPERY_2,
4289 EL_EMC_WALL_SLIPPERY_3,
4290 EL_EMC_WALL_SLIPPERY_4,
4311 static int ep_em_slippery_wall[] =
4316 static int ep_gfx_crumbled[] =
4327 static int ep_editor_cascade_active[] =
4329 EL_INTERNAL_CASCADE_BD_ACTIVE,
4330 EL_INTERNAL_CASCADE_EM_ACTIVE,
4331 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4332 EL_INTERNAL_CASCADE_RND_ACTIVE,
4333 EL_INTERNAL_CASCADE_SB_ACTIVE,
4334 EL_INTERNAL_CASCADE_SP_ACTIVE,
4335 EL_INTERNAL_CASCADE_DC_ACTIVE,
4336 EL_INTERNAL_CASCADE_DX_ACTIVE,
4337 EL_INTERNAL_CASCADE_MM_ACTIVE,
4338 EL_INTERNAL_CASCADE_DF_ACTIVE,
4339 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4340 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4341 EL_INTERNAL_CASCADE_CE_ACTIVE,
4342 EL_INTERNAL_CASCADE_GE_ACTIVE,
4343 EL_INTERNAL_CASCADE_REF_ACTIVE,
4344 EL_INTERNAL_CASCADE_USER_ACTIVE,
4345 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4350 static int ep_editor_cascade_inactive[] =
4352 EL_INTERNAL_CASCADE_BD,
4353 EL_INTERNAL_CASCADE_EM,
4354 EL_INTERNAL_CASCADE_EMC,
4355 EL_INTERNAL_CASCADE_RND,
4356 EL_INTERNAL_CASCADE_SB,
4357 EL_INTERNAL_CASCADE_SP,
4358 EL_INTERNAL_CASCADE_DC,
4359 EL_INTERNAL_CASCADE_DX,
4360 EL_INTERNAL_CASCADE_MM,
4361 EL_INTERNAL_CASCADE_DF,
4362 EL_INTERNAL_CASCADE_CHARS,
4363 EL_INTERNAL_CASCADE_STEEL_CHARS,
4364 EL_INTERNAL_CASCADE_CE,
4365 EL_INTERNAL_CASCADE_GE,
4366 EL_INTERNAL_CASCADE_REF,
4367 EL_INTERNAL_CASCADE_USER,
4368 EL_INTERNAL_CASCADE_DYNAMIC,
4373 static int ep_obsolete[] =
4377 EL_EM_KEY_1_FILE_OBSOLETE,
4378 EL_EM_KEY_2_FILE_OBSOLETE,
4379 EL_EM_KEY_3_FILE_OBSOLETE,
4380 EL_EM_KEY_4_FILE_OBSOLETE,
4381 EL_ENVELOPE_OBSOLETE,
4390 } element_properties[] =
4392 { ep_diggable, EP_DIGGABLE },
4393 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4394 { ep_dont_run_into, EP_DONT_RUN_INTO },
4395 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4396 { ep_dont_touch, EP_DONT_TOUCH },
4397 { ep_indestructible, EP_INDESTRUCTIBLE },
4398 { ep_slippery, EP_SLIPPERY },
4399 { ep_can_change, EP_CAN_CHANGE },
4400 { ep_can_move, EP_CAN_MOVE },
4401 { ep_can_fall, EP_CAN_FALL },
4402 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4403 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4404 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4405 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4406 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4407 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4408 { ep_walkable_over, EP_WALKABLE_OVER },
4409 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4410 { ep_walkable_under, EP_WALKABLE_UNDER },
4411 { ep_passable_over, EP_PASSABLE_OVER },
4412 { ep_passable_inside, EP_PASSABLE_INSIDE },
4413 { ep_passable_under, EP_PASSABLE_UNDER },
4414 { ep_droppable, EP_DROPPABLE },
4415 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4416 { ep_pushable, EP_PUSHABLE },
4417 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4418 { ep_protected, EP_PROTECTED },
4419 { ep_throwable, EP_THROWABLE },
4420 { ep_can_explode, EP_CAN_EXPLODE },
4421 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4423 { ep_player, EP_PLAYER },
4424 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4425 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4426 { ep_switchable, EP_SWITCHABLE },
4427 { ep_bd_element, EP_BD_ELEMENT },
4428 { ep_sp_element, EP_SP_ELEMENT },
4429 { ep_sb_element, EP_SB_ELEMENT },
4431 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4432 { ep_food_penguin, EP_FOOD_PENGUIN },
4433 { ep_food_pig, EP_FOOD_PIG },
4434 { ep_historic_wall, EP_HISTORIC_WALL },
4435 { ep_historic_solid, EP_HISTORIC_SOLID },
4436 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4437 { ep_belt, EP_BELT },
4438 { ep_belt_active, EP_BELT_ACTIVE },
4439 { ep_belt_switch, EP_BELT_SWITCH },
4440 { ep_tube, EP_TUBE },
4441 { ep_acid_pool, EP_ACID_POOL },
4442 { ep_keygate, EP_KEYGATE },
4443 { ep_amoeboid, EP_AMOEBOID },
4444 { ep_amoebalive, EP_AMOEBALIVE },
4445 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4446 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4447 { ep_can_grow, EP_CAN_GROW },
4448 { ep_active_bomb, EP_ACTIVE_BOMB },
4449 { ep_inactive, EP_INACTIVE },
4451 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4453 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4455 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4456 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4458 { ep_obsolete, EP_OBSOLETE },
4465 // always start with reliable default values (element has no properties)
4466 // (but never initialize clipboard elements after the very first time)
4467 // (to be able to use clipboard elements between several levels)
4468 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4469 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4470 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4471 SET_PROPERTY(i, j, FALSE);
4473 // set all base element properties from above array definitions
4474 for (i = 0; element_properties[i].elements != NULL; i++)
4475 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4476 SET_PROPERTY((element_properties[i].elements)[j],
4477 element_properties[i].property, TRUE);
4479 // copy properties to some elements that are only stored in level file
4480 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4481 for (j = 0; copy_properties[j][0] != -1; j++)
4482 if (HAS_PROPERTY(copy_properties[j][0], i))
4483 for (k = 1; k <= 4; k++)
4484 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4486 // set static element properties that are not listed in array definitions
4487 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4488 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4490 clipboard_elements_initialized = TRUE;
4493 void InitElementPropertiesEngine(int engine_version)
4495 static int no_wall_properties[] =
4498 EP_COLLECTIBLE_ONLY,
4500 EP_DONT_COLLIDE_WITH,
4503 EP_CAN_SMASH_PLAYER,
4504 EP_CAN_SMASH_ENEMIES,
4505 EP_CAN_SMASH_EVERYTHING,
4510 EP_FOOD_DARK_YAMYAM,
4526 /* important: after initialization in InitElementPropertiesStatic(), the
4527 elements are not again initialized to a default value; therefore all
4528 changes have to make sure that they leave the element with a defined
4529 property (which means that conditional property changes must be set to
4530 a reliable default value before) */
4532 // resolve group elements
4533 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4534 ResolveGroupElement(EL_GROUP_START + i);
4536 // set all special, combined or engine dependent element properties
4537 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4539 // do not change (already initialized) clipboard elements here
4540 if (IS_CLIPBOARD_ELEMENT(i))
4543 // ---------- INACTIVE ----------------------------------------------------
4544 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4545 i <= EL_CHAR_END) ||
4546 (i >= EL_STEEL_CHAR_START &&
4547 i <= EL_STEEL_CHAR_END)));
4549 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4550 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4551 IS_WALKABLE_INSIDE(i) ||
4552 IS_WALKABLE_UNDER(i)));
4554 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4555 IS_PASSABLE_INSIDE(i) ||
4556 IS_PASSABLE_UNDER(i)));
4558 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4559 IS_PASSABLE_OVER(i)));
4561 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4562 IS_PASSABLE_INSIDE(i)));
4564 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4565 IS_PASSABLE_UNDER(i)));
4567 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4570 // ---------- COLLECTIBLE -------------------------------------------------
4571 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4575 // ---------- SNAPPABLE ---------------------------------------------------
4576 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4577 IS_COLLECTIBLE(i) ||
4581 // ---------- WALL --------------------------------------------------------
4582 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4584 for (j = 0; no_wall_properties[j] != -1; j++)
4585 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4586 i >= EL_FIRST_RUNTIME_UNREAL)
4587 SET_PROPERTY(i, EP_WALL, FALSE);
4589 if (IS_HISTORIC_WALL(i))
4590 SET_PROPERTY(i, EP_WALL, TRUE);
4592 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4593 if (engine_version < VERSION_IDENT(2,2,0,0))
4594 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4596 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4598 !IS_COLLECTIBLE(i)));
4600 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4601 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4602 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4604 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4607 // ---------- EXPLOSION_PROOF ---------------------------------------------
4609 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4610 else if (engine_version < VERSION_IDENT(2,2,0,0))
4611 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4613 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4617 if (IS_CUSTOM_ELEMENT(i))
4619 // these are additional properties which are initially false when set
4621 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4623 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4624 if (DONT_COLLIDE_WITH(i))
4625 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4627 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4628 if (CAN_SMASH_EVERYTHING(i))
4629 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4630 if (CAN_SMASH_ENEMIES(i))
4631 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4634 // ---------- CAN_SMASH ---------------------------------------------------
4635 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4636 CAN_SMASH_ENEMIES(i) ||
4637 CAN_SMASH_EVERYTHING(i)));
4639 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4640 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4641 EXPLODES_BY_FIRE(i)));
4643 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4644 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4645 EXPLODES_SMASHED(i)));
4647 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4648 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4649 EXPLODES_IMPACT(i)));
4651 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4652 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4654 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4655 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4656 i == EL_BLACK_ORB));
4658 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4659 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4661 IS_CUSTOM_ELEMENT(i)));
4663 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4664 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4665 i == EL_SP_ELECTRON));
4667 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4668 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4669 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4670 getMoveIntoAcidProperty(&level, i));
4672 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4673 if (MAYBE_DONT_COLLIDE_WITH(i))
4674 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4675 getDontCollideWithProperty(&level, i));
4677 // ---------- SP_PORT -----------------------------------------------------
4678 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4679 IS_PASSABLE_INSIDE(i)));
4681 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4682 for (j = 0; j < level.num_android_clone_elements; j++)
4683 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4685 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4687 // ---------- CAN_CHANGE --------------------------------------------------
4688 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4689 for (j = 0; j < element_info[i].num_change_pages; j++)
4690 if (element_info[i].change_page[j].can_change)
4691 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4693 // ---------- HAS_ACTION --------------------------------------------------
4694 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4695 for (j = 0; j < element_info[i].num_change_pages; j++)
4696 if (element_info[i].change_page[j].has_action)
4697 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4699 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4700 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4703 // ---------- GFX_CRUMBLED ------------------------------------------------
4704 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4705 element_info[i].crumbled[ACTION_DEFAULT] !=
4706 element_info[i].graphic[ACTION_DEFAULT]);
4708 // ---------- EDITOR_CASCADE ----------------------------------------------
4709 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4710 IS_EDITOR_CASCADE_INACTIVE(i)));
4713 // dynamically adjust element properties according to game engine version
4715 static int ep_em_slippery_wall[] =
4720 EL_EXPANDABLE_WALL_HORIZONTAL,
4721 EL_EXPANDABLE_WALL_VERTICAL,
4722 EL_EXPANDABLE_WALL_ANY,
4723 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4724 EL_EXPANDABLE_STEELWALL_VERTICAL,
4725 EL_EXPANDABLE_STEELWALL_ANY,
4726 EL_EXPANDABLE_STEELWALL_GROWING,
4730 static int ep_em_explodes_by_fire[] =
4733 EL_EM_DYNAMITE_ACTIVE,
4738 // special EM style gems behaviour
4739 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4740 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4741 level.em_slippery_gems);
4743 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4744 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4745 (level.em_slippery_gems &&
4746 engine_version > VERSION_IDENT(2,0,1,0)));
4748 // special EM style explosion behaviour regarding chain reactions
4749 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4750 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4751 level.em_explodes_by_fire);
4754 // this is needed because some graphics depend on element properties
4755 if (game_status == GAME_MODE_PLAYING)
4756 InitElementGraphicInfo();
4759 void InitElementPropertiesGfxElement(void)
4763 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4765 struct ElementInfo *ei = &element_info[i];
4767 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4771 static void InitGlobal(void)
4776 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4778 // check if element_name_info entry defined for each element in "main.h"
4779 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4780 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4782 element_info[i].token_name = element_name_info[i].token_name;
4783 element_info[i].class_name = element_name_info[i].class_name;
4784 element_info[i].editor_description= element_name_info[i].editor_description;
4787 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4789 // check if global_anim_name_info defined for each entry in "main.h"
4790 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4791 global_anim_name_info[i].token_name == NULL)
4792 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4794 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4797 // create hash from image config list
4798 image_config_hash = newSetupFileHash();
4799 for (i = 0; image_config[i].token != NULL; i++)
4800 setHashEntry(image_config_hash,
4801 image_config[i].token,
4802 image_config[i].value);
4804 // create hash from element token list
4805 element_token_hash = newSetupFileHash();
4806 for (i = 0; element_name_info[i].token_name != NULL; i++)
4807 setHashEntry(element_token_hash,
4808 element_name_info[i].token_name,
4811 // create hash from graphic token list
4812 graphic_token_hash = newSetupFileHash();
4813 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4814 if (strSuffix(image_config[i].value, ".png") ||
4815 strSuffix(image_config[i].value, ".pcx") ||
4816 strSuffix(image_config[i].value, ".wav") ||
4817 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4818 setHashEntry(graphic_token_hash,
4819 image_config[i].token,
4820 int2str(graphic++, 0));
4822 // create hash from font token list
4823 font_token_hash = newSetupFileHash();
4824 for (i = 0; font_info[i].token_name != NULL; i++)
4825 setHashEntry(font_token_hash,
4826 font_info[i].token_name,
4829 // set default filenames for all cloned graphics in static configuration
4830 for (i = 0; image_config[i].token != NULL; i++)
4832 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4834 char *token = image_config[i].token;
4835 char *token_clone_from = getStringCat2(token, ".clone_from");
4836 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4838 if (token_cloned != NULL)
4840 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4842 if (value_cloned != NULL)
4844 // set default filename in static configuration
4845 image_config[i].value = value_cloned;
4847 // set default filename in image config hash
4848 setHashEntry(image_config_hash, token, value_cloned);
4852 free(token_clone_from);
4856 // always start with reliable default values (all elements)
4857 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4858 ActiveElement[i] = i;
4860 // now add all entries that have an active state (active elements)
4861 for (i = 0; element_with_active_state[i].element != -1; i++)
4863 int element = element_with_active_state[i].element;
4864 int element_active = element_with_active_state[i].element_active;
4866 ActiveElement[element] = element_active;
4869 // always start with reliable default values (all buttons)
4870 for (i = 0; i < NUM_IMAGE_FILES; i++)
4871 ActiveButton[i] = i;
4873 // now add all entries that have an active state (active buttons)
4874 for (i = 0; button_with_active_state[i].button != -1; i++)
4876 int button = button_with_active_state[i].button;
4877 int button_active = button_with_active_state[i].button_active;
4879 ActiveButton[button] = button_active;
4882 // always start with reliable default values (all fonts)
4883 for (i = 0; i < NUM_FONTS; i++)
4886 // now add all entries that have an active state (active fonts)
4887 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4889 int font = font_with_active_state[i].font_nr;
4890 int font_active = font_with_active_state[i].font_nr_active;
4892 ActiveFont[font] = font_active;
4895 global.autoplay_leveldir = NULL;
4896 global.convert_leveldir = NULL;
4897 global.create_images_dir = NULL;
4899 global.frames_per_second = 0;
4900 global.show_frames_per_second = FALSE;
4902 global.border_status = GAME_MODE_LOADING;
4903 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4905 global.use_envelope_request = FALSE;
4908 static void Execute_Command(char *command)
4912 if (strEqual(command, "print graphicsinfo.conf"))
4914 Print("# You can configure additional/alternative image files here.\n");
4915 Print("# (The entries below are default and therefore commented out.)\n");
4917 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4919 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4922 for (i = 0; image_config[i].token != NULL; i++)
4923 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4924 image_config[i].value));
4928 else if (strEqual(command, "print soundsinfo.conf"))
4930 Print("# You can configure additional/alternative sound files here.\n");
4931 Print("# (The entries below are default and therefore commented out.)\n");
4933 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4935 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4938 for (i = 0; sound_config[i].token != NULL; i++)
4939 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4940 sound_config[i].value));
4944 else if (strEqual(command, "print musicinfo.conf"))
4946 Print("# You can configure additional/alternative music files here.\n");
4947 Print("# (The entries below are default and therefore commented out.)\n");
4949 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4951 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4954 for (i = 0; music_config[i].token != NULL; i++)
4955 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4956 music_config[i].value));
4960 else if (strEqual(command, "print editorsetup.conf"))
4962 Print("# You can configure your personal editor element list here.\n");
4963 Print("# (The entries below are default and therefore commented out.)\n");
4966 // this is needed to be able to check element list for cascade elements
4967 InitElementPropertiesStatic();
4968 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4970 PrintEditorElementList();
4974 else if (strEqual(command, "print helpanim.conf"))
4976 Print("# You can configure different element help animations here.\n");
4977 Print("# (The entries below are default and therefore commented out.)\n");
4980 for (i = 0; helpanim_config[i].token != NULL; i++)
4982 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4983 helpanim_config[i].value));
4985 if (strEqual(helpanim_config[i].token, "end"))
4991 else if (strEqual(command, "print helptext.conf"))
4993 Print("# You can configure different element help text here.\n");
4994 Print("# (The entries below are default and therefore commented out.)\n");
4997 for (i = 0; helptext_config[i].token != NULL; i++)
4998 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4999 helptext_config[i].value));
5003 else if (strPrefix(command, "dump level "))
5005 char *filename = &command[11];
5007 if (!fileExists(filename))
5008 Error(ERR_EXIT, "cannot open file '%s'", filename);
5010 LoadLevelFromFilename(&level, filename);
5015 else if (strPrefix(command, "dump tape "))
5017 char *filename = &command[10];
5019 if (!fileExists(filename))
5020 Error(ERR_EXIT, "cannot open file '%s'", filename);
5022 LoadTapeFromFilename(filename);
5027 else if (strPrefix(command, "autotest ") ||
5028 strPrefix(command, "autoplay ") ||
5029 strPrefix(command, "autoffwd ") ||
5030 strPrefix(command, "autowarp "))
5032 char *str_ptr = getStringCopy(&command[9]); // read command parameters
5034 global.autoplay_mode =
5035 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5036 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5037 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5038 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5039 AUTOPLAY_MODE_NONE);
5041 while (*str_ptr != '\0') // continue parsing string
5043 // cut leading whitespace from string, replace it by string terminator
5044 while (*str_ptr == ' ' || *str_ptr == '\t')
5047 if (*str_ptr == '\0') // end of string reached
5050 if (global.autoplay_leveldir == NULL) // read level set string
5052 global.autoplay_leveldir = str_ptr;
5053 global.autoplay_all = TRUE; // default: play all tapes
5055 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5056 global.autoplay_level[i] = FALSE;
5058 else // read level number string
5060 int level_nr = atoi(str_ptr); // get level_nr value
5062 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5063 global.autoplay_level[level_nr] = TRUE;
5065 global.autoplay_all = FALSE;
5068 // advance string pointer to the next whitespace (or end of string)
5069 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5073 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5074 program.headless = TRUE;
5076 else if (strPrefix(command, "convert "))
5078 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5079 char *str_ptr = strchr(str_copy, ' ');
5081 global.convert_leveldir = str_copy;
5082 global.convert_level_nr = -1;
5084 if (str_ptr != NULL) // level number follows
5086 *str_ptr++ = '\0'; // terminate leveldir string
5087 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5090 program.headless = TRUE;
5092 else if (strPrefix(command, "create images "))
5094 global.create_images_dir = getStringCopy(&command[14]);
5096 if (access(global.create_images_dir, W_OK) != 0)
5097 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5098 global.create_images_dir);
5100 else if (strPrefix(command, "create CE image "))
5102 CreateCustomElementImages(&command[16]);
5108 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5111 // disable networking if any valid command was recognized
5112 options.network = setup.network_mode = FALSE;
5115 static void InitSetup(void)
5117 LoadSetup(); // global setup info
5118 LoadSetup_AutoSetup(); // global auto setup info
5120 // set some options from setup file
5122 if (setup.options.verbose)
5123 options.verbose = TRUE;
5125 if (setup.debug.show_frames_per_second)
5126 global.show_frames_per_second = TRUE;
5129 static void InitGameInfo(void)
5131 game.restart_level = FALSE;
5132 game.restart_game_message = NULL;
5133 game.request_active = FALSE;
5136 static void InitPlayerInfo(void)
5140 // choose default local player
5141 local_player = &stored_player[0];
5143 for (i = 0; i < MAX_PLAYERS; i++)
5145 stored_player[i].connected_locally = FALSE;
5146 stored_player[i].connected_network = FALSE;
5149 local_player->connected_locally = TRUE;
5152 static void InitArtworkInfo(void)
5157 static char *get_string_in_brackets(char *string)
5159 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5161 sprintf(string_in_brackets, "[%s]", string);
5163 return string_in_brackets;
5166 static char *get_level_id_suffix(int id_nr)
5168 char *id_suffix = checked_malloc(1 + 3 + 1);
5170 if (id_nr < 0 || id_nr > 999)
5173 sprintf(id_suffix, ".%03d", id_nr);
5178 static void InitArtworkConfig(void)
5180 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5182 NUM_GLOBAL_ANIM_TOKENS + 1];
5183 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5184 NUM_GLOBAL_ANIM_TOKENS + 1];
5185 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5186 NUM_GLOBAL_ANIM_TOKENS + 1];
5187 static char *action_id_suffix[NUM_ACTIONS + 1];
5188 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5189 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5190 static char *level_id_suffix[MAX_LEVELS + 1];
5191 static char *dummy[1] = { NULL };
5192 static char *ignore_generic_tokens[] =
5197 "program_copyright",
5202 static char **ignore_image_tokens;
5203 static char **ignore_sound_tokens;
5204 static char **ignore_music_tokens;
5205 int num_ignore_generic_tokens;
5206 int num_ignore_image_tokens;
5207 int num_ignore_sound_tokens;
5208 int num_ignore_music_tokens;
5211 // dynamically determine list of generic tokens to be ignored
5212 num_ignore_generic_tokens = 0;
5213 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5214 num_ignore_generic_tokens++;
5216 // dynamically determine list of image tokens to be ignored
5217 num_ignore_image_tokens = num_ignore_generic_tokens;
5218 for (i = 0; image_config_vars[i].token != NULL; i++)
5219 num_ignore_image_tokens++;
5220 ignore_image_tokens =
5221 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5222 for (i = 0; i < num_ignore_generic_tokens; i++)
5223 ignore_image_tokens[i] = ignore_generic_tokens[i];
5224 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5225 ignore_image_tokens[num_ignore_generic_tokens + i] =
5226 image_config_vars[i].token;
5227 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5229 // dynamically determine list of sound tokens to be ignored
5230 num_ignore_sound_tokens = num_ignore_generic_tokens;
5231 ignore_sound_tokens =
5232 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5233 for (i = 0; i < num_ignore_generic_tokens; i++)
5234 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5235 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5237 // dynamically determine list of music tokens to be ignored
5238 num_ignore_music_tokens = num_ignore_generic_tokens;
5239 ignore_music_tokens =
5240 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5241 for (i = 0; i < num_ignore_generic_tokens; i++)
5242 ignore_music_tokens[i] = ignore_generic_tokens[i];
5243 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5245 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5246 image_id_prefix[i] = element_info[i].token_name;
5247 for (i = 0; i < NUM_FONTS; i++)
5248 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5249 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5250 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5251 global_anim_info[i].token_name;
5252 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5254 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5255 sound_id_prefix[i] = element_info[i].token_name;
5256 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5257 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5258 get_string_in_brackets(element_info[i].class_name);
5259 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5260 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5261 global_anim_info[i].token_name;
5262 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5264 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5265 music_id_prefix[i] = music_prefix_info[i].prefix;
5266 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5267 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5268 global_anim_info[i].token_name;
5269 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5271 for (i = 0; i < NUM_ACTIONS; i++)
5272 action_id_suffix[i] = element_action_info[i].suffix;
5273 action_id_suffix[NUM_ACTIONS] = NULL;
5275 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5276 direction_id_suffix[i] = element_direction_info[i].suffix;
5277 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5279 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5280 special_id_suffix[i] = special_suffix_info[i].suffix;
5281 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5283 for (i = 0; i < MAX_LEVELS; i++)
5284 level_id_suffix[i] = get_level_id_suffix(i);
5285 level_id_suffix[MAX_LEVELS] = NULL;
5287 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5288 image_id_prefix, action_id_suffix, direction_id_suffix,
5289 special_id_suffix, ignore_image_tokens);
5290 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5291 sound_id_prefix, action_id_suffix, dummy,
5292 special_id_suffix, ignore_sound_tokens);
5293 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5294 music_id_prefix, action_id_suffix, special_id_suffix,
5295 level_id_suffix, ignore_music_tokens);
5298 static void InitMixer(void)
5305 static void InitVideoOverlay(void)
5307 // if virtual buttons are not loaded from setup file, repeat initializing
5308 // virtual buttons grid with default values now that video is initialized
5309 if (!setup.touch.grid_initialized)
5312 InitTileCursorInfo();
5316 void InitGfxBuffers(void)
5318 static int win_xsize_last = -1;
5319 static int win_ysize_last = -1;
5321 // create additional image buffers for double-buffering and cross-fading
5323 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5325 // used to temporarily store the backbuffer -- only re-create if changed
5326 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5327 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5329 win_xsize_last = WIN_XSIZE;
5330 win_ysize_last = WIN_YSIZE;
5333 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5334 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5335 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5336 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5338 // initialize screen properties
5339 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5340 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5342 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5343 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5344 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5345 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5346 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5347 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5349 // required if door size definitions have changed
5350 InitGraphicCompatibilityInfo_Doors();
5352 InitGfxBuffers_EM();
5353 InitGfxBuffers_SP();
5356 static void InitGfx(void)
5358 struct GraphicInfo *graphic_info_last = graphic_info;
5359 char *filename_font_initial = NULL;
5360 char *filename_anim_initial = NULL;
5361 Bitmap *bitmap_font_initial = NULL;
5364 // determine settings for initial font (for displaying startup messages)
5365 for (i = 0; image_config[i].token != NULL; i++)
5367 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5369 char font_token[128];
5372 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5373 len_font_token = strlen(font_token);
5375 if (strEqual(image_config[i].token, font_token))
5376 filename_font_initial = image_config[i].value;
5377 else if (strlen(image_config[i].token) > len_font_token &&
5378 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5380 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5381 font_initial[j].src_x = atoi(image_config[i].value);
5382 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5383 font_initial[j].src_y = atoi(image_config[i].value);
5384 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5385 font_initial[j].width = atoi(image_config[i].value);
5386 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5387 font_initial[j].height = atoi(image_config[i].value);
5392 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5394 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5395 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5398 if (filename_font_initial == NULL) // should not happen
5399 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5402 InitGfxCustomArtworkInfo();
5403 InitGfxOtherSettings();
5405 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5407 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5408 font_initial[j].bitmap = bitmap_font_initial;
5410 InitFontGraphicInfo();
5414 DrawInitText("Loading graphics", 120, FC_GREEN);
5416 // initialize settings for busy animation with default values
5417 int parameter[NUM_GFX_ARGS];
5418 for (i = 0; i < NUM_GFX_ARGS; i++)
5419 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5420 image_config_suffix[i].token,
5421 image_config_suffix[i].type);
5423 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5424 int len_anim_token = strlen(anim_token);
5426 // read settings for busy animation from default custom artwork config
5427 char *gfx_config_filename = getPath3(options.graphics_directory,
5429 GRAPHICSINFO_FILENAME);
5431 if (fileExists(gfx_config_filename))
5433 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5435 if (setup_file_hash)
5437 char *filename = getHashEntry(setup_file_hash, anim_token);
5441 filename_anim_initial = getStringCopy(filename);
5443 for (j = 0; image_config_suffix[j].token != NULL; j++)
5445 int type = image_config_suffix[j].type;
5446 char *suffix = image_config_suffix[j].token;
5447 char *token = getStringCat2(anim_token, suffix);
5448 char *value = getHashEntry(setup_file_hash, token);
5450 checked_free(token);
5453 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5457 freeSetupFileHash(setup_file_hash);
5461 if (filename_anim_initial == NULL)
5463 // read settings for busy animation from static default artwork config
5464 for (i = 0; image_config[i].token != NULL; i++)
5466 if (strEqual(image_config[i].token, anim_token))
5467 filename_anim_initial = getStringCopy(image_config[i].value);
5468 else if (strlen(image_config[i].token) > len_anim_token &&
5469 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5471 for (j = 0; image_config_suffix[j].token != NULL; j++)
5473 if (strEqual(&image_config[i].token[len_anim_token],
5474 image_config_suffix[j].token))
5476 get_graphic_parameter_value(image_config[i].value,
5477 image_config_suffix[j].token,
5478 image_config_suffix[j].type);
5484 if (filename_anim_initial == NULL) // should not happen
5485 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5487 anim_initial.bitmaps =
5488 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5490 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5491 LoadCustomImage(filename_anim_initial);
5493 checked_free(filename_anim_initial);
5495 graphic_info = &anim_initial; // graphic == 0 => anim_initial
5497 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5499 graphic_info = graphic_info_last;
5501 init.busy.width = anim_initial.width;
5502 init.busy.height = anim_initial.height;
5504 InitMenuDesignSettings_Static();
5506 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5507 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5508 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5509 InitGfxDrawTileCursorFunction(DrawTileCursor);
5511 gfx.fade_border_source_status = global.border_status;
5512 gfx.fade_border_target_status = global.border_status;
5513 gfx.masked_border_bitmap_ptr = backbuffer;
5515 // use copy of busy animation to prevent change while reloading artwork
5519 static void InitGfxBackground(void)
5521 fieldbuffer = bitmap_db_field;
5522 SetDrawtoField(DRAW_TO_BACKBUFFER);
5524 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5526 redraw_mask = REDRAW_ALL;
5529 static void InitLevelInfo(void)
5531 LoadLevelInfo(); // global level info
5532 LoadLevelSetup_LastSeries(); // last played series info
5533 LoadLevelSetup_SeriesInfo(); // last played level info
5535 if (global.autoplay_leveldir &&
5536 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5538 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5539 global.autoplay_leveldir);
5540 if (leveldir_current == NULL)
5541 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5544 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5547 static void InitLevelArtworkInfo(void)
5549 LoadLevelArtworkInfo();
5552 static void InitImages(void)
5554 print_timestamp_init("InitImages");
5557 printf("::: leveldir_current->identifier == '%s'\n",
5558 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5559 printf("::: leveldir_current->graphics_path == '%s'\n",
5560 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5561 printf("::: leveldir_current->graphics_set == '%s'\n",
5562 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5563 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5564 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5567 setLevelArtworkDir(artwork.gfx_first);
5570 printf("::: leveldir_current->identifier == '%s'\n",
5571 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5572 printf("::: leveldir_current->graphics_path == '%s'\n",
5573 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5574 printf("::: leveldir_current->graphics_set == '%s'\n",
5575 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5576 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5577 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5581 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5582 leveldir_current->identifier,
5583 artwork.gfx_current_identifier,
5584 artwork.gfx_current->identifier,
5585 leveldir_current->graphics_set,
5586 leveldir_current->graphics_path);
5589 UPDATE_BUSY_STATE();
5591 ReloadCustomImages();
5592 print_timestamp_time("ReloadCustomImages");
5594 UPDATE_BUSY_STATE();
5596 LoadCustomElementDescriptions();
5597 print_timestamp_time("LoadCustomElementDescriptions");
5599 UPDATE_BUSY_STATE();
5601 LoadMenuDesignSettings();
5602 print_timestamp_time("LoadMenuDesignSettings");
5604 UPDATE_BUSY_STATE();
5606 ReinitializeGraphics();
5607 print_timestamp_time("ReinitializeGraphics");
5609 LoadMenuDesignSettings_AfterGraphics();
5610 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5612 UPDATE_BUSY_STATE();
5614 print_timestamp_done("InitImages");
5617 static void InitSound(char *identifier)
5619 print_timestamp_init("InitSound");
5621 if (identifier == NULL)
5622 identifier = artwork.snd_current->identifier;
5624 // set artwork path to send it to the sound server process
5625 setLevelArtworkDir(artwork.snd_first);
5627 InitReloadCustomSounds(identifier);
5628 print_timestamp_time("InitReloadCustomSounds");
5630 ReinitializeSounds();
5631 print_timestamp_time("ReinitializeSounds");
5633 print_timestamp_done("InitSound");
5636 static void InitMusic(char *identifier)
5638 print_timestamp_init("InitMusic");
5640 if (identifier == NULL)
5641 identifier = artwork.mus_current->identifier;
5643 // set artwork path to send it to the sound server process
5644 setLevelArtworkDir(artwork.mus_first);
5646 InitReloadCustomMusic(identifier);
5647 print_timestamp_time("InitReloadCustomMusic");
5649 ReinitializeMusic();
5650 print_timestamp_time("ReinitializeMusic");
5652 print_timestamp_done("InitMusic");
5655 static void InitArtworkDone(void)
5657 if (program.headless)
5660 InitGlobalAnimations();
5663 static void InitNetworkSettings(void)
5665 boolean network_enabled = (options.network || setup.network_mode);
5666 char *network_server = (options.server_host != NULL ? options.server_host :
5667 setup.network_server_hostname);
5669 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5670 network_server = NULL;
5672 InitNetworkInfo(network_enabled,
5676 options.server_port);
5679 void InitNetworkServer(void)
5681 if (!network.enabled || network.connected)
5684 LimitScreenUpdates(FALSE);
5686 if (game_status == GAME_MODE_LOADING)
5689 if (!ConnectToServer(network.server_host, network.server_port))
5691 network.enabled = FALSE;
5693 setup.network_mode = FALSE;
5697 SendToServer_ProtocolVersion();
5698 SendToServer_PlayerName(setup.player_name);
5699 SendToServer_NrWanted(setup.network_player_nr + 1);
5701 network.connected = TRUE;
5704 // short time to recognize result of network initialization
5705 if (game_status == GAME_MODE_LOADING)
5706 Delay_WithScreenUpdates(1000);
5709 static boolean CheckArtworkConfigForCustomElements(char *filename)
5711 SetupFileHash *setup_file_hash;
5712 boolean redefined_ce_found = FALSE;
5714 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5716 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5718 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5720 char *token = HASH_ITERATION_TOKEN(itr);
5722 if (strPrefix(token, "custom_"))
5724 redefined_ce_found = TRUE;
5729 END_HASH_ITERATION(setup_file_hash, itr)
5731 freeSetupFileHash(setup_file_hash);
5734 return redefined_ce_found;
5737 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5739 char *filename_base, *filename_local;
5740 boolean redefined_ce_found = FALSE;
5742 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5745 printf("::: leveldir_current->identifier == '%s'\n",
5746 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5747 printf("::: leveldir_current->graphics_path == '%s'\n",
5748 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5749 printf("::: leveldir_current->graphics_set == '%s'\n",
5750 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5751 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5752 leveldir_current == NULL ? "[NULL]" :
5753 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5756 // first look for special artwork configured in level series config
5757 filename_base = getCustomArtworkLevelConfigFilename(type);
5760 printf("::: filename_base == '%s'\n", filename_base);
5763 if (fileExists(filename_base))
5764 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5766 filename_local = getCustomArtworkConfigFilename(type);
5769 printf("::: filename_local == '%s'\n", filename_local);
5772 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5773 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5776 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5779 return redefined_ce_found;
5782 static void InitOverrideArtwork(void)
5784 boolean redefined_ce_found = FALSE;
5786 // to check if this level set redefines any CEs, do not use overriding
5787 gfx.override_level_graphics = FALSE;
5788 gfx.override_level_sounds = FALSE;
5789 gfx.override_level_music = FALSE;
5791 // now check if this level set has definitions for custom elements
5792 if (setup.override_level_graphics == AUTO ||
5793 setup.override_level_sounds == AUTO ||
5794 setup.override_level_music == AUTO)
5795 redefined_ce_found =
5796 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5797 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5798 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5801 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5804 if (redefined_ce_found)
5806 // this level set has CE definitions: change "AUTO" to "FALSE"
5807 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5808 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5809 gfx.override_level_music = (setup.override_level_music == TRUE);
5813 // this level set has no CE definitions: change "AUTO" to "TRUE"
5814 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5815 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5816 gfx.override_level_music = (setup.override_level_music != FALSE);
5820 printf("::: => %d, %d, %d\n",
5821 gfx.override_level_graphics,
5822 gfx.override_level_sounds,
5823 gfx.override_level_music);
5827 static char *getNewArtworkIdentifier(int type)
5829 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5830 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5831 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5832 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5833 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5834 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5835 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5836 char *leveldir_identifier = leveldir_current->identifier;
5837 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
5838 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5839 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5840 char *artwork_current_identifier;
5841 char *artwork_new_identifier = NULL; // default: nothing has changed
5843 // leveldir_current may be invalid (level group, parent link)
5844 if (!validLevelSeries(leveldir_current))
5847 /* 1st step: determine artwork set to be activated in descending order:
5848 --------------------------------------------------------------------
5849 1. setup artwork (when configured to override everything else)
5850 2. artwork set configured in "levelinfo.conf" of current level set
5851 (artwork in level directory will have priority when loading later)
5852 3. artwork in level directory (stored in artwork sub-directory)
5853 4. setup artwork (currently configured in setup menu) */
5855 if (setup_override_artwork)
5856 artwork_current_identifier = setup_artwork_set;
5857 else if (leveldir_artwork_set != NULL)
5858 artwork_current_identifier = leveldir_artwork_set;
5859 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5860 artwork_current_identifier = leveldir_identifier;
5862 artwork_current_identifier = setup_artwork_set;
5865 /* 2nd step: check if it is really needed to reload artwork set
5866 ------------------------------------------------------------ */
5868 // ---------- reload if level set and also artwork set has changed ----------
5869 if (leveldir_current_identifier[type] != leveldir_identifier &&
5870 (last_has_level_artwork_set[type] || has_level_artwork_set))
5871 artwork_new_identifier = artwork_current_identifier;
5873 leveldir_current_identifier[type] = leveldir_identifier;
5874 last_has_level_artwork_set[type] = has_level_artwork_set;
5876 // ---------- reload if "override artwork" setting has changed --------------
5877 if (last_override_level_artwork[type] != setup_override_artwork)
5878 artwork_new_identifier = artwork_current_identifier;
5880 last_override_level_artwork[type] = setup_override_artwork;
5882 // ---------- reload if current artwork identifier has changed --------------
5883 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5884 artwork_current_identifier))
5885 artwork_new_identifier = artwork_current_identifier;
5887 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5889 // ---------- do not reload directly after starting -------------------------
5890 if (!initialized[type])
5891 artwork_new_identifier = NULL;
5893 initialized[type] = TRUE;
5895 return artwork_new_identifier;
5898 void ReloadCustomArtwork(int force_reload)
5900 int last_game_status = game_status; // save current game status
5901 char *gfx_new_identifier;
5902 char *snd_new_identifier;
5903 char *mus_new_identifier;
5904 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5905 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5906 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5907 boolean reload_needed;
5909 InitOverrideArtwork();
5911 force_reload_gfx |= AdjustGraphicsForEMC();
5913 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5914 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5915 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5917 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5918 snd_new_identifier != NULL || force_reload_snd ||
5919 mus_new_identifier != NULL || force_reload_mus);
5924 print_timestamp_init("ReloadCustomArtwork");
5926 SetGameStatus(GAME_MODE_LOADING);
5928 FadeOut(REDRAW_ALL);
5930 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5931 print_timestamp_time("ClearRectangle");
5935 if (gfx_new_identifier != NULL || force_reload_gfx)
5938 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5939 artwork.gfx_current_identifier,
5941 artwork.gfx_current->identifier,
5942 leveldir_current->graphics_set);
5946 print_timestamp_time("InitImages");
5949 if (snd_new_identifier != NULL || force_reload_snd)
5951 InitSound(snd_new_identifier);
5952 print_timestamp_time("InitSound");
5955 if (mus_new_identifier != NULL || force_reload_mus)
5957 InitMusic(mus_new_identifier);
5958 print_timestamp_time("InitMusic");
5963 SetGameStatus(last_game_status); // restore current game status
5965 init_last = init; // switch to new busy animation
5967 FadeOut(REDRAW_ALL);
5969 RedrawGlobalBorder();
5971 // force redraw of (open or closed) door graphics
5972 SetDoorState(DOOR_OPEN_ALL);
5973 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5975 FadeSetEnterScreen();
5976 FadeSkipNextFadeOut();
5978 print_timestamp_done("ReloadCustomArtwork");
5980 LimitScreenUpdates(FALSE);
5983 void KeyboardAutoRepeatOffUnlessAutoplay(void)
5985 if (global.autoplay_leveldir == NULL)
5986 KeyboardAutoRepeatOff();
5989 void DisplayExitMessage(char *format, va_list ap)
5991 // also check for initialized video (headless flag may be temporarily unset)
5992 if (program.headless || !video.initialized)
5995 // check if draw buffer and fonts for exit message are already available
5996 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5999 int font_1 = FC_RED;
6000 int font_2 = FC_YELLOW;
6001 int font_3 = FC_BLUE;
6002 int font_width = getFontWidth(font_2);
6003 int font_height = getFontHeight(font_2);
6006 int sxsize = WIN_XSIZE - 2 * sx;
6007 int sysize = WIN_YSIZE - 2 * sy;
6008 int line_length = sxsize / font_width;
6009 int max_lines = sysize / font_height;
6010 int num_lines_printed;
6014 gfx.sxsize = sxsize;
6015 gfx.sysize = sysize;
6019 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6021 DrawTextSCentered(sy, font_1, "Fatal error:");
6022 sy += 3 * font_height;;
6025 DrawTextBufferVA(sx, sy, format, ap, font_2,
6026 line_length, line_length, max_lines,
6027 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6028 sy += (num_lines_printed + 3) * font_height;
6030 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6031 sy += 3 * font_height;
6034 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6035 line_length, line_length, max_lines,
6036 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6038 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6040 redraw_mask = REDRAW_ALL;
6042 // force drawing exit message even if screen updates are currently limited
6043 LimitScreenUpdates(FALSE);
6047 // deactivate toons on error message screen
6048 setup.toons = FALSE;
6050 WaitForEventToContinue();
6054 // ============================================================================
6056 // ============================================================================
6060 print_timestamp_init("OpenAll");
6062 SetGameStatus(GAME_MODE_LOADING);
6066 InitGlobal(); // initialize some global variables
6068 print_timestamp_time("[init global stuff]");
6072 print_timestamp_time("[init setup/config stuff (1)]");
6076 if (options.execute_command)
6077 Execute_Command(options.execute_command);
6079 InitNetworkSettings();
6083 if (network.serveronly)
6085 #if defined(PLATFORM_UNIX)
6086 NetworkServer(network.server_port, TRUE);
6088 Error(ERR_WARN, "networking only supported in Unix version");
6091 exit(0); // never reached, server loops forever
6095 print_timestamp_time("[init setup/config stuff (2)]");
6097 print_timestamp_time("[init setup/config stuff (3)]");
6098 InitArtworkInfo(); // needed before loading gfx, sound & music
6099 print_timestamp_time("[init setup/config stuff (4)]");
6100 InitArtworkConfig(); // needed before forking sound child process
6101 print_timestamp_time("[init setup/config stuff (5)]");
6103 print_timestamp_time("[init setup/config stuff (6)]");
6105 InitRND(NEW_RANDOMIZE);
6106 InitSimpleRandom(NEW_RANDOMIZE);
6110 print_timestamp_time("[init setup/config stuff]");
6112 InitVideoDefaults();
6114 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6117 InitEventFilter(FilterMouseMotionEvents);
6119 print_timestamp_time("[init video stuff]");
6121 InitElementPropertiesStatic();
6122 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6123 InitElementPropertiesGfxElement();
6125 print_timestamp_time("[init element properties stuff]");
6129 print_timestamp_time("InitGfx");
6132 print_timestamp_time("InitLevelInfo");
6134 InitLevelArtworkInfo();
6135 print_timestamp_time("InitLevelArtworkInfo");
6137 InitOverrideArtwork(); // needs to know current level directory
6138 print_timestamp_time("InitOverrideArtwork");
6140 InitImages(); // needs to know current level directory
6141 print_timestamp_time("InitImages");
6143 InitSound(NULL); // needs to know current level directory
6144 print_timestamp_time("InitSound");
6146 InitMusic(NULL); // needs to know current level directory
6147 print_timestamp_time("InitMusic");
6151 InitGfxBackground();
6157 if (global.autoplay_leveldir)
6162 else if (global.convert_leveldir)
6167 else if (global.create_images_dir)
6169 CreateLevelSketchImages();
6173 InitNetworkServer();
6175 SetGameStatus(GAME_MODE_MAIN);
6177 FadeSetEnterScreen();
6178 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6179 FadeSkipNextFadeOut();
6181 print_timestamp_time("[post-artwork]");
6183 print_timestamp_done("OpenAll");
6188 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6190 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6191 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6192 #if defined(PLATFORM_ANDROID)
6193 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6194 SDL_AndroidGetInternalStoragePath());
6195 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6196 SDL_AndroidGetExternalStoragePath());
6197 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6198 (SDL_AndroidGetExternalStorageState() &
6199 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6200 SDL_AndroidGetExternalStorageState() &
6201 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6206 void CloseAllAndExit(int exit_value)
6211 CloseAudio(); // called after freeing sounds (needed for SDL)
6219 // set a flag to tell the network server thread to quit and wait for it
6220 // using SDL_WaitThread()
6222 // Code used with SDL 1.2:
6223 // if (network_server) // terminate network server
6224 // SDL_KillThread(server_thread);
6226 CloseVideoDisplay();
6227 ClosePlatformDependentStuff();
6229 if (exit_value != 0 && !options.execute_command)
6231 // fall back to default level set (current set may have caused an error)
6232 SaveLevelSetup_LastSeries_Deactivate();
6234 // tell user where to find error log file which may contain more details
6235 // (error notification now directly displayed on screen inside R'n'D
6236 // NotifyUserAboutErrorFile(); // currently only works for Windows