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 == 0) // 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 == 0) // 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 // this is only used for drawing font characters
1556 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1557 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1559 // use a different default value for global animations and toons
1560 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1561 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1562 g->draw_masked = TRUE;
1564 // this is used for drawing envelopes, global animations and toons
1565 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1566 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1568 // used for toon animations and global animations
1569 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1570 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1572 // optional graphic for cloning all graphics settings
1573 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1574 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1576 // optional settings for drawing title screens and title messages
1577 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1578 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1579 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1580 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1581 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1582 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1583 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1584 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1585 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1586 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1587 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1588 g->align = parameter[GFX_ARG_ALIGN];
1589 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1590 g->valign = parameter[GFX_ARG_VALIGN];
1591 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1592 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1594 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1595 g->class = parameter[GFX_ARG_CLASS];
1596 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1597 g->style = parameter[GFX_ARG_STYLE];
1599 // this is only used for drawing menu buttons and text
1600 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1601 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1602 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1603 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1606 static void set_graphic_parameters(int graphic)
1608 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1609 char **parameter_raw = image->parameter;
1610 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1611 int parameter[NUM_GFX_ARGS];
1614 // if fallback to default artwork is done, also use the default parameters
1615 if (image->fallback_to_default)
1616 parameter_raw = image->default_parameter;
1618 // get integer values from string parameters
1619 for (i = 0; i < NUM_GFX_ARGS; i++)
1620 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1621 image_config_suffix[i].token,
1622 image_config_suffix[i].type);
1624 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1626 UPDATE_BUSY_STATE();
1629 static void set_cloned_graphic_parameters(int graphic)
1631 int fallback_graphic = IMG_CHAR_EXCLAM;
1632 int max_num_images = getImageListSize();
1633 int clone_graphic = graphic_info[graphic].clone_from;
1634 int num_references_followed = 1;
1636 while (graphic_info[clone_graphic].clone_from != -1 &&
1637 num_references_followed < max_num_images)
1639 clone_graphic = graphic_info[clone_graphic].clone_from;
1641 num_references_followed++;
1644 if (num_references_followed >= max_num_images)
1646 Error(ERR_INFO_LINE, "-");
1647 Error(ERR_INFO, "warning: error found in config file:");
1648 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1649 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1650 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1651 Error(ERR_INFO, "custom graphic rejected for this element/action");
1653 if (graphic == fallback_graphic)
1654 Error(ERR_EXIT, "no fallback graphic available");
1656 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1657 Error(ERR_INFO_LINE, "-");
1659 graphic_info[graphic] = graphic_info[fallback_graphic];
1663 graphic_info[graphic] = graphic_info[clone_graphic];
1664 graphic_info[graphic].clone_from = clone_graphic;
1668 static void InitGraphicInfo(void)
1670 int fallback_graphic = IMG_CHAR_EXCLAM;
1671 int num_images = getImageListSize();
1674 // use image size as default values for width and height for these images
1675 static int full_size_graphics[] =
1678 IMG_GLOBAL_BORDER_MAIN,
1679 IMG_GLOBAL_BORDER_SCORES,
1680 IMG_GLOBAL_BORDER_EDITOR,
1681 IMG_GLOBAL_BORDER_PLAYING,
1684 IMG_BACKGROUND_ENVELOPE_1,
1685 IMG_BACKGROUND_ENVELOPE_2,
1686 IMG_BACKGROUND_ENVELOPE_3,
1687 IMG_BACKGROUND_ENVELOPE_4,
1688 IMG_BACKGROUND_REQUEST,
1691 IMG_BACKGROUND_TITLE_INITIAL,
1692 IMG_BACKGROUND_TITLE,
1693 IMG_BACKGROUND_MAIN,
1694 IMG_BACKGROUND_LEVELS,
1695 IMG_BACKGROUND_LEVELNR,
1696 IMG_BACKGROUND_SCORES,
1697 IMG_BACKGROUND_EDITOR,
1698 IMG_BACKGROUND_INFO,
1699 IMG_BACKGROUND_INFO_ELEMENTS,
1700 IMG_BACKGROUND_INFO_MUSIC,
1701 IMG_BACKGROUND_INFO_CREDITS,
1702 IMG_BACKGROUND_INFO_PROGRAM,
1703 IMG_BACKGROUND_INFO_VERSION,
1704 IMG_BACKGROUND_INFO_LEVELSET,
1705 IMG_BACKGROUND_SETUP,
1706 IMG_BACKGROUND_PLAYING,
1707 IMG_BACKGROUND_DOOR,
1708 IMG_BACKGROUND_TAPE,
1709 IMG_BACKGROUND_PANEL,
1710 IMG_BACKGROUND_PALETTE,
1711 IMG_BACKGROUND_TOOLBOX,
1713 IMG_TITLESCREEN_INITIAL_1,
1714 IMG_TITLESCREEN_INITIAL_2,
1715 IMG_TITLESCREEN_INITIAL_3,
1716 IMG_TITLESCREEN_INITIAL_4,
1717 IMG_TITLESCREEN_INITIAL_5,
1724 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1725 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1726 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1727 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1728 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1729 IMG_BACKGROUND_TITLEMESSAGE_1,
1730 IMG_BACKGROUND_TITLEMESSAGE_2,
1731 IMG_BACKGROUND_TITLEMESSAGE_3,
1732 IMG_BACKGROUND_TITLEMESSAGE_4,
1733 IMG_BACKGROUND_TITLEMESSAGE_5,
1738 FreeGlobalAnimEventInfo();
1740 checked_free(graphic_info);
1742 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1744 // initialize "use_image_size" flag with default value
1745 for (i = 0; i < num_images; i++)
1746 graphic_info[i].use_image_size = FALSE;
1748 // initialize "use_image_size" flag from static configuration above
1749 for (i = 0; full_size_graphics[i] != -1; i++)
1750 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1752 // first set all graphic paramaters ...
1753 for (i = 0; i < num_images; i++)
1754 set_graphic_parameters(i);
1756 // ... then copy these parameters for cloned graphics
1757 for (i = 0; i < num_images; i++)
1758 if (graphic_info[i].clone_from != -1)
1759 set_cloned_graphic_parameters(i);
1761 for (i = 0; i < num_images; i++)
1763 Bitmap *src_bitmap = graphic_info[i].bitmap;
1767 int src_bitmap_width, src_bitmap_height;
1769 // now check if no animation frames are outside of the loaded image
1771 if (graphic_info[i].bitmap == NULL)
1772 continue; // skip check for optional images that are undefined
1774 // get image size (this can differ from the standard element tile size!)
1775 width = graphic_info[i].width;
1776 height = graphic_info[i].height;
1778 // get final bitmap size (with scaling, but without small images)
1779 src_bitmap_width = graphic_info[i].src_image_width;
1780 src_bitmap_height = graphic_info[i].src_image_height;
1782 // check if first animation frame is inside specified bitmap
1784 // do not use getGraphicSourceXY() here to get position of first frame;
1785 // this avoids calculating wrong start position for out-of-bounds frame
1786 src_x = graphic_info[i].src_x;
1787 src_y = graphic_info[i].src_y;
1789 if (program.headless)
1792 if (src_x < 0 || src_y < 0 ||
1793 src_x + width > src_bitmap_width ||
1794 src_y + height > src_bitmap_height)
1796 Error(ERR_INFO_LINE, "-");
1797 Error(ERR_INFO, "warning: error found in config file:");
1798 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1799 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1800 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1801 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1803 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1804 src_x, src_y, src_bitmap_width, src_bitmap_height);
1805 Error(ERR_INFO, "custom graphic rejected for this element/action");
1807 if (i == fallback_graphic)
1808 Error(ERR_EXIT, "no fallback graphic available");
1810 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1811 Error(ERR_INFO_LINE, "-");
1813 graphic_info[i] = graphic_info[fallback_graphic];
1815 // if first frame out of bounds, do not check last frame anymore
1819 // check if last animation frame is inside specified bitmap
1821 last_frame = graphic_info[i].anim_frames - 1;
1822 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1824 if (src_x < 0 || src_y < 0 ||
1825 src_x + width > src_bitmap_width ||
1826 src_y + height > src_bitmap_height)
1828 Error(ERR_INFO_LINE, "-");
1829 Error(ERR_INFO, "warning: error found in config file:");
1830 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1831 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1832 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1833 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1835 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1836 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1837 Error(ERR_INFO, "custom graphic rejected for this element/action");
1839 if (i == fallback_graphic)
1840 Error(ERR_EXIT, "no fallback graphic available");
1842 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1843 Error(ERR_INFO_LINE, "-");
1845 graphic_info[i] = graphic_info[fallback_graphic];
1850 static void InitGraphicCompatibilityInfo(void)
1852 struct FileInfo *fi_global_door =
1853 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1854 int num_images = getImageListSize();
1857 /* the following compatibility handling is needed for the following case:
1858 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1859 graphics mainly used for door and panel graphics, like editor, tape and
1860 in-game buttons with hard-coded bitmap positions and button sizes; as
1861 these graphics now have individual definitions, redefining "global.door"
1862 to change all these graphics at once like before does not work anymore
1863 (because all those individual definitions still have their default values);
1864 to solve this, remap all those individual definitions that are not
1865 redefined to the new bitmap of "global.door" if it was redefined */
1867 // special compatibility handling if image "global.door" was redefined
1868 if (fi_global_door->redefined)
1870 for (i = 0; i < num_images; i++)
1872 struct FileInfo *fi = getImageListEntryFromImageID(i);
1874 // process only those images that still use the default settings
1877 // process all images which default to same image as "global.door"
1878 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1880 // printf("::: special treatment needed for token '%s'\n", fi->token);
1882 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1883 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1889 InitGraphicCompatibilityInfo_Doors();
1892 static void InitElementSoundInfo(void)
1894 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1895 int num_property_mappings = getSoundListPropertyMappingSize();
1898 // set values to -1 to identify later as "uninitialized" values
1899 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1900 for (act = 0; act < NUM_ACTIONS; act++)
1901 element_info[i].sound[act] = -1;
1903 // initialize element/sound mapping from static configuration
1904 for (i = 0; element_to_sound[i].element > -1; i++)
1906 int element = element_to_sound[i].element;
1907 int action = element_to_sound[i].action;
1908 int sound = element_to_sound[i].sound;
1909 boolean is_class = element_to_sound[i].is_class;
1912 action = ACTION_DEFAULT;
1915 element_info[element].sound[action] = sound;
1917 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1918 if (strEqual(element_info[j].class_name,
1919 element_info[element].class_name))
1920 element_info[j].sound[action] = sound;
1923 // initialize element class/sound mapping from dynamic configuration
1924 for (i = 0; i < num_property_mappings; i++)
1926 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1927 int action = property_mapping[i].ext1_index;
1928 int sound = property_mapping[i].artwork_index;
1930 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1934 action = ACTION_DEFAULT;
1936 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1937 if (strEqual(element_info[j].class_name,
1938 element_info[element_class].class_name))
1939 element_info[j].sound[action] = sound;
1942 // initialize element/sound mapping from dynamic configuration
1943 for (i = 0; i < num_property_mappings; i++)
1945 int element = property_mapping[i].base_index;
1946 int action = property_mapping[i].ext1_index;
1947 int sound = property_mapping[i].artwork_index;
1949 if (element >= MAX_NUM_ELEMENTS)
1953 action = ACTION_DEFAULT;
1955 element_info[element].sound[action] = sound;
1958 // now set all '-1' values to element specific default values
1959 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1961 for (act = 0; act < NUM_ACTIONS; act++)
1963 // generic default action sound (defined by "[default]" directive)
1964 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1966 // look for special default action sound (classic game specific)
1967 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1968 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1969 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1970 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1971 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1972 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1973 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1974 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1976 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1977 // !!! make this better !!!
1978 if (i == EL_EMPTY_SPACE)
1979 default_action_sound = element_info[EL_DEFAULT].sound[act];
1981 // no sound for this specific action -- use default action sound
1982 if (element_info[i].sound[act] == -1)
1983 element_info[i].sound[act] = default_action_sound;
1987 // copy sound settings to some elements that are only stored in level file
1988 // in native R'n'D levels, but are used by game engine in native EM levels
1989 for (i = 0; copy_properties[i][0] != -1; i++)
1990 for (j = 1; j <= 4; j++)
1991 for (act = 0; act < NUM_ACTIONS; act++)
1992 element_info[copy_properties[i][j]].sound[act] =
1993 element_info[copy_properties[i][0]].sound[act];
1996 static void InitGameModeSoundInfo(void)
2000 // set values to -1 to identify later as "uninitialized" values
2001 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2004 // initialize gamemode/sound mapping from static configuration
2005 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2007 int gamemode = gamemode_to_sound[i].gamemode;
2008 int sound = gamemode_to_sound[i].sound;
2011 gamemode = GAME_MODE_DEFAULT;
2013 menu.sound[gamemode] = sound;
2016 // now set all '-1' values to levelset specific default values
2017 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2018 if (menu.sound[i] == -1)
2019 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2022 static void set_sound_parameters(int sound, char **parameter_raw)
2024 int parameter[NUM_SND_ARGS];
2027 // get integer values from string parameters
2028 for (i = 0; i < NUM_SND_ARGS; i++)
2030 get_parameter_value(parameter_raw[i],
2031 sound_config_suffix[i].token,
2032 sound_config_suffix[i].type);
2034 // explicit loop mode setting in configuration overrides default value
2035 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2036 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2038 // sound volume to change the original volume when loading the sound file
2039 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2041 // sound priority to give certain sounds a higher or lower priority
2042 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2045 static void InitSoundInfo(void)
2047 int *sound_effect_properties;
2048 int num_sounds = getSoundListSize();
2051 checked_free(sound_info);
2053 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2054 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2056 // initialize sound effect for all elements to "no sound"
2057 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2058 for (j = 0; j < NUM_ACTIONS; j++)
2059 element_info[i].sound[j] = SND_UNDEFINED;
2061 for (i = 0; i < num_sounds; i++)
2063 struct FileInfo *sound = getSoundListEntry(i);
2064 int len_effect_text = strlen(sound->token);
2066 sound_effect_properties[i] = ACTION_OTHER;
2067 sound_info[i].loop = FALSE; // default: play sound only once
2069 // determine all loop sounds and identify certain sound classes
2071 for (j = 0; element_action_info[j].suffix; j++)
2073 int len_action_text = strlen(element_action_info[j].suffix);
2075 if (len_action_text < len_effect_text &&
2076 strEqual(&sound->token[len_effect_text - len_action_text],
2077 element_action_info[j].suffix))
2079 sound_effect_properties[i] = element_action_info[j].value;
2080 sound_info[i].loop = element_action_info[j].is_loop_sound;
2086 // associate elements and some selected sound actions
2088 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2090 if (element_info[j].class_name)
2092 int len_class_text = strlen(element_info[j].class_name);
2094 if (len_class_text + 1 < len_effect_text &&
2095 strncmp(sound->token,
2096 element_info[j].class_name, len_class_text) == 0 &&
2097 sound->token[len_class_text] == '.')
2099 int sound_action_value = sound_effect_properties[i];
2101 element_info[j].sound[sound_action_value] = i;
2106 set_sound_parameters(i, sound->parameter);
2109 free(sound_effect_properties);
2112 static void InitGameModeMusicInfo(void)
2114 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2115 int num_property_mappings = getMusicListPropertyMappingSize();
2116 int default_levelset_music = -1;
2119 // set values to -1 to identify later as "uninitialized" values
2120 for (i = 0; i < MAX_LEVELS; i++)
2121 levelset.music[i] = -1;
2122 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2125 // initialize gamemode/music mapping from static configuration
2126 for (i = 0; gamemode_to_music[i].music > -1; i++)
2128 int gamemode = gamemode_to_music[i].gamemode;
2129 int music = gamemode_to_music[i].music;
2132 gamemode = GAME_MODE_DEFAULT;
2134 menu.music[gamemode] = music;
2137 // initialize gamemode/music mapping from dynamic configuration
2138 for (i = 0; i < num_property_mappings; i++)
2140 int prefix = property_mapping[i].base_index;
2141 int gamemode = property_mapping[i].ext2_index;
2142 int level = property_mapping[i].ext3_index;
2143 int music = property_mapping[i].artwork_index;
2145 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2149 gamemode = GAME_MODE_DEFAULT;
2151 // level specific music only allowed for in-game music
2152 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2153 gamemode = GAME_MODE_PLAYING;
2158 default_levelset_music = music;
2161 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2162 levelset.music[level] = music;
2163 if (gamemode != GAME_MODE_PLAYING)
2164 menu.music[gamemode] = music;
2167 // now set all '-1' values to menu specific default values
2168 // (undefined values of "levelset.music[]" might stay at "-1" to
2169 // allow dynamic selection of music files from music directory!)
2170 for (i = 0; i < MAX_LEVELS; i++)
2171 if (levelset.music[i] == -1)
2172 levelset.music[i] = default_levelset_music;
2173 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2174 if (menu.music[i] == -1)
2175 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2178 static void set_music_parameters(int music, char **parameter_raw)
2180 int parameter[NUM_MUS_ARGS];
2183 // get integer values from string parameters
2184 for (i = 0; i < NUM_MUS_ARGS; i++)
2186 get_parameter_value(parameter_raw[i],
2187 music_config_suffix[i].token,
2188 music_config_suffix[i].type);
2190 // explicit loop mode setting in configuration overrides default value
2191 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2192 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2195 static void InitMusicInfo(void)
2197 int num_music = getMusicListSize();
2200 checked_free(music_info);
2202 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2204 for (i = 0; i < num_music; i++)
2206 struct FileInfo *music = getMusicListEntry(i);
2207 int len_music_text = strlen(music->token);
2209 music_info[i].loop = TRUE; // default: play music in loop mode
2211 // determine all loop music
2213 for (j = 0; music_prefix_info[j].prefix; j++)
2215 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2217 if (len_prefix_text < len_music_text &&
2218 strncmp(music->token,
2219 music_prefix_info[j].prefix, len_prefix_text) == 0)
2221 music_info[i].loop = music_prefix_info[j].is_loop_music;
2227 set_music_parameters(i, music->parameter);
2231 static void ReinitializeGraphics(void)
2233 print_timestamp_init("ReinitializeGraphics");
2235 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2237 InitGraphicInfo(); // graphic properties mapping
2238 print_timestamp_time("InitGraphicInfo");
2239 InitElementGraphicInfo(); // element game graphic mapping
2240 print_timestamp_time("InitElementGraphicInfo");
2241 InitElementSpecialGraphicInfo(); // element special graphic mapping
2242 print_timestamp_time("InitElementSpecialGraphicInfo");
2244 InitElementSmallImages(); // scale elements to all needed sizes
2245 print_timestamp_time("InitElementSmallImages");
2246 InitScaledImages(); // scale all other images, if needed
2247 print_timestamp_time("InitScaledImages");
2248 InitBitmapPointers(); // set standard size bitmap pointers
2249 print_timestamp_time("InitBitmapPointers");
2250 InitFontGraphicInfo(); // initialize text drawing functions
2251 print_timestamp_time("InitFontGraphicInfo");
2252 InitGlobalAnimGraphicInfo(); // initialize global animation config
2253 print_timestamp_time("InitGlobalAnimGraphicInfo");
2255 InitImageTextures(); // create textures for certain images
2256 print_timestamp_time("InitImageTextures");
2258 InitGraphicInfo_EM(); // graphic mapping for EM engine
2259 print_timestamp_time("InitGraphicInfo_EM");
2261 InitGraphicCompatibilityInfo();
2262 print_timestamp_time("InitGraphicCompatibilityInfo");
2264 SetMainBackgroundImage(IMG_BACKGROUND);
2265 print_timestamp_time("SetMainBackgroundImage");
2266 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2267 print_timestamp_time("SetDoorBackgroundImage");
2270 print_timestamp_time("InitGadgets");
2272 print_timestamp_time("InitDoors");
2274 print_timestamp_done("ReinitializeGraphics");
2277 static void ReinitializeSounds(void)
2279 InitSoundInfo(); // sound properties mapping
2280 InitElementSoundInfo(); // element game sound mapping
2281 InitGameModeSoundInfo(); // game mode sound mapping
2282 InitGlobalAnimSoundInfo(); // global animation sound settings
2284 InitPlayLevelSound(); // internal game sound settings
2287 static void ReinitializeMusic(void)
2289 InitMusicInfo(); // music properties mapping
2290 InitGameModeMusicInfo(); // game mode music mapping
2291 InitGlobalAnimMusicInfo(); // global animation music settings
2294 static int get_special_property_bit(int element, int property_bit_nr)
2296 struct PropertyBitInfo
2302 static struct PropertyBitInfo pb_can_move_into_acid[] =
2304 // the player may be able fall into acid when gravity is activated
2309 { EL_SP_MURPHY, 0 },
2310 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2312 // all elements that can move may be able to also move into acid
2315 { EL_BUG_RIGHT, 1 },
2318 { EL_SPACESHIP, 2 },
2319 { EL_SPACESHIP_LEFT, 2 },
2320 { EL_SPACESHIP_RIGHT, 2 },
2321 { EL_SPACESHIP_UP, 2 },
2322 { EL_SPACESHIP_DOWN, 2 },
2323 { EL_BD_BUTTERFLY, 3 },
2324 { EL_BD_BUTTERFLY_LEFT, 3 },
2325 { EL_BD_BUTTERFLY_RIGHT, 3 },
2326 { EL_BD_BUTTERFLY_UP, 3 },
2327 { EL_BD_BUTTERFLY_DOWN, 3 },
2328 { EL_BD_FIREFLY, 4 },
2329 { EL_BD_FIREFLY_LEFT, 4 },
2330 { EL_BD_FIREFLY_RIGHT, 4 },
2331 { EL_BD_FIREFLY_UP, 4 },
2332 { EL_BD_FIREFLY_DOWN, 4 },
2334 { EL_YAMYAM_LEFT, 5 },
2335 { EL_YAMYAM_RIGHT, 5 },
2336 { EL_YAMYAM_UP, 5 },
2337 { EL_YAMYAM_DOWN, 5 },
2338 { EL_DARK_YAMYAM, 6 },
2341 { EL_PACMAN_LEFT, 8 },
2342 { EL_PACMAN_RIGHT, 8 },
2343 { EL_PACMAN_UP, 8 },
2344 { EL_PACMAN_DOWN, 8 },
2346 { EL_MOLE_LEFT, 9 },
2347 { EL_MOLE_RIGHT, 9 },
2349 { EL_MOLE_DOWN, 9 },
2353 { EL_SATELLITE, 13 },
2354 { EL_SP_SNIKSNAK, 14 },
2355 { EL_SP_ELECTRON, 15 },
2358 { EL_EMC_ANDROID, 18 },
2363 static struct PropertyBitInfo pb_dont_collide_with[] =
2365 { EL_SP_SNIKSNAK, 0 },
2366 { EL_SP_ELECTRON, 1 },
2374 struct PropertyBitInfo *pb_info;
2377 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2378 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2383 struct PropertyBitInfo *pb_info = NULL;
2386 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2387 if (pb_definition[i].bit_nr == property_bit_nr)
2388 pb_info = pb_definition[i].pb_info;
2390 if (pb_info == NULL)
2393 for (i = 0; pb_info[i].element != -1; i++)
2394 if (pb_info[i].element == element)
2395 return pb_info[i].bit_nr;
2400 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2401 boolean property_value)
2403 int bit_nr = get_special_property_bit(element, property_bit_nr);
2408 *bitfield |= (1 << bit_nr);
2410 *bitfield &= ~(1 << bit_nr);
2414 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2416 int bit_nr = get_special_property_bit(element, property_bit_nr);
2419 return ((*bitfield & (1 << bit_nr)) != 0);
2424 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2426 static int group_nr;
2427 static struct ElementGroupInfo *group;
2428 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2431 if (actual_group == NULL) // not yet initialized
2434 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2436 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2437 group_element - EL_GROUP_START + 1);
2439 // replace element which caused too deep recursion by question mark
2440 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2445 if (recursion_depth == 0) // initialization
2447 group = actual_group;
2448 group_nr = GROUP_NR(group_element);
2450 group->num_elements_resolved = 0;
2451 group->choice_pos = 0;
2453 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2454 element_info[i].in_group[group_nr] = FALSE;
2457 for (i = 0; i < actual_group->num_elements; i++)
2459 int element = actual_group->element[i];
2461 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2464 if (IS_GROUP_ELEMENT(element))
2465 ResolveGroupElementExt(element, recursion_depth + 1);
2468 group->element_resolved[group->num_elements_resolved++] = element;
2469 element_info[element].in_group[group_nr] = TRUE;
2474 void ResolveGroupElement(int group_element)
2476 ResolveGroupElementExt(group_element, 0);
2479 void InitElementPropertiesStatic(void)
2481 static boolean clipboard_elements_initialized = FALSE;
2483 static int ep_diggable[] =
2488 EL_SP_BUGGY_BASE_ACTIVATING,
2491 EL_INVISIBLE_SAND_ACTIVE,
2494 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2495 // (if amoeba can grow into anything diggable, maybe keep these out)
2500 EL_SP_BUGGY_BASE_ACTIVE,
2507 static int ep_collectible_only[] =
2529 EL_DYNABOMB_INCREASE_NUMBER,
2530 EL_DYNABOMB_INCREASE_SIZE,
2531 EL_DYNABOMB_INCREASE_POWER,
2549 // !!! handle separately !!!
2550 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2556 static int ep_dont_run_into[] =
2558 // same elements as in 'ep_dont_touch'
2564 // same elements as in 'ep_dont_collide_with'
2576 // !!! maybe this should better be handled by 'ep_diggable' !!!
2581 EL_SP_BUGGY_BASE_ACTIVE,
2588 static int ep_dont_collide_with[] =
2590 // same elements as in 'ep_dont_touch'
2607 static int ep_dont_touch[] =
2617 static int ep_indestructible[] =
2621 EL_ACID_POOL_TOPLEFT,
2622 EL_ACID_POOL_TOPRIGHT,
2623 EL_ACID_POOL_BOTTOMLEFT,
2624 EL_ACID_POOL_BOTTOM,
2625 EL_ACID_POOL_BOTTOMRIGHT,
2626 EL_SP_HARDWARE_GRAY,
2627 EL_SP_HARDWARE_GREEN,
2628 EL_SP_HARDWARE_BLUE,
2630 EL_SP_HARDWARE_YELLOW,
2631 EL_SP_HARDWARE_BASE_1,
2632 EL_SP_HARDWARE_BASE_2,
2633 EL_SP_HARDWARE_BASE_3,
2634 EL_SP_HARDWARE_BASE_4,
2635 EL_SP_HARDWARE_BASE_5,
2636 EL_SP_HARDWARE_BASE_6,
2637 EL_INVISIBLE_STEELWALL,
2638 EL_INVISIBLE_STEELWALL_ACTIVE,
2639 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2640 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2641 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2642 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2643 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2644 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2645 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2646 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2647 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2648 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2649 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2650 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2652 EL_LIGHT_SWITCH_ACTIVE,
2653 EL_SIGN_EXCLAMATION,
2654 EL_SIGN_RADIOACTIVITY,
2661 EL_SIGN_ENTRY_FORBIDDEN,
2662 EL_SIGN_EMERGENCY_EXIT,
2670 EL_STEEL_EXIT_CLOSED,
2672 EL_STEEL_EXIT_OPENING,
2673 EL_STEEL_EXIT_CLOSING,
2674 EL_EM_STEEL_EXIT_CLOSED,
2675 EL_EM_STEEL_EXIT_OPEN,
2676 EL_EM_STEEL_EXIT_OPENING,
2677 EL_EM_STEEL_EXIT_CLOSING,
2678 EL_DC_STEELWALL_1_LEFT,
2679 EL_DC_STEELWALL_1_RIGHT,
2680 EL_DC_STEELWALL_1_TOP,
2681 EL_DC_STEELWALL_1_BOTTOM,
2682 EL_DC_STEELWALL_1_HORIZONTAL,
2683 EL_DC_STEELWALL_1_VERTICAL,
2684 EL_DC_STEELWALL_1_TOPLEFT,
2685 EL_DC_STEELWALL_1_TOPRIGHT,
2686 EL_DC_STEELWALL_1_BOTTOMLEFT,
2687 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2688 EL_DC_STEELWALL_1_TOPLEFT_2,
2689 EL_DC_STEELWALL_1_TOPRIGHT_2,
2690 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2691 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2692 EL_DC_STEELWALL_2_LEFT,
2693 EL_DC_STEELWALL_2_RIGHT,
2694 EL_DC_STEELWALL_2_TOP,
2695 EL_DC_STEELWALL_2_BOTTOM,
2696 EL_DC_STEELWALL_2_HORIZONTAL,
2697 EL_DC_STEELWALL_2_VERTICAL,
2698 EL_DC_STEELWALL_2_MIDDLE,
2699 EL_DC_STEELWALL_2_SINGLE,
2700 EL_STEELWALL_SLIPPERY,
2714 EL_GATE_1_GRAY_ACTIVE,
2715 EL_GATE_2_GRAY_ACTIVE,
2716 EL_GATE_3_GRAY_ACTIVE,
2717 EL_GATE_4_GRAY_ACTIVE,
2726 EL_EM_GATE_1_GRAY_ACTIVE,
2727 EL_EM_GATE_2_GRAY_ACTIVE,
2728 EL_EM_GATE_3_GRAY_ACTIVE,
2729 EL_EM_GATE_4_GRAY_ACTIVE,
2738 EL_EMC_GATE_5_GRAY_ACTIVE,
2739 EL_EMC_GATE_6_GRAY_ACTIVE,
2740 EL_EMC_GATE_7_GRAY_ACTIVE,
2741 EL_EMC_GATE_8_GRAY_ACTIVE,
2743 EL_DC_GATE_WHITE_GRAY,
2744 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2745 EL_DC_GATE_FAKE_GRAY,
2747 EL_SWITCHGATE_OPENING,
2748 EL_SWITCHGATE_CLOSED,
2749 EL_SWITCHGATE_CLOSING,
2750 EL_DC_SWITCHGATE_SWITCH_UP,
2751 EL_DC_SWITCHGATE_SWITCH_DOWN,
2753 EL_TIMEGATE_OPENING,
2755 EL_TIMEGATE_CLOSING,
2756 EL_DC_TIMEGATE_SWITCH,
2757 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2761 EL_TUBE_VERTICAL_LEFT,
2762 EL_TUBE_VERTICAL_RIGHT,
2763 EL_TUBE_HORIZONTAL_UP,
2764 EL_TUBE_HORIZONTAL_DOWN,
2769 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2770 EL_EXPANDABLE_STEELWALL_VERTICAL,
2771 EL_EXPANDABLE_STEELWALL_ANY,
2776 static int ep_slippery[] =
2790 EL_ROBOT_WHEEL_ACTIVE,
2796 EL_ACID_POOL_TOPLEFT,
2797 EL_ACID_POOL_TOPRIGHT,
2807 EL_STEELWALL_SLIPPERY,
2810 EL_EMC_WALL_SLIPPERY_1,
2811 EL_EMC_WALL_SLIPPERY_2,
2812 EL_EMC_WALL_SLIPPERY_3,
2813 EL_EMC_WALL_SLIPPERY_4,
2815 EL_EMC_MAGIC_BALL_ACTIVE,
2820 static int ep_can_change[] =
2825 static int ep_can_move[] =
2827 // same elements as in 'pb_can_move_into_acid'
2850 static int ep_can_fall[] =
2864 EL_QUICKSAND_FAST_FULL,
2866 EL_BD_MAGIC_WALL_FULL,
2867 EL_DC_MAGIC_WALL_FULL,
2881 static int ep_can_smash_player[] =
2907 static int ep_can_smash_enemies[] =
2916 static int ep_can_smash_everything[] =
2925 static int ep_explodes_by_fire[] =
2927 // same elements as in 'ep_explodes_impact'
2932 // same elements as in 'ep_explodes_smashed'
2942 EL_EM_DYNAMITE_ACTIVE,
2943 EL_DYNABOMB_PLAYER_1_ACTIVE,
2944 EL_DYNABOMB_PLAYER_2_ACTIVE,
2945 EL_DYNABOMB_PLAYER_3_ACTIVE,
2946 EL_DYNABOMB_PLAYER_4_ACTIVE,
2947 EL_DYNABOMB_INCREASE_NUMBER,
2948 EL_DYNABOMB_INCREASE_SIZE,
2949 EL_DYNABOMB_INCREASE_POWER,
2950 EL_SP_DISK_RED_ACTIVE,
2964 static int ep_explodes_smashed[] =
2966 // same elements as in 'ep_explodes_impact'
2980 static int ep_explodes_impact[] =
2989 static int ep_walkable_over[] =
2993 EL_SOKOBAN_FIELD_EMPTY,
3000 EL_EM_STEEL_EXIT_OPEN,
3001 EL_EM_STEEL_EXIT_OPENING,
3010 EL_GATE_1_GRAY_ACTIVE,
3011 EL_GATE_2_GRAY_ACTIVE,
3012 EL_GATE_3_GRAY_ACTIVE,
3013 EL_GATE_4_GRAY_ACTIVE,
3021 static int ep_walkable_inside[] =
3026 EL_TUBE_VERTICAL_LEFT,
3027 EL_TUBE_VERTICAL_RIGHT,
3028 EL_TUBE_HORIZONTAL_UP,
3029 EL_TUBE_HORIZONTAL_DOWN,
3038 static int ep_walkable_under[] =
3043 static int ep_passable_over[] =
3053 EL_EM_GATE_1_GRAY_ACTIVE,
3054 EL_EM_GATE_2_GRAY_ACTIVE,
3055 EL_EM_GATE_3_GRAY_ACTIVE,
3056 EL_EM_GATE_4_GRAY_ACTIVE,
3065 EL_EMC_GATE_5_GRAY_ACTIVE,
3066 EL_EMC_GATE_6_GRAY_ACTIVE,
3067 EL_EMC_GATE_7_GRAY_ACTIVE,
3068 EL_EMC_GATE_8_GRAY_ACTIVE,
3070 EL_DC_GATE_WHITE_GRAY,
3071 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3078 static int ep_passable_inside[] =
3084 EL_SP_PORT_HORIZONTAL,
3085 EL_SP_PORT_VERTICAL,
3087 EL_SP_GRAVITY_PORT_LEFT,
3088 EL_SP_GRAVITY_PORT_RIGHT,
3089 EL_SP_GRAVITY_PORT_UP,
3090 EL_SP_GRAVITY_PORT_DOWN,
3091 EL_SP_GRAVITY_ON_PORT_LEFT,
3092 EL_SP_GRAVITY_ON_PORT_RIGHT,
3093 EL_SP_GRAVITY_ON_PORT_UP,
3094 EL_SP_GRAVITY_ON_PORT_DOWN,
3095 EL_SP_GRAVITY_OFF_PORT_LEFT,
3096 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3097 EL_SP_GRAVITY_OFF_PORT_UP,
3098 EL_SP_GRAVITY_OFF_PORT_DOWN,
3103 static int ep_passable_under[] =
3108 static int ep_droppable[] =
3113 static int ep_explodes_1x1_old[] =
3118 static int ep_pushable[] =
3130 EL_SOKOBAN_FIELD_FULL,
3139 static int ep_explodes_cross_old[] =
3144 static int ep_protected[] =
3146 // same elements as in 'ep_walkable_inside'
3150 EL_TUBE_VERTICAL_LEFT,
3151 EL_TUBE_VERTICAL_RIGHT,
3152 EL_TUBE_HORIZONTAL_UP,
3153 EL_TUBE_HORIZONTAL_DOWN,
3159 // same elements as in 'ep_passable_over'
3168 EL_EM_GATE_1_GRAY_ACTIVE,
3169 EL_EM_GATE_2_GRAY_ACTIVE,
3170 EL_EM_GATE_3_GRAY_ACTIVE,
3171 EL_EM_GATE_4_GRAY_ACTIVE,
3180 EL_EMC_GATE_5_GRAY_ACTIVE,
3181 EL_EMC_GATE_6_GRAY_ACTIVE,
3182 EL_EMC_GATE_7_GRAY_ACTIVE,
3183 EL_EMC_GATE_8_GRAY_ACTIVE,
3185 EL_DC_GATE_WHITE_GRAY,
3186 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3190 // same elements as in 'ep_passable_inside'
3195 EL_SP_PORT_HORIZONTAL,
3196 EL_SP_PORT_VERTICAL,
3198 EL_SP_GRAVITY_PORT_LEFT,
3199 EL_SP_GRAVITY_PORT_RIGHT,
3200 EL_SP_GRAVITY_PORT_UP,
3201 EL_SP_GRAVITY_PORT_DOWN,
3202 EL_SP_GRAVITY_ON_PORT_LEFT,
3203 EL_SP_GRAVITY_ON_PORT_RIGHT,
3204 EL_SP_GRAVITY_ON_PORT_UP,
3205 EL_SP_GRAVITY_ON_PORT_DOWN,
3206 EL_SP_GRAVITY_OFF_PORT_LEFT,
3207 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3208 EL_SP_GRAVITY_OFF_PORT_UP,
3209 EL_SP_GRAVITY_OFF_PORT_DOWN,
3214 static int ep_throwable[] =
3219 static int ep_can_explode[] =
3221 // same elements as in 'ep_explodes_impact'
3226 // same elements as in 'ep_explodes_smashed'
3232 // elements that can explode by explosion or by dragonfire
3236 EL_EM_DYNAMITE_ACTIVE,
3237 EL_DYNABOMB_PLAYER_1_ACTIVE,
3238 EL_DYNABOMB_PLAYER_2_ACTIVE,
3239 EL_DYNABOMB_PLAYER_3_ACTIVE,
3240 EL_DYNABOMB_PLAYER_4_ACTIVE,
3241 EL_DYNABOMB_INCREASE_NUMBER,
3242 EL_DYNABOMB_INCREASE_SIZE,
3243 EL_DYNABOMB_INCREASE_POWER,
3244 EL_SP_DISK_RED_ACTIVE,
3252 // elements that can explode only by explosion
3258 static int ep_gravity_reachable[] =
3264 EL_INVISIBLE_SAND_ACTIVE,
3269 EL_SP_PORT_HORIZONTAL,
3270 EL_SP_PORT_VERTICAL,
3272 EL_SP_GRAVITY_PORT_LEFT,
3273 EL_SP_GRAVITY_PORT_RIGHT,
3274 EL_SP_GRAVITY_PORT_UP,
3275 EL_SP_GRAVITY_PORT_DOWN,
3276 EL_SP_GRAVITY_ON_PORT_LEFT,
3277 EL_SP_GRAVITY_ON_PORT_RIGHT,
3278 EL_SP_GRAVITY_ON_PORT_UP,
3279 EL_SP_GRAVITY_ON_PORT_DOWN,
3280 EL_SP_GRAVITY_OFF_PORT_LEFT,
3281 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3282 EL_SP_GRAVITY_OFF_PORT_UP,
3283 EL_SP_GRAVITY_OFF_PORT_DOWN,
3289 static int ep_player[] =
3296 EL_SOKOBAN_FIELD_PLAYER,
3302 static int ep_can_pass_magic_wall[] =
3316 static int ep_can_pass_dc_magic_wall[] =
3332 static int ep_switchable[] =
3336 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3337 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3338 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3339 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3340 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3341 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3342 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3343 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3344 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3345 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3346 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3347 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3348 EL_SWITCHGATE_SWITCH_UP,
3349 EL_SWITCHGATE_SWITCH_DOWN,
3350 EL_DC_SWITCHGATE_SWITCH_UP,
3351 EL_DC_SWITCHGATE_SWITCH_DOWN,
3353 EL_LIGHT_SWITCH_ACTIVE,
3355 EL_DC_TIMEGATE_SWITCH,
3356 EL_BALLOON_SWITCH_LEFT,
3357 EL_BALLOON_SWITCH_RIGHT,
3358 EL_BALLOON_SWITCH_UP,
3359 EL_BALLOON_SWITCH_DOWN,
3360 EL_BALLOON_SWITCH_ANY,
3361 EL_BALLOON_SWITCH_NONE,
3364 EL_EMC_MAGIC_BALL_SWITCH,
3365 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3370 static int ep_bd_element[] =
3404 static int ep_sp_element[] =
3406 // should always be valid
3409 // standard classic Supaplex elements
3416 EL_SP_HARDWARE_GRAY,
3424 EL_SP_GRAVITY_PORT_RIGHT,
3425 EL_SP_GRAVITY_PORT_DOWN,
3426 EL_SP_GRAVITY_PORT_LEFT,
3427 EL_SP_GRAVITY_PORT_UP,
3432 EL_SP_PORT_VERTICAL,
3433 EL_SP_PORT_HORIZONTAL,
3439 EL_SP_HARDWARE_BASE_1,
3440 EL_SP_HARDWARE_GREEN,
3441 EL_SP_HARDWARE_BLUE,
3443 EL_SP_HARDWARE_YELLOW,
3444 EL_SP_HARDWARE_BASE_2,
3445 EL_SP_HARDWARE_BASE_3,
3446 EL_SP_HARDWARE_BASE_4,
3447 EL_SP_HARDWARE_BASE_5,
3448 EL_SP_HARDWARE_BASE_6,
3452 // additional elements that appeared in newer Supaplex levels
3455 // additional gravity port elements (not switching, but setting gravity)
3456 EL_SP_GRAVITY_ON_PORT_LEFT,
3457 EL_SP_GRAVITY_ON_PORT_RIGHT,
3458 EL_SP_GRAVITY_ON_PORT_UP,
3459 EL_SP_GRAVITY_ON_PORT_DOWN,
3460 EL_SP_GRAVITY_OFF_PORT_LEFT,
3461 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3462 EL_SP_GRAVITY_OFF_PORT_UP,
3463 EL_SP_GRAVITY_OFF_PORT_DOWN,
3465 // more than one Murphy in a level results in an inactive clone
3468 // runtime Supaplex elements
3469 EL_SP_DISK_RED_ACTIVE,
3470 EL_SP_TERMINAL_ACTIVE,
3471 EL_SP_BUGGY_BASE_ACTIVATING,
3472 EL_SP_BUGGY_BASE_ACTIVE,
3479 static int ep_sb_element[] =
3484 EL_SOKOBAN_FIELD_EMPTY,
3485 EL_SOKOBAN_FIELD_FULL,
3486 EL_SOKOBAN_FIELD_PLAYER,
3491 EL_INVISIBLE_STEELWALL,
3496 static int ep_gem[] =
3508 static int ep_food_dark_yamyam[] =
3536 static int ep_food_penguin[] =
3550 static int ep_food_pig[] =
3562 static int ep_historic_wall[] =
3573 EL_GATE_1_GRAY_ACTIVE,
3574 EL_GATE_2_GRAY_ACTIVE,
3575 EL_GATE_3_GRAY_ACTIVE,
3576 EL_GATE_4_GRAY_ACTIVE,
3585 EL_EM_GATE_1_GRAY_ACTIVE,
3586 EL_EM_GATE_2_GRAY_ACTIVE,
3587 EL_EM_GATE_3_GRAY_ACTIVE,
3588 EL_EM_GATE_4_GRAY_ACTIVE,
3595 EL_EXPANDABLE_WALL_HORIZONTAL,
3596 EL_EXPANDABLE_WALL_VERTICAL,
3597 EL_EXPANDABLE_WALL_ANY,
3598 EL_EXPANDABLE_WALL_GROWING,
3599 EL_BD_EXPANDABLE_WALL,
3606 EL_SP_HARDWARE_GRAY,
3607 EL_SP_HARDWARE_GREEN,
3608 EL_SP_HARDWARE_BLUE,
3610 EL_SP_HARDWARE_YELLOW,
3611 EL_SP_HARDWARE_BASE_1,
3612 EL_SP_HARDWARE_BASE_2,
3613 EL_SP_HARDWARE_BASE_3,
3614 EL_SP_HARDWARE_BASE_4,
3615 EL_SP_HARDWARE_BASE_5,
3616 EL_SP_HARDWARE_BASE_6,
3618 EL_SP_TERMINAL_ACTIVE,
3621 EL_INVISIBLE_STEELWALL,
3622 EL_INVISIBLE_STEELWALL_ACTIVE,
3624 EL_INVISIBLE_WALL_ACTIVE,
3625 EL_STEELWALL_SLIPPERY,
3642 static int ep_historic_solid[] =
3646 EL_EXPANDABLE_WALL_HORIZONTAL,
3647 EL_EXPANDABLE_WALL_VERTICAL,
3648 EL_EXPANDABLE_WALL_ANY,
3649 EL_BD_EXPANDABLE_WALL,
3662 EL_QUICKSAND_FILLING,
3663 EL_QUICKSAND_EMPTYING,
3665 EL_MAGIC_WALL_ACTIVE,
3666 EL_MAGIC_WALL_EMPTYING,
3667 EL_MAGIC_WALL_FILLING,
3671 EL_BD_MAGIC_WALL_ACTIVE,
3672 EL_BD_MAGIC_WALL_EMPTYING,
3673 EL_BD_MAGIC_WALL_FULL,
3674 EL_BD_MAGIC_WALL_FILLING,
3675 EL_BD_MAGIC_WALL_DEAD,
3684 EL_SP_TERMINAL_ACTIVE,
3688 EL_INVISIBLE_WALL_ACTIVE,
3689 EL_SWITCHGATE_SWITCH_UP,
3690 EL_SWITCHGATE_SWITCH_DOWN,
3692 EL_TIMEGATE_SWITCH_ACTIVE,
3704 // the following elements are a direct copy of "indestructible" elements,
3705 // except "EL_ACID", which is "indestructible", but not "solid"!
3710 EL_ACID_POOL_TOPLEFT,
3711 EL_ACID_POOL_TOPRIGHT,
3712 EL_ACID_POOL_BOTTOMLEFT,
3713 EL_ACID_POOL_BOTTOM,
3714 EL_ACID_POOL_BOTTOMRIGHT,
3715 EL_SP_HARDWARE_GRAY,
3716 EL_SP_HARDWARE_GREEN,
3717 EL_SP_HARDWARE_BLUE,
3719 EL_SP_HARDWARE_YELLOW,
3720 EL_SP_HARDWARE_BASE_1,
3721 EL_SP_HARDWARE_BASE_2,
3722 EL_SP_HARDWARE_BASE_3,
3723 EL_SP_HARDWARE_BASE_4,
3724 EL_SP_HARDWARE_BASE_5,
3725 EL_SP_HARDWARE_BASE_6,
3726 EL_INVISIBLE_STEELWALL,
3727 EL_INVISIBLE_STEELWALL_ACTIVE,
3728 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3729 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3730 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3731 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3732 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3733 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3734 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3735 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3736 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3737 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3738 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3739 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3741 EL_LIGHT_SWITCH_ACTIVE,
3742 EL_SIGN_EXCLAMATION,
3743 EL_SIGN_RADIOACTIVITY,
3750 EL_SIGN_ENTRY_FORBIDDEN,
3751 EL_SIGN_EMERGENCY_EXIT,
3759 EL_STEEL_EXIT_CLOSED,
3761 EL_STEEL_EXIT_OPENING,
3762 EL_STEEL_EXIT_CLOSING,
3763 EL_EM_STEEL_EXIT_CLOSED,
3764 EL_EM_STEEL_EXIT_OPEN,
3765 EL_EM_STEEL_EXIT_OPENING,
3766 EL_EM_STEEL_EXIT_CLOSING,
3767 EL_DC_STEELWALL_1_LEFT,
3768 EL_DC_STEELWALL_1_RIGHT,
3769 EL_DC_STEELWALL_1_TOP,
3770 EL_DC_STEELWALL_1_BOTTOM,
3771 EL_DC_STEELWALL_1_HORIZONTAL,
3772 EL_DC_STEELWALL_1_VERTICAL,
3773 EL_DC_STEELWALL_1_TOPLEFT,
3774 EL_DC_STEELWALL_1_TOPRIGHT,
3775 EL_DC_STEELWALL_1_BOTTOMLEFT,
3776 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3777 EL_DC_STEELWALL_1_TOPLEFT_2,
3778 EL_DC_STEELWALL_1_TOPRIGHT_2,
3779 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3780 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3781 EL_DC_STEELWALL_2_LEFT,
3782 EL_DC_STEELWALL_2_RIGHT,
3783 EL_DC_STEELWALL_2_TOP,
3784 EL_DC_STEELWALL_2_BOTTOM,
3785 EL_DC_STEELWALL_2_HORIZONTAL,
3786 EL_DC_STEELWALL_2_VERTICAL,
3787 EL_DC_STEELWALL_2_MIDDLE,
3788 EL_DC_STEELWALL_2_SINGLE,
3789 EL_STEELWALL_SLIPPERY,
3803 EL_GATE_1_GRAY_ACTIVE,
3804 EL_GATE_2_GRAY_ACTIVE,
3805 EL_GATE_3_GRAY_ACTIVE,
3806 EL_GATE_4_GRAY_ACTIVE,
3815 EL_EM_GATE_1_GRAY_ACTIVE,
3816 EL_EM_GATE_2_GRAY_ACTIVE,
3817 EL_EM_GATE_3_GRAY_ACTIVE,
3818 EL_EM_GATE_4_GRAY_ACTIVE,
3827 EL_EMC_GATE_5_GRAY_ACTIVE,
3828 EL_EMC_GATE_6_GRAY_ACTIVE,
3829 EL_EMC_GATE_7_GRAY_ACTIVE,
3830 EL_EMC_GATE_8_GRAY_ACTIVE,
3832 EL_DC_GATE_WHITE_GRAY,
3833 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3834 EL_DC_GATE_FAKE_GRAY,
3836 EL_SWITCHGATE_OPENING,
3837 EL_SWITCHGATE_CLOSED,
3838 EL_SWITCHGATE_CLOSING,
3839 EL_DC_SWITCHGATE_SWITCH_UP,
3840 EL_DC_SWITCHGATE_SWITCH_DOWN,
3842 EL_TIMEGATE_OPENING,
3844 EL_TIMEGATE_CLOSING,
3845 EL_DC_TIMEGATE_SWITCH,
3846 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3850 EL_TUBE_VERTICAL_LEFT,
3851 EL_TUBE_VERTICAL_RIGHT,
3852 EL_TUBE_HORIZONTAL_UP,
3853 EL_TUBE_HORIZONTAL_DOWN,
3858 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3859 EL_EXPANDABLE_STEELWALL_VERTICAL,
3860 EL_EXPANDABLE_STEELWALL_ANY,
3865 static int ep_classic_enemy[] =
3882 static int ep_belt[] =
3884 EL_CONVEYOR_BELT_1_LEFT,
3885 EL_CONVEYOR_BELT_1_MIDDLE,
3886 EL_CONVEYOR_BELT_1_RIGHT,
3887 EL_CONVEYOR_BELT_2_LEFT,
3888 EL_CONVEYOR_BELT_2_MIDDLE,
3889 EL_CONVEYOR_BELT_2_RIGHT,
3890 EL_CONVEYOR_BELT_3_LEFT,
3891 EL_CONVEYOR_BELT_3_MIDDLE,
3892 EL_CONVEYOR_BELT_3_RIGHT,
3893 EL_CONVEYOR_BELT_4_LEFT,
3894 EL_CONVEYOR_BELT_4_MIDDLE,
3895 EL_CONVEYOR_BELT_4_RIGHT,
3900 static int ep_belt_active[] =
3902 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3903 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3904 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3905 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3906 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3907 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3908 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3909 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3910 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3911 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3912 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3913 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3918 static int ep_belt_switch[] =
3920 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3921 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3922 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3923 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3924 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3925 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3926 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3927 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3928 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3929 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3930 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3931 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3936 static int ep_tube[] =
3943 EL_TUBE_HORIZONTAL_UP,
3944 EL_TUBE_HORIZONTAL_DOWN,
3946 EL_TUBE_VERTICAL_LEFT,
3947 EL_TUBE_VERTICAL_RIGHT,
3953 static int ep_acid_pool[] =
3955 EL_ACID_POOL_TOPLEFT,
3956 EL_ACID_POOL_TOPRIGHT,
3957 EL_ACID_POOL_BOTTOMLEFT,
3958 EL_ACID_POOL_BOTTOM,
3959 EL_ACID_POOL_BOTTOMRIGHT,
3964 static int ep_keygate[] =
3974 EL_GATE_1_GRAY_ACTIVE,
3975 EL_GATE_2_GRAY_ACTIVE,
3976 EL_GATE_3_GRAY_ACTIVE,
3977 EL_GATE_4_GRAY_ACTIVE,
3986 EL_EM_GATE_1_GRAY_ACTIVE,
3987 EL_EM_GATE_2_GRAY_ACTIVE,
3988 EL_EM_GATE_3_GRAY_ACTIVE,
3989 EL_EM_GATE_4_GRAY_ACTIVE,
3998 EL_EMC_GATE_5_GRAY_ACTIVE,
3999 EL_EMC_GATE_6_GRAY_ACTIVE,
4000 EL_EMC_GATE_7_GRAY_ACTIVE,
4001 EL_EMC_GATE_8_GRAY_ACTIVE,
4003 EL_DC_GATE_WHITE_GRAY,
4004 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4009 static int ep_amoeboid[] =
4021 static int ep_amoebalive[] =
4032 static int ep_has_editor_content[] =
4038 EL_SOKOBAN_FIELD_PLAYER,
4055 static int ep_can_turn_each_move[] =
4057 // !!! do something with this one !!!
4061 static int ep_can_grow[] =
4075 static int ep_active_bomb[] =
4078 EL_EM_DYNAMITE_ACTIVE,
4079 EL_DYNABOMB_PLAYER_1_ACTIVE,
4080 EL_DYNABOMB_PLAYER_2_ACTIVE,
4081 EL_DYNABOMB_PLAYER_3_ACTIVE,
4082 EL_DYNABOMB_PLAYER_4_ACTIVE,
4083 EL_SP_DISK_RED_ACTIVE,
4088 static int ep_inactive[] =
4098 EL_QUICKSAND_FAST_EMPTY,
4121 EL_GATE_1_GRAY_ACTIVE,
4122 EL_GATE_2_GRAY_ACTIVE,
4123 EL_GATE_3_GRAY_ACTIVE,
4124 EL_GATE_4_GRAY_ACTIVE,
4133 EL_EM_GATE_1_GRAY_ACTIVE,
4134 EL_EM_GATE_2_GRAY_ACTIVE,
4135 EL_EM_GATE_3_GRAY_ACTIVE,
4136 EL_EM_GATE_4_GRAY_ACTIVE,
4145 EL_EMC_GATE_5_GRAY_ACTIVE,
4146 EL_EMC_GATE_6_GRAY_ACTIVE,
4147 EL_EMC_GATE_7_GRAY_ACTIVE,
4148 EL_EMC_GATE_8_GRAY_ACTIVE,
4150 EL_DC_GATE_WHITE_GRAY,
4151 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4152 EL_DC_GATE_FAKE_GRAY,
4155 EL_INVISIBLE_STEELWALL,
4163 EL_WALL_EMERALD_YELLOW,
4164 EL_DYNABOMB_INCREASE_NUMBER,
4165 EL_DYNABOMB_INCREASE_SIZE,
4166 EL_DYNABOMB_INCREASE_POWER,
4170 EL_SOKOBAN_FIELD_EMPTY,
4171 EL_SOKOBAN_FIELD_FULL,
4172 EL_WALL_EMERALD_RED,
4173 EL_WALL_EMERALD_PURPLE,
4174 EL_ACID_POOL_TOPLEFT,
4175 EL_ACID_POOL_TOPRIGHT,
4176 EL_ACID_POOL_BOTTOMLEFT,
4177 EL_ACID_POOL_BOTTOM,
4178 EL_ACID_POOL_BOTTOMRIGHT,
4182 EL_BD_MAGIC_WALL_DEAD,
4184 EL_DC_MAGIC_WALL_DEAD,
4185 EL_AMOEBA_TO_DIAMOND,
4193 EL_SP_GRAVITY_PORT_RIGHT,
4194 EL_SP_GRAVITY_PORT_DOWN,
4195 EL_SP_GRAVITY_PORT_LEFT,
4196 EL_SP_GRAVITY_PORT_UP,
4197 EL_SP_PORT_HORIZONTAL,
4198 EL_SP_PORT_VERTICAL,
4209 EL_SP_HARDWARE_GRAY,
4210 EL_SP_HARDWARE_GREEN,
4211 EL_SP_HARDWARE_BLUE,
4213 EL_SP_HARDWARE_YELLOW,
4214 EL_SP_HARDWARE_BASE_1,
4215 EL_SP_HARDWARE_BASE_2,
4216 EL_SP_HARDWARE_BASE_3,
4217 EL_SP_HARDWARE_BASE_4,
4218 EL_SP_HARDWARE_BASE_5,
4219 EL_SP_HARDWARE_BASE_6,
4220 EL_SP_GRAVITY_ON_PORT_LEFT,
4221 EL_SP_GRAVITY_ON_PORT_RIGHT,
4222 EL_SP_GRAVITY_ON_PORT_UP,
4223 EL_SP_GRAVITY_ON_PORT_DOWN,
4224 EL_SP_GRAVITY_OFF_PORT_LEFT,
4225 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4226 EL_SP_GRAVITY_OFF_PORT_UP,
4227 EL_SP_GRAVITY_OFF_PORT_DOWN,
4228 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4229 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4230 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4231 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4232 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4233 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4234 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4235 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4236 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4237 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4238 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4239 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4240 EL_SIGN_EXCLAMATION,
4241 EL_SIGN_RADIOACTIVITY,
4248 EL_SIGN_ENTRY_FORBIDDEN,
4249 EL_SIGN_EMERGENCY_EXIT,
4257 EL_DC_STEELWALL_1_LEFT,
4258 EL_DC_STEELWALL_1_RIGHT,
4259 EL_DC_STEELWALL_1_TOP,
4260 EL_DC_STEELWALL_1_BOTTOM,
4261 EL_DC_STEELWALL_1_HORIZONTAL,
4262 EL_DC_STEELWALL_1_VERTICAL,
4263 EL_DC_STEELWALL_1_TOPLEFT,
4264 EL_DC_STEELWALL_1_TOPRIGHT,
4265 EL_DC_STEELWALL_1_BOTTOMLEFT,
4266 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4267 EL_DC_STEELWALL_1_TOPLEFT_2,
4268 EL_DC_STEELWALL_1_TOPRIGHT_2,
4269 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4270 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4271 EL_DC_STEELWALL_2_LEFT,
4272 EL_DC_STEELWALL_2_RIGHT,
4273 EL_DC_STEELWALL_2_TOP,
4274 EL_DC_STEELWALL_2_BOTTOM,
4275 EL_DC_STEELWALL_2_HORIZONTAL,
4276 EL_DC_STEELWALL_2_VERTICAL,
4277 EL_DC_STEELWALL_2_MIDDLE,
4278 EL_DC_STEELWALL_2_SINGLE,
4279 EL_STEELWALL_SLIPPERY,
4284 EL_EMC_WALL_SLIPPERY_1,
4285 EL_EMC_WALL_SLIPPERY_2,
4286 EL_EMC_WALL_SLIPPERY_3,
4287 EL_EMC_WALL_SLIPPERY_4,
4308 static int ep_em_slippery_wall[] =
4313 static int ep_gfx_crumbled[] =
4324 static int ep_editor_cascade_active[] =
4326 EL_INTERNAL_CASCADE_BD_ACTIVE,
4327 EL_INTERNAL_CASCADE_EM_ACTIVE,
4328 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4329 EL_INTERNAL_CASCADE_RND_ACTIVE,
4330 EL_INTERNAL_CASCADE_SB_ACTIVE,
4331 EL_INTERNAL_CASCADE_SP_ACTIVE,
4332 EL_INTERNAL_CASCADE_DC_ACTIVE,
4333 EL_INTERNAL_CASCADE_DX_ACTIVE,
4334 EL_INTERNAL_CASCADE_MM_ACTIVE,
4335 EL_INTERNAL_CASCADE_DF_ACTIVE,
4336 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4337 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4338 EL_INTERNAL_CASCADE_CE_ACTIVE,
4339 EL_INTERNAL_CASCADE_GE_ACTIVE,
4340 EL_INTERNAL_CASCADE_REF_ACTIVE,
4341 EL_INTERNAL_CASCADE_USER_ACTIVE,
4342 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4347 static int ep_editor_cascade_inactive[] =
4349 EL_INTERNAL_CASCADE_BD,
4350 EL_INTERNAL_CASCADE_EM,
4351 EL_INTERNAL_CASCADE_EMC,
4352 EL_INTERNAL_CASCADE_RND,
4353 EL_INTERNAL_CASCADE_SB,
4354 EL_INTERNAL_CASCADE_SP,
4355 EL_INTERNAL_CASCADE_DC,
4356 EL_INTERNAL_CASCADE_DX,
4357 EL_INTERNAL_CASCADE_MM,
4358 EL_INTERNAL_CASCADE_DF,
4359 EL_INTERNAL_CASCADE_CHARS,
4360 EL_INTERNAL_CASCADE_STEEL_CHARS,
4361 EL_INTERNAL_CASCADE_CE,
4362 EL_INTERNAL_CASCADE_GE,
4363 EL_INTERNAL_CASCADE_REF,
4364 EL_INTERNAL_CASCADE_USER,
4365 EL_INTERNAL_CASCADE_DYNAMIC,
4370 static int ep_obsolete[] =
4374 EL_EM_KEY_1_FILE_OBSOLETE,
4375 EL_EM_KEY_2_FILE_OBSOLETE,
4376 EL_EM_KEY_3_FILE_OBSOLETE,
4377 EL_EM_KEY_4_FILE_OBSOLETE,
4378 EL_ENVELOPE_OBSOLETE,
4387 } element_properties[] =
4389 { ep_diggable, EP_DIGGABLE },
4390 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4391 { ep_dont_run_into, EP_DONT_RUN_INTO },
4392 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4393 { ep_dont_touch, EP_DONT_TOUCH },
4394 { ep_indestructible, EP_INDESTRUCTIBLE },
4395 { ep_slippery, EP_SLIPPERY },
4396 { ep_can_change, EP_CAN_CHANGE },
4397 { ep_can_move, EP_CAN_MOVE },
4398 { ep_can_fall, EP_CAN_FALL },
4399 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4400 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4401 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4402 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4403 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4404 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4405 { ep_walkable_over, EP_WALKABLE_OVER },
4406 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4407 { ep_walkable_under, EP_WALKABLE_UNDER },
4408 { ep_passable_over, EP_PASSABLE_OVER },
4409 { ep_passable_inside, EP_PASSABLE_INSIDE },
4410 { ep_passable_under, EP_PASSABLE_UNDER },
4411 { ep_droppable, EP_DROPPABLE },
4412 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4413 { ep_pushable, EP_PUSHABLE },
4414 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4415 { ep_protected, EP_PROTECTED },
4416 { ep_throwable, EP_THROWABLE },
4417 { ep_can_explode, EP_CAN_EXPLODE },
4418 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4420 { ep_player, EP_PLAYER },
4421 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4422 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4423 { ep_switchable, EP_SWITCHABLE },
4424 { ep_bd_element, EP_BD_ELEMENT },
4425 { ep_sp_element, EP_SP_ELEMENT },
4426 { ep_sb_element, EP_SB_ELEMENT },
4428 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4429 { ep_food_penguin, EP_FOOD_PENGUIN },
4430 { ep_food_pig, EP_FOOD_PIG },
4431 { ep_historic_wall, EP_HISTORIC_WALL },
4432 { ep_historic_solid, EP_HISTORIC_SOLID },
4433 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4434 { ep_belt, EP_BELT },
4435 { ep_belt_active, EP_BELT_ACTIVE },
4436 { ep_belt_switch, EP_BELT_SWITCH },
4437 { ep_tube, EP_TUBE },
4438 { ep_acid_pool, EP_ACID_POOL },
4439 { ep_keygate, EP_KEYGATE },
4440 { ep_amoeboid, EP_AMOEBOID },
4441 { ep_amoebalive, EP_AMOEBALIVE },
4442 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4443 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4444 { ep_can_grow, EP_CAN_GROW },
4445 { ep_active_bomb, EP_ACTIVE_BOMB },
4446 { ep_inactive, EP_INACTIVE },
4448 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4450 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4452 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4453 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4455 { ep_obsolete, EP_OBSOLETE },
4462 // always start with reliable default values (element has no properties)
4463 // (but never initialize clipboard elements after the very first time)
4464 // (to be able to use clipboard elements between several levels)
4465 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4466 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4467 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4468 SET_PROPERTY(i, j, FALSE);
4470 // set all base element properties from above array definitions
4471 for (i = 0; element_properties[i].elements != NULL; i++)
4472 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4473 SET_PROPERTY((element_properties[i].elements)[j],
4474 element_properties[i].property, TRUE);
4476 // copy properties to some elements that are only stored in level file
4477 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4478 for (j = 0; copy_properties[j][0] != -1; j++)
4479 if (HAS_PROPERTY(copy_properties[j][0], i))
4480 for (k = 1; k <= 4; k++)
4481 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4483 // set static element properties that are not listed in array definitions
4484 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4485 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4487 clipboard_elements_initialized = TRUE;
4490 void InitElementPropertiesEngine(int engine_version)
4492 static int no_wall_properties[] =
4495 EP_COLLECTIBLE_ONLY,
4497 EP_DONT_COLLIDE_WITH,
4500 EP_CAN_SMASH_PLAYER,
4501 EP_CAN_SMASH_ENEMIES,
4502 EP_CAN_SMASH_EVERYTHING,
4507 EP_FOOD_DARK_YAMYAM,
4523 /* important: after initialization in InitElementPropertiesStatic(), the
4524 elements are not again initialized to a default value; therefore all
4525 changes have to make sure that they leave the element with a defined
4526 property (which means that conditional property changes must be set to
4527 a reliable default value before) */
4529 // resolve group elements
4530 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4531 ResolveGroupElement(EL_GROUP_START + i);
4533 // set all special, combined or engine dependent element properties
4534 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4536 // do not change (already initialized) clipboard elements here
4537 if (IS_CLIPBOARD_ELEMENT(i))
4540 // ---------- INACTIVE ----------------------------------------------------
4541 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4542 i <= EL_CHAR_END) ||
4543 (i >= EL_STEEL_CHAR_START &&
4544 i <= EL_STEEL_CHAR_END)));
4546 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4547 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4548 IS_WALKABLE_INSIDE(i) ||
4549 IS_WALKABLE_UNDER(i)));
4551 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4552 IS_PASSABLE_INSIDE(i) ||
4553 IS_PASSABLE_UNDER(i)));
4555 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4556 IS_PASSABLE_OVER(i)));
4558 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4559 IS_PASSABLE_INSIDE(i)));
4561 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4562 IS_PASSABLE_UNDER(i)));
4564 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4567 // ---------- COLLECTIBLE -------------------------------------------------
4568 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4572 // ---------- SNAPPABLE ---------------------------------------------------
4573 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4574 IS_COLLECTIBLE(i) ||
4578 // ---------- WALL --------------------------------------------------------
4579 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4581 for (j = 0; no_wall_properties[j] != -1; j++)
4582 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4583 i >= EL_FIRST_RUNTIME_UNREAL)
4584 SET_PROPERTY(i, EP_WALL, FALSE);
4586 if (IS_HISTORIC_WALL(i))
4587 SET_PROPERTY(i, EP_WALL, TRUE);
4589 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4590 if (engine_version < VERSION_IDENT(2,2,0,0))
4591 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4593 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4595 !IS_COLLECTIBLE(i)));
4597 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4598 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4599 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4601 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4604 // ---------- EXPLOSION_PROOF ---------------------------------------------
4606 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4607 else if (engine_version < VERSION_IDENT(2,2,0,0))
4608 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4610 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4614 if (IS_CUSTOM_ELEMENT(i))
4616 // these are additional properties which are initially false when set
4618 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4620 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4621 if (DONT_COLLIDE_WITH(i))
4622 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4624 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4625 if (CAN_SMASH_EVERYTHING(i))
4626 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4627 if (CAN_SMASH_ENEMIES(i))
4628 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4631 // ---------- CAN_SMASH ---------------------------------------------------
4632 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4633 CAN_SMASH_ENEMIES(i) ||
4634 CAN_SMASH_EVERYTHING(i)));
4636 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4637 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4638 EXPLODES_BY_FIRE(i)));
4640 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4641 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4642 EXPLODES_SMASHED(i)));
4644 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4645 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4646 EXPLODES_IMPACT(i)));
4648 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4649 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4651 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4652 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4653 i == EL_BLACK_ORB));
4655 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4656 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4658 IS_CUSTOM_ELEMENT(i)));
4660 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4661 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4662 i == EL_SP_ELECTRON));
4664 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4665 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4666 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4667 getMoveIntoAcidProperty(&level, i));
4669 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4670 if (MAYBE_DONT_COLLIDE_WITH(i))
4671 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4672 getDontCollideWithProperty(&level, i));
4674 // ---------- SP_PORT -----------------------------------------------------
4675 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4676 IS_PASSABLE_INSIDE(i)));
4678 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4679 for (j = 0; j < level.num_android_clone_elements; j++)
4680 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4682 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4684 // ---------- CAN_CHANGE --------------------------------------------------
4685 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4686 for (j = 0; j < element_info[i].num_change_pages; j++)
4687 if (element_info[i].change_page[j].can_change)
4688 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4690 // ---------- HAS_ACTION --------------------------------------------------
4691 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4692 for (j = 0; j < element_info[i].num_change_pages; j++)
4693 if (element_info[i].change_page[j].has_action)
4694 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4696 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4697 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4700 // ---------- GFX_CRUMBLED ------------------------------------------------
4701 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4702 element_info[i].crumbled[ACTION_DEFAULT] !=
4703 element_info[i].graphic[ACTION_DEFAULT]);
4705 // ---------- EDITOR_CASCADE ----------------------------------------------
4706 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4707 IS_EDITOR_CASCADE_INACTIVE(i)));
4710 // dynamically adjust element properties according to game engine version
4712 static int ep_em_slippery_wall[] =
4717 EL_EXPANDABLE_WALL_HORIZONTAL,
4718 EL_EXPANDABLE_WALL_VERTICAL,
4719 EL_EXPANDABLE_WALL_ANY,
4720 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4721 EL_EXPANDABLE_STEELWALL_VERTICAL,
4722 EL_EXPANDABLE_STEELWALL_ANY,
4723 EL_EXPANDABLE_STEELWALL_GROWING,
4727 static int ep_em_explodes_by_fire[] =
4730 EL_EM_DYNAMITE_ACTIVE,
4735 // special EM style gems behaviour
4736 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4737 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4738 level.em_slippery_gems);
4740 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4741 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4742 (level.em_slippery_gems &&
4743 engine_version > VERSION_IDENT(2,0,1,0)));
4745 // special EM style explosion behaviour regarding chain reactions
4746 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4747 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4748 level.em_explodes_by_fire);
4751 // this is needed because some graphics depend on element properties
4752 if (game_status == GAME_MODE_PLAYING)
4753 InitElementGraphicInfo();
4756 void InitElementPropertiesGfxElement(void)
4760 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4762 struct ElementInfo *ei = &element_info[i];
4764 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4768 static void InitGlobal(void)
4773 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4775 // check if element_name_info entry defined for each element in "main.h"
4776 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4777 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4779 element_info[i].token_name = element_name_info[i].token_name;
4780 element_info[i].class_name = element_name_info[i].class_name;
4781 element_info[i].editor_description= element_name_info[i].editor_description;
4784 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4786 // check if global_anim_name_info defined for each entry in "main.h"
4787 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4788 global_anim_name_info[i].token_name == NULL)
4789 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4791 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4794 // create hash from image config list
4795 image_config_hash = newSetupFileHash();
4796 for (i = 0; image_config[i].token != NULL; i++)
4797 setHashEntry(image_config_hash,
4798 image_config[i].token,
4799 image_config[i].value);
4801 // create hash from element token list
4802 element_token_hash = newSetupFileHash();
4803 for (i = 0; element_name_info[i].token_name != NULL; i++)
4804 setHashEntry(element_token_hash,
4805 element_name_info[i].token_name,
4808 // create hash from graphic token list
4809 graphic_token_hash = newSetupFileHash();
4810 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4811 if (strSuffix(image_config[i].value, ".png") ||
4812 strSuffix(image_config[i].value, ".pcx") ||
4813 strSuffix(image_config[i].value, ".wav") ||
4814 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4815 setHashEntry(graphic_token_hash,
4816 image_config[i].token,
4817 int2str(graphic++, 0));
4819 // create hash from font token list
4820 font_token_hash = newSetupFileHash();
4821 for (i = 0; font_info[i].token_name != NULL; i++)
4822 setHashEntry(font_token_hash,
4823 font_info[i].token_name,
4826 // set default filenames for all cloned graphics in static configuration
4827 for (i = 0; image_config[i].token != NULL; i++)
4829 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4831 char *token = image_config[i].token;
4832 char *token_clone_from = getStringCat2(token, ".clone_from");
4833 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4835 if (token_cloned != NULL)
4837 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4839 if (value_cloned != NULL)
4841 // set default filename in static configuration
4842 image_config[i].value = value_cloned;
4844 // set default filename in image config hash
4845 setHashEntry(image_config_hash, token, value_cloned);
4849 free(token_clone_from);
4853 // always start with reliable default values (all elements)
4854 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4855 ActiveElement[i] = i;
4857 // now add all entries that have an active state (active elements)
4858 for (i = 0; element_with_active_state[i].element != -1; i++)
4860 int element = element_with_active_state[i].element;
4861 int element_active = element_with_active_state[i].element_active;
4863 ActiveElement[element] = element_active;
4866 // always start with reliable default values (all buttons)
4867 for (i = 0; i < NUM_IMAGE_FILES; i++)
4868 ActiveButton[i] = i;
4870 // now add all entries that have an active state (active buttons)
4871 for (i = 0; button_with_active_state[i].button != -1; i++)
4873 int button = button_with_active_state[i].button;
4874 int button_active = button_with_active_state[i].button_active;
4876 ActiveButton[button] = button_active;
4879 // always start with reliable default values (all fonts)
4880 for (i = 0; i < NUM_FONTS; i++)
4883 // now add all entries that have an active state (active fonts)
4884 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4886 int font = font_with_active_state[i].font_nr;
4887 int font_active = font_with_active_state[i].font_nr_active;
4889 ActiveFont[font] = font_active;
4892 global.autoplay_leveldir = NULL;
4893 global.convert_leveldir = NULL;
4894 global.create_images_dir = NULL;
4896 global.frames_per_second = 0;
4897 global.show_frames_per_second = FALSE;
4899 global.border_status = GAME_MODE_LOADING;
4900 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4902 global.use_envelope_request = FALSE;
4905 static void Execute_Command(char *command)
4909 if (strEqual(command, "print graphicsinfo.conf"))
4911 Print("# You can configure additional/alternative image files here.\n");
4912 Print("# (The entries below are default and therefore commented out.)\n");
4914 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4916 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4919 for (i = 0; image_config[i].token != NULL; i++)
4920 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4921 image_config[i].value));
4925 else if (strEqual(command, "print soundsinfo.conf"))
4927 Print("# You can configure additional/alternative sound files here.\n");
4928 Print("# (The entries below are default and therefore commented out.)\n");
4930 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4932 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4935 for (i = 0; sound_config[i].token != NULL; i++)
4936 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4937 sound_config[i].value));
4941 else if (strEqual(command, "print musicinfo.conf"))
4943 Print("# You can configure additional/alternative music files here.\n");
4944 Print("# (The entries below are default and therefore commented out.)\n");
4946 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4948 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4951 for (i = 0; music_config[i].token != NULL; i++)
4952 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4953 music_config[i].value));
4957 else if (strEqual(command, "print editorsetup.conf"))
4959 Print("# You can configure your personal editor element list here.\n");
4960 Print("# (The entries below are default and therefore commented out.)\n");
4963 // this is needed to be able to check element list for cascade elements
4964 InitElementPropertiesStatic();
4965 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4967 PrintEditorElementList();
4971 else if (strEqual(command, "print helpanim.conf"))
4973 Print("# You can configure different element help animations here.\n");
4974 Print("# (The entries below are default and therefore commented out.)\n");
4977 for (i = 0; helpanim_config[i].token != NULL; i++)
4979 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4980 helpanim_config[i].value));
4982 if (strEqual(helpanim_config[i].token, "end"))
4988 else if (strEqual(command, "print helptext.conf"))
4990 Print("# You can configure different element help text here.\n");
4991 Print("# (The entries below are default and therefore commented out.)\n");
4994 for (i = 0; helptext_config[i].token != NULL; i++)
4995 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4996 helptext_config[i].value));
5000 else if (strPrefix(command, "dump level "))
5002 char *filename = &command[11];
5004 if (!fileExists(filename))
5005 Error(ERR_EXIT, "cannot open file '%s'", filename);
5007 LoadLevelFromFilename(&level, filename);
5012 else if (strPrefix(command, "dump tape "))
5014 char *filename = &command[10];
5016 if (!fileExists(filename))
5017 Error(ERR_EXIT, "cannot open file '%s'", filename);
5019 LoadTapeFromFilename(filename);
5024 else if (strPrefix(command, "autotest ") ||
5025 strPrefix(command, "autoplay ") ||
5026 strPrefix(command, "autoffwd ") ||
5027 strPrefix(command, "autowarp "))
5029 char *str_ptr = getStringCopy(&command[9]); // read command parameters
5031 global.autoplay_mode =
5032 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5033 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5034 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5035 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5036 AUTOPLAY_MODE_NONE);
5038 while (*str_ptr != '\0') // continue parsing string
5040 // cut leading whitespace from string, replace it by string terminator
5041 while (*str_ptr == ' ' || *str_ptr == '\t')
5044 if (*str_ptr == '\0') // end of string reached
5047 if (global.autoplay_leveldir == NULL) // read level set string
5049 global.autoplay_leveldir = str_ptr;
5050 global.autoplay_all = TRUE; // default: play all tapes
5052 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5053 global.autoplay_level[i] = FALSE;
5055 else // read level number string
5057 int level_nr = atoi(str_ptr); // get level_nr value
5059 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5060 global.autoplay_level[level_nr] = TRUE;
5062 global.autoplay_all = FALSE;
5065 // advance string pointer to the next whitespace (or end of string)
5066 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5070 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5071 program.headless = TRUE;
5073 else if (strPrefix(command, "convert "))
5075 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5076 char *str_ptr = strchr(str_copy, ' ');
5078 global.convert_leveldir = str_copy;
5079 global.convert_level_nr = -1;
5081 if (str_ptr != NULL) // level number follows
5083 *str_ptr++ = '\0'; // terminate leveldir string
5084 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5087 program.headless = TRUE;
5089 else if (strPrefix(command, "create images "))
5091 global.create_images_dir = getStringCopy(&command[14]);
5093 if (access(global.create_images_dir, W_OK) != 0)
5094 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5095 global.create_images_dir);
5097 else if (strPrefix(command, "create CE image "))
5099 CreateCustomElementImages(&command[16]);
5105 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5108 // disable networking if any valid command was recognized
5109 options.network = setup.network_mode = FALSE;
5112 static void InitSetup(void)
5114 LoadSetup(); // global setup info
5115 LoadSetup_AutoSetup(); // global auto setup info
5117 // set some options from setup file
5119 if (setup.options.verbose)
5120 options.verbose = TRUE;
5122 if (setup.debug.show_frames_per_second)
5123 global.show_frames_per_second = TRUE;
5126 static void InitGameInfo(void)
5128 game.restart_level = FALSE;
5129 game.restart_game_message = NULL;
5130 game.request_active = FALSE;
5133 static void InitPlayerInfo(void)
5137 // choose default local player
5138 local_player = &stored_player[0];
5140 for (i = 0; i < MAX_PLAYERS; i++)
5142 stored_player[i].connected_locally = FALSE;
5143 stored_player[i].connected_network = FALSE;
5146 local_player->connected_locally = TRUE;
5149 static void InitArtworkInfo(void)
5154 static char *get_string_in_brackets(char *string)
5156 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5158 sprintf(string_in_brackets, "[%s]", string);
5160 return string_in_brackets;
5163 static char *get_level_id_suffix(int id_nr)
5165 char *id_suffix = checked_malloc(1 + 3 + 1);
5167 if (id_nr < 0 || id_nr > 999)
5170 sprintf(id_suffix, ".%03d", id_nr);
5175 static void InitArtworkConfig(void)
5177 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5179 NUM_GLOBAL_ANIM_TOKENS + 1];
5180 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5181 NUM_GLOBAL_ANIM_TOKENS + 1];
5182 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5183 NUM_GLOBAL_ANIM_TOKENS + 1];
5184 static char *action_id_suffix[NUM_ACTIONS + 1];
5185 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5186 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5187 static char *level_id_suffix[MAX_LEVELS + 1];
5188 static char *dummy[1] = { NULL };
5189 static char *ignore_generic_tokens[] =
5194 "program_copyright",
5199 static char **ignore_image_tokens;
5200 static char **ignore_sound_tokens;
5201 static char **ignore_music_tokens;
5202 int num_ignore_generic_tokens;
5203 int num_ignore_image_tokens;
5204 int num_ignore_sound_tokens;
5205 int num_ignore_music_tokens;
5208 // dynamically determine list of generic tokens to be ignored
5209 num_ignore_generic_tokens = 0;
5210 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5211 num_ignore_generic_tokens++;
5213 // dynamically determine list of image tokens to be ignored
5214 num_ignore_image_tokens = num_ignore_generic_tokens;
5215 for (i = 0; image_config_vars[i].token != NULL; i++)
5216 num_ignore_image_tokens++;
5217 ignore_image_tokens =
5218 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5219 for (i = 0; i < num_ignore_generic_tokens; i++)
5220 ignore_image_tokens[i] = ignore_generic_tokens[i];
5221 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5222 ignore_image_tokens[num_ignore_generic_tokens + i] =
5223 image_config_vars[i].token;
5224 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5226 // dynamically determine list of sound tokens to be ignored
5227 num_ignore_sound_tokens = num_ignore_generic_tokens;
5228 ignore_sound_tokens =
5229 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5230 for (i = 0; i < num_ignore_generic_tokens; i++)
5231 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5232 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5234 // dynamically determine list of music tokens to be ignored
5235 num_ignore_music_tokens = num_ignore_generic_tokens;
5236 ignore_music_tokens =
5237 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5238 for (i = 0; i < num_ignore_generic_tokens; i++)
5239 ignore_music_tokens[i] = ignore_generic_tokens[i];
5240 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5242 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5243 image_id_prefix[i] = element_info[i].token_name;
5244 for (i = 0; i < NUM_FONTS; i++)
5245 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5246 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5247 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5248 global_anim_info[i].token_name;
5249 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5251 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5252 sound_id_prefix[i] = element_info[i].token_name;
5253 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5254 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5255 get_string_in_brackets(element_info[i].class_name);
5256 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5257 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5258 global_anim_info[i].token_name;
5259 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5261 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5262 music_id_prefix[i] = music_prefix_info[i].prefix;
5263 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5264 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5265 global_anim_info[i].token_name;
5266 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5268 for (i = 0; i < NUM_ACTIONS; i++)
5269 action_id_suffix[i] = element_action_info[i].suffix;
5270 action_id_suffix[NUM_ACTIONS] = NULL;
5272 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5273 direction_id_suffix[i] = element_direction_info[i].suffix;
5274 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5276 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5277 special_id_suffix[i] = special_suffix_info[i].suffix;
5278 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5280 for (i = 0; i < MAX_LEVELS; i++)
5281 level_id_suffix[i] = get_level_id_suffix(i);
5282 level_id_suffix[MAX_LEVELS] = NULL;
5284 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5285 image_id_prefix, action_id_suffix, direction_id_suffix,
5286 special_id_suffix, ignore_image_tokens);
5287 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5288 sound_id_prefix, action_id_suffix, dummy,
5289 special_id_suffix, ignore_sound_tokens);
5290 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5291 music_id_prefix, action_id_suffix, special_id_suffix,
5292 level_id_suffix, ignore_music_tokens);
5295 static void InitMixer(void)
5302 static void InitVideoOverlay(void)
5304 // if virtual buttons are not loaded from setup file, repeat initializing
5305 // virtual buttons grid with default values now that video is initialized
5306 if (!setup.touch.grid_initialized)
5309 InitTileCursorInfo();
5313 void InitGfxBuffers(void)
5315 static int win_xsize_last = -1;
5316 static int win_ysize_last = -1;
5318 // create additional image buffers for double-buffering and cross-fading
5320 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5322 // used to temporarily store the backbuffer -- only re-create if changed
5323 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5324 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5326 win_xsize_last = WIN_XSIZE;
5327 win_ysize_last = WIN_YSIZE;
5330 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5331 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5332 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5333 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5335 // initialize screen properties
5336 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5337 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5339 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5340 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5341 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5342 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5343 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5344 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5346 // required if door size definitions have changed
5347 InitGraphicCompatibilityInfo_Doors();
5349 InitGfxBuffers_EM();
5350 InitGfxBuffers_SP();
5353 static void InitGfx(void)
5355 struct GraphicInfo *graphic_info_last = graphic_info;
5356 char *filename_font_initial = NULL;
5357 char *filename_anim_initial = NULL;
5358 Bitmap *bitmap_font_initial = NULL;
5361 // determine settings for initial font (for displaying startup messages)
5362 for (i = 0; image_config[i].token != NULL; i++)
5364 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5366 char font_token[128];
5369 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5370 len_font_token = strlen(font_token);
5372 if (strEqual(image_config[i].token, font_token))
5373 filename_font_initial = image_config[i].value;
5374 else if (strlen(image_config[i].token) > len_font_token &&
5375 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5377 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5378 font_initial[j].src_x = atoi(image_config[i].value);
5379 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5380 font_initial[j].src_y = atoi(image_config[i].value);
5381 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5382 font_initial[j].width = atoi(image_config[i].value);
5383 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5384 font_initial[j].height = atoi(image_config[i].value);
5389 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5391 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5392 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5395 if (filename_font_initial == NULL) // should not happen
5396 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5399 InitGfxCustomArtworkInfo();
5400 InitGfxOtherSettings();
5402 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5404 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5405 font_initial[j].bitmap = bitmap_font_initial;
5407 InitFontGraphicInfo();
5411 DrawInitText("Loading graphics", 120, FC_GREEN);
5413 // initialize settings for busy animation with default values
5414 int parameter[NUM_GFX_ARGS];
5415 for (i = 0; i < NUM_GFX_ARGS; i++)
5416 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5417 image_config_suffix[i].token,
5418 image_config_suffix[i].type);
5420 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5421 int len_anim_token = strlen(anim_token);
5423 // read settings for busy animation from default custom artwork config
5424 char *gfx_config_filename = getPath3(options.graphics_directory,
5426 GRAPHICSINFO_FILENAME);
5428 if (fileExists(gfx_config_filename))
5430 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5432 if (setup_file_hash)
5434 char *filename = getHashEntry(setup_file_hash, anim_token);
5438 filename_anim_initial = getStringCopy(filename);
5440 for (j = 0; image_config_suffix[j].token != NULL; j++)
5442 int type = image_config_suffix[j].type;
5443 char *suffix = image_config_suffix[j].token;
5444 char *token = getStringCat2(anim_token, suffix);
5445 char *value = getHashEntry(setup_file_hash, token);
5447 checked_free(token);
5450 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5454 freeSetupFileHash(setup_file_hash);
5458 if (filename_anim_initial == NULL)
5460 // read settings for busy animation from static default artwork config
5461 for (i = 0; image_config[i].token != NULL; i++)
5463 if (strEqual(image_config[i].token, anim_token))
5464 filename_anim_initial = getStringCopy(image_config[i].value);
5465 else if (strlen(image_config[i].token) > len_anim_token &&
5466 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5468 for (j = 0; image_config_suffix[j].token != NULL; j++)
5470 if (strEqual(&image_config[i].token[len_anim_token],
5471 image_config_suffix[j].token))
5473 get_graphic_parameter_value(image_config[i].value,
5474 image_config_suffix[j].token,
5475 image_config_suffix[j].type);
5481 if (filename_anim_initial == NULL) // should not happen
5482 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5484 anim_initial.bitmaps =
5485 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5487 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5488 LoadCustomImage(filename_anim_initial);
5490 checked_free(filename_anim_initial);
5492 graphic_info = &anim_initial; // graphic == 0 => anim_initial
5494 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5496 graphic_info = graphic_info_last;
5498 init.busy.width = anim_initial.width;
5499 init.busy.height = anim_initial.height;
5501 InitMenuDesignSettings_Static();
5503 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5504 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5505 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5506 InitGfxDrawTileCursorFunction(DrawTileCursor);
5508 gfx.fade_border_source_status = global.border_status;
5509 gfx.fade_border_target_status = global.border_status;
5510 gfx.masked_border_bitmap_ptr = backbuffer;
5512 // use copy of busy animation to prevent change while reloading artwork
5516 static void InitGfxBackground(void)
5518 fieldbuffer = bitmap_db_field;
5519 SetDrawtoField(DRAW_TO_BACKBUFFER);
5521 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5523 redraw_mask = REDRAW_ALL;
5526 static void InitLevelInfo(void)
5528 LoadLevelInfo(); // global level info
5529 LoadLevelSetup_LastSeries(); // last played series info
5530 LoadLevelSetup_SeriesInfo(); // last played level info
5532 if (global.autoplay_leveldir &&
5533 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5535 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5536 global.autoplay_leveldir);
5537 if (leveldir_current == NULL)
5538 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5541 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5544 static void InitLevelArtworkInfo(void)
5546 LoadLevelArtworkInfo();
5549 static void InitImages(void)
5551 print_timestamp_init("InitImages");
5554 printf("::: leveldir_current->identifier == '%s'\n",
5555 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5556 printf("::: leveldir_current->graphics_path == '%s'\n",
5557 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5558 printf("::: leveldir_current->graphics_set == '%s'\n",
5559 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5560 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5561 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5564 setLevelArtworkDir(artwork.gfx_first);
5567 printf("::: leveldir_current->identifier == '%s'\n",
5568 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5569 printf("::: leveldir_current->graphics_path == '%s'\n",
5570 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5571 printf("::: leveldir_current->graphics_set == '%s'\n",
5572 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5573 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5574 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5578 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5579 leveldir_current->identifier,
5580 artwork.gfx_current_identifier,
5581 artwork.gfx_current->identifier,
5582 leveldir_current->graphics_set,
5583 leveldir_current->graphics_path);
5586 UPDATE_BUSY_STATE();
5588 ReloadCustomImages();
5589 print_timestamp_time("ReloadCustomImages");
5591 UPDATE_BUSY_STATE();
5593 LoadCustomElementDescriptions();
5594 print_timestamp_time("LoadCustomElementDescriptions");
5596 UPDATE_BUSY_STATE();
5598 LoadMenuDesignSettings();
5599 print_timestamp_time("LoadMenuDesignSettings");
5601 UPDATE_BUSY_STATE();
5603 ReinitializeGraphics();
5604 print_timestamp_time("ReinitializeGraphics");
5606 LoadMenuDesignSettings_AfterGraphics();
5607 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5609 UPDATE_BUSY_STATE();
5611 print_timestamp_done("InitImages");
5614 static void InitSound(char *identifier)
5616 print_timestamp_init("InitSound");
5618 if (identifier == NULL)
5619 identifier = artwork.snd_current->identifier;
5621 // set artwork path to send it to the sound server process
5622 setLevelArtworkDir(artwork.snd_first);
5624 InitReloadCustomSounds(identifier);
5625 print_timestamp_time("InitReloadCustomSounds");
5627 ReinitializeSounds();
5628 print_timestamp_time("ReinitializeSounds");
5630 print_timestamp_done("InitSound");
5633 static void InitMusic(char *identifier)
5635 print_timestamp_init("InitMusic");
5637 if (identifier == NULL)
5638 identifier = artwork.mus_current->identifier;
5640 // set artwork path to send it to the sound server process
5641 setLevelArtworkDir(artwork.mus_first);
5643 InitReloadCustomMusic(identifier);
5644 print_timestamp_time("InitReloadCustomMusic");
5646 ReinitializeMusic();
5647 print_timestamp_time("ReinitializeMusic");
5649 print_timestamp_done("InitMusic");
5652 static void InitArtworkDone(void)
5654 if (program.headless)
5657 InitGlobalAnimations();
5660 static void InitNetworkSettings(void)
5662 boolean network_enabled = (options.network || setup.network_mode);
5663 char *network_server = (options.server_host != NULL ? options.server_host :
5664 setup.network_server_hostname);
5666 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5667 network_server = NULL;
5669 InitNetworkInfo(network_enabled,
5673 options.server_port);
5676 void InitNetworkServer(void)
5678 if (!network.enabled || network.connected)
5681 LimitScreenUpdates(FALSE);
5683 if (game_status == GAME_MODE_LOADING)
5686 if (!ConnectToServer(network.server_host, network.server_port))
5688 network.enabled = FALSE;
5690 setup.network_mode = FALSE;
5694 SendToServer_ProtocolVersion();
5695 SendToServer_PlayerName(setup.player_name);
5696 SendToServer_NrWanted(setup.network_player_nr + 1);
5698 network.connected = TRUE;
5701 // short time to recognize result of network initialization
5702 if (game_status == GAME_MODE_LOADING)
5703 Delay_WithScreenUpdates(1000);
5706 static boolean CheckArtworkConfigForCustomElements(char *filename)
5708 SetupFileHash *setup_file_hash;
5709 boolean redefined_ce_found = FALSE;
5711 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5713 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5715 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5717 char *token = HASH_ITERATION_TOKEN(itr);
5719 if (strPrefix(token, "custom_"))
5721 redefined_ce_found = TRUE;
5726 END_HASH_ITERATION(setup_file_hash, itr)
5728 freeSetupFileHash(setup_file_hash);
5731 return redefined_ce_found;
5734 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5736 char *filename_base, *filename_local;
5737 boolean redefined_ce_found = FALSE;
5739 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5742 printf("::: leveldir_current->identifier == '%s'\n",
5743 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5744 printf("::: leveldir_current->graphics_path == '%s'\n",
5745 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5746 printf("::: leveldir_current->graphics_set == '%s'\n",
5747 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5748 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5749 leveldir_current == NULL ? "[NULL]" :
5750 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5753 // first look for special artwork configured in level series config
5754 filename_base = getCustomArtworkLevelConfigFilename(type);
5757 printf("::: filename_base == '%s'\n", filename_base);
5760 if (fileExists(filename_base))
5761 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5763 filename_local = getCustomArtworkConfigFilename(type);
5766 printf("::: filename_local == '%s'\n", filename_local);
5769 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5770 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5773 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5776 return redefined_ce_found;
5779 static void InitOverrideArtwork(void)
5781 boolean redefined_ce_found = FALSE;
5783 // to check if this level set redefines any CEs, do not use overriding
5784 gfx.override_level_graphics = FALSE;
5785 gfx.override_level_sounds = FALSE;
5786 gfx.override_level_music = FALSE;
5788 // now check if this level set has definitions for custom elements
5789 if (setup.override_level_graphics == AUTO ||
5790 setup.override_level_sounds == AUTO ||
5791 setup.override_level_music == AUTO)
5792 redefined_ce_found =
5793 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5794 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5795 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5798 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5801 if (redefined_ce_found)
5803 // this level set has CE definitions: change "AUTO" to "FALSE"
5804 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5805 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5806 gfx.override_level_music = (setup.override_level_music == TRUE);
5810 // this level set has no CE definitions: change "AUTO" to "TRUE"
5811 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5812 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5813 gfx.override_level_music = (setup.override_level_music != FALSE);
5817 printf("::: => %d, %d, %d\n",
5818 gfx.override_level_graphics,
5819 gfx.override_level_sounds,
5820 gfx.override_level_music);
5824 static char *getNewArtworkIdentifier(int type)
5826 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5827 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5828 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5829 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5830 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5831 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5832 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5833 char *leveldir_identifier = leveldir_current->identifier;
5834 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
5835 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5836 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5837 char *artwork_current_identifier;
5838 char *artwork_new_identifier = NULL; // default: nothing has changed
5840 // leveldir_current may be invalid (level group, parent link)
5841 if (!validLevelSeries(leveldir_current))
5844 /* 1st step: determine artwork set to be activated in descending order:
5845 --------------------------------------------------------------------
5846 1. setup artwork (when configured to override everything else)
5847 2. artwork set configured in "levelinfo.conf" of current level set
5848 (artwork in level directory will have priority when loading later)
5849 3. artwork in level directory (stored in artwork sub-directory)
5850 4. setup artwork (currently configured in setup menu) */
5852 if (setup_override_artwork)
5853 artwork_current_identifier = setup_artwork_set;
5854 else if (leveldir_artwork_set != NULL)
5855 artwork_current_identifier = leveldir_artwork_set;
5856 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5857 artwork_current_identifier = leveldir_identifier;
5859 artwork_current_identifier = setup_artwork_set;
5862 /* 2nd step: check if it is really needed to reload artwork set
5863 ------------------------------------------------------------ */
5865 // ---------- reload if level set and also artwork set has changed ----------
5866 if (leveldir_current_identifier[type] != leveldir_identifier &&
5867 (last_has_level_artwork_set[type] || has_level_artwork_set))
5868 artwork_new_identifier = artwork_current_identifier;
5870 leveldir_current_identifier[type] = leveldir_identifier;
5871 last_has_level_artwork_set[type] = has_level_artwork_set;
5873 // ---------- reload if "override artwork" setting has changed --------------
5874 if (last_override_level_artwork[type] != setup_override_artwork)
5875 artwork_new_identifier = artwork_current_identifier;
5877 last_override_level_artwork[type] = setup_override_artwork;
5879 // ---------- reload if current artwork identifier has changed --------------
5880 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5881 artwork_current_identifier))
5882 artwork_new_identifier = artwork_current_identifier;
5884 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5886 // ---------- do not reload directly after starting -------------------------
5887 if (!initialized[type])
5888 artwork_new_identifier = NULL;
5890 initialized[type] = TRUE;
5892 return artwork_new_identifier;
5895 void ReloadCustomArtwork(int force_reload)
5897 int last_game_status = game_status; // save current game status
5898 char *gfx_new_identifier;
5899 char *snd_new_identifier;
5900 char *mus_new_identifier;
5901 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5902 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5903 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5904 boolean reload_needed;
5906 InitOverrideArtwork();
5908 force_reload_gfx |= AdjustGraphicsForEMC();
5910 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5911 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5912 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5914 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5915 snd_new_identifier != NULL || force_reload_snd ||
5916 mus_new_identifier != NULL || force_reload_mus);
5921 print_timestamp_init("ReloadCustomArtwork");
5923 SetGameStatus(GAME_MODE_LOADING);
5925 FadeOut(REDRAW_ALL);
5927 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5928 print_timestamp_time("ClearRectangle");
5932 if (gfx_new_identifier != NULL || force_reload_gfx)
5935 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5936 artwork.gfx_current_identifier,
5938 artwork.gfx_current->identifier,
5939 leveldir_current->graphics_set);
5943 print_timestamp_time("InitImages");
5946 if (snd_new_identifier != NULL || force_reload_snd)
5948 InitSound(snd_new_identifier);
5949 print_timestamp_time("InitSound");
5952 if (mus_new_identifier != NULL || force_reload_mus)
5954 InitMusic(mus_new_identifier);
5955 print_timestamp_time("InitMusic");
5960 SetGameStatus(last_game_status); // restore current game status
5962 init_last = init; // switch to new busy animation
5964 FadeOut(REDRAW_ALL);
5966 RedrawGlobalBorder();
5968 // force redraw of (open or closed) door graphics
5969 SetDoorState(DOOR_OPEN_ALL);
5970 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5972 FadeSetEnterScreen();
5973 FadeSkipNextFadeOut();
5975 print_timestamp_done("ReloadCustomArtwork");
5977 LimitScreenUpdates(FALSE);
5980 void KeyboardAutoRepeatOffUnlessAutoplay(void)
5982 if (global.autoplay_leveldir == NULL)
5983 KeyboardAutoRepeatOff();
5986 void DisplayExitMessage(char *format, va_list ap)
5988 // also check for initialized video (headless flag may be temporarily unset)
5989 if (program.headless || !video.initialized)
5992 // check if draw buffer and fonts for exit message are already available
5993 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5996 int font_1 = FC_RED;
5997 int font_2 = FC_YELLOW;
5998 int font_3 = FC_BLUE;
5999 int font_width = getFontWidth(font_2);
6000 int font_height = getFontHeight(font_2);
6003 int sxsize = WIN_XSIZE - 2 * sx;
6004 int sysize = WIN_YSIZE - 2 * sy;
6005 int line_length = sxsize / font_width;
6006 int max_lines = sysize / font_height;
6007 int num_lines_printed;
6011 gfx.sxsize = sxsize;
6012 gfx.sysize = sysize;
6016 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6018 DrawTextSCentered(sy, font_1, "Fatal error:");
6019 sy += 3 * font_height;;
6022 DrawTextBufferVA(sx, sy, format, ap, font_2,
6023 line_length, line_length, max_lines,
6024 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6025 sy += (num_lines_printed + 3) * font_height;
6027 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6028 sy += 3 * font_height;
6031 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6032 line_length, line_length, max_lines,
6033 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6035 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6037 redraw_mask = REDRAW_ALL;
6039 // force drawing exit message even if screen updates are currently limited
6040 LimitScreenUpdates(FALSE);
6044 // deactivate toons on error message screen
6045 setup.toons = FALSE;
6047 WaitForEventToContinue();
6051 // ============================================================================
6053 // ============================================================================
6057 print_timestamp_init("OpenAll");
6059 SetGameStatus(GAME_MODE_LOADING);
6063 InitGlobal(); // initialize some global variables
6065 print_timestamp_time("[init global stuff]");
6069 print_timestamp_time("[init setup/config stuff (1)]");
6073 if (options.execute_command)
6074 Execute_Command(options.execute_command);
6076 InitNetworkSettings();
6080 if (network.serveronly)
6082 #if defined(PLATFORM_UNIX)
6083 NetworkServer(network.server_port, TRUE);
6085 Error(ERR_WARN, "networking only supported in Unix version");
6088 exit(0); // never reached, server loops forever
6092 print_timestamp_time("[init setup/config stuff (2)]");
6094 print_timestamp_time("[init setup/config stuff (3)]");
6095 InitArtworkInfo(); // needed before loading gfx, sound & music
6096 print_timestamp_time("[init setup/config stuff (4)]");
6097 InitArtworkConfig(); // needed before forking sound child process
6098 print_timestamp_time("[init setup/config stuff (5)]");
6100 print_timestamp_time("[init setup/config stuff (6)]");
6102 InitRND(NEW_RANDOMIZE);
6103 InitSimpleRandom(NEW_RANDOMIZE);
6107 print_timestamp_time("[init setup/config stuff]");
6109 InitVideoDefaults();
6111 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6114 InitEventFilter(FilterMouseMotionEvents);
6116 print_timestamp_time("[init video stuff]");
6118 InitElementPropertiesStatic();
6119 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6120 InitElementPropertiesGfxElement();
6122 print_timestamp_time("[init element properties stuff]");
6126 print_timestamp_time("InitGfx");
6129 print_timestamp_time("InitLevelInfo");
6131 InitLevelArtworkInfo();
6132 print_timestamp_time("InitLevelArtworkInfo");
6134 InitOverrideArtwork(); // needs to know current level directory
6135 print_timestamp_time("InitOverrideArtwork");
6137 InitImages(); // needs to know current level directory
6138 print_timestamp_time("InitImages");
6140 InitSound(NULL); // needs to know current level directory
6141 print_timestamp_time("InitSound");
6143 InitMusic(NULL); // needs to know current level directory
6144 print_timestamp_time("InitMusic");
6148 InitGfxBackground();
6154 if (global.autoplay_leveldir)
6159 else if (global.convert_leveldir)
6164 else if (global.create_images_dir)
6166 CreateLevelSketchImages();
6170 InitNetworkServer();
6172 SetGameStatus(GAME_MODE_MAIN);
6174 FadeSetEnterScreen();
6175 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6176 FadeSkipNextFadeOut();
6178 print_timestamp_time("[post-artwork]");
6180 print_timestamp_done("OpenAll");
6185 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6187 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6188 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6189 #if defined(PLATFORM_ANDROID)
6190 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6191 SDL_AndroidGetInternalStoragePath());
6192 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6193 SDL_AndroidGetExternalStoragePath());
6194 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6195 (SDL_AndroidGetExternalStorageState() &
6196 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6197 SDL_AndroidGetExternalStorageState() &
6198 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6203 void CloseAllAndExit(int exit_value)
6208 CloseAudio(); // called after freeing sounds (needed for SDL)
6216 // set a flag to tell the network server thread to quit and wait for it
6217 // using SDL_WaitThread()
6219 // Code used with SDL 1.2:
6220 // if (network_server) // terminate network server
6221 // SDL_KillThread(server_thread);
6223 CloseVideoDisplay();
6224 ClosePlatformDependentStuff();
6226 if (exit_value != 0 && !options.execute_command)
6228 // fall back to default level set (current set may have caused an error)
6229 SaveLevelSetup_LastSeries_Deactivate();
6231 // tell user where to find error log file which may contain more details
6232 // (error notification now directly displayed on screen inside R'n'D
6233 // NotifyUserAboutErrorFile(); // currently only works for Windows