1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #include "conf_e2g.c" // include auto-generated data structure definitions
28 #include "conf_esg.c" // include auto-generated data structure definitions
29 #include "conf_e2s.c" // include auto-generated data structure definitions
30 #include "conf_fnt.c" // include auto-generated data structure definitions
31 #include "conf_g2s.c" // include auto-generated data structure definitions
32 #include "conf_g2m.c" // include auto-generated data structure definitions
33 #include "conf_act.c" // include auto-generated data structure definitions
36 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41 static struct GraphicInfo anim_initial;
43 static int copy_properties[][5] =
47 EL_BUG_LEFT, EL_BUG_RIGHT,
48 EL_BUG_UP, EL_BUG_DOWN
52 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
53 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
57 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
58 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
62 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
63 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
67 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
68 EL_PACMAN_UP, EL_PACMAN_DOWN
72 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
73 EL_YAMYAM_UP, EL_YAMYAM_DOWN
77 EL_MOLE_LEFT, EL_MOLE_RIGHT,
78 EL_MOLE_UP, EL_MOLE_DOWN
87 // forward declaration for internal use
88 static int get_graphic_parameter_value(char *, char *, int);
91 static void DrawInitAnim(void)
93 struct GraphicInfo *graphic_info_last = graphic_info;
95 static unsigned int action_delay = 0;
96 unsigned int action_delay_value = GameFrameDelay;
97 int sync_frame = FrameCounter;
100 // prevent OS (Windows) from complaining about program not responding
103 if (game_status != GAME_MODE_LOADING)
106 if (anim_initial.bitmap == NULL || window == NULL)
109 if (!DelayReached(&action_delay, action_delay_value))
112 if (init_last.busy.x == -1)
113 init_last.busy.x = WIN_XSIZE / 2;
114 if (init_last.busy.y == -1)
115 init_last.busy.y = WIN_YSIZE / 2;
117 x = ALIGNED_TEXT_XPOS(&init_last.busy);
118 y = ALIGNED_TEXT_YPOS(&init_last.busy);
120 graphic_info = &anim_initial; // graphic == 0 => anim_initial
122 if (sync_frame % anim_initial.anim_delay == 0)
126 int width = graphic_info[graphic].width;
127 int height = graphic_info[graphic].height;
128 int frame = getGraphicAnimationFrame(graphic, sync_frame);
130 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
131 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
134 graphic_info = graphic_info_last;
139 static void DrawProgramInfo(void)
141 int font1_nr = FC_YELLOW;
142 int font2_nr = FC_RED;
143 int font2_height = getFontHeight(font2_nr);
146 int ypos3 = WIN_YSIZE - 20 - font2_height;
148 DrawInitText(getProgramInitString(), ypos1, font1_nr);
149 DrawInitText(setup.internal.program_copyright, ypos2, font2_nr);
150 DrawInitText(setup.internal.program_website, ypos3, font2_nr);
153 static void FreeGadgets(void)
155 FreeLevelEditorGadgets();
162 void InitGadgets(void)
164 static boolean gadgets_initialized = FALSE;
166 if (gadgets_initialized)
169 CreateLevelEditorGadgets();
173 CreateScreenGadgets();
175 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
177 gadgets_initialized = TRUE;
180 static void InitElementSmallImagesScaledUp(int graphic)
182 struct GraphicInfo *g = &graphic_info[graphic];
184 // create small and game tile sized bitmaps (and scale up, if needed)
185 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
188 static void InitElementSmallImages(void)
190 print_timestamp_init("InitElementSmallImages");
192 static int special_graphics[] =
206 IMG_EDITOR_ELEMENT_BORDER,
207 IMG_EDITOR_ELEMENT_BORDER_INPUT,
208 IMG_EDITOR_CASCADE_LIST,
209 IMG_EDITOR_CASCADE_LIST_ACTIVE,
212 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
213 int num_property_mappings = getImageListPropertyMappingSize();
216 print_timestamp_time("getImageListPropertyMapping/Size");
218 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
219 // initialize normal element images from static configuration
220 for (i = 0; element_to_graphic[i].element > -1; i++)
221 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
222 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
224 // initialize special element images from static configuration
225 for (i = 0; element_to_special_graphic[i].element > -1; i++)
226 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
227 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
229 // initialize element images from dynamic configuration
230 for (i = 0; i < num_property_mappings; i++)
231 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
232 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
233 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
235 // initialize special non-element images from above list
236 for (i = 0; special_graphics[i] > -1; i++)
237 InitElementSmallImagesScaledUp(special_graphics[i]);
238 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
240 print_timestamp_done("InitElementSmallImages");
243 static void InitScaledImagesScaledUp(int graphic)
245 struct GraphicInfo *g = &graphic_info[graphic];
247 ScaleImage(graphic, g->scale_up_factor);
250 static void InitScaledImages(void)
252 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
253 int num_property_mappings = getImageListPropertyMappingSize();
256 // scale normal images from static configuration, if not already scaled
257 for (i = 0; i < NUM_IMAGE_FILES; i++)
258 InitScaledImagesScaledUp(i);
260 // scale images from dynamic configuration, if not already scaled
261 for (i = 0; i < num_property_mappings; i++)
262 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
265 static void InitBitmapPointers(void)
267 int num_images = getImageListSize();
270 // standard size bitmap may have changed -- update default bitmap pointer
271 for (i = 0; i < num_images; i++)
272 if (graphic_info[i].bitmaps)
273 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
276 void InitImageTextures(void)
280 FreeAllImageTextures();
282 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
283 CreateImageTextures(i);
285 for (i = 0; i < MAX_NUM_TOONS; i++)
286 CreateImageTextures(IMG_TOON_1 + i);
288 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
290 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
292 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
294 int graphic = global_anim_info[i].graphic[j][k];
296 if (graphic == IMG_UNDEFINED)
299 CreateImageTextures(graphic);
306 // !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!!
307 void SetBitmaps_EM(Bitmap **em_bitmap)
309 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
310 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
315 // !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!!
316 void SetBitmaps_SP(Bitmap **sp_bitmap)
318 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
322 static int getFontBitmapID(int font_nr)
326 // (special case: do not use special font for GAME_MODE_LOADING)
327 if (game_status >= GAME_MODE_TITLE_INITIAL &&
328 game_status <= GAME_MODE_PSEUDO_PREVIEW)
329 special = game_status;
330 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
331 special = GFX_SPECIAL_ARG_MAIN;
334 return font_info[font_nr].special_bitmap_id[special];
339 static int getFontFromToken(char *token)
341 char *value = getHashEntry(font_token_hash, token);
346 // if font not found, use reliable default value
347 return FONT_INITIAL_1;
350 static void InitFontGraphicInfo(void)
352 static struct FontBitmapInfo *font_bitmap_info = NULL;
353 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
354 int num_property_mappings = getImageListPropertyMappingSize();
355 int num_font_bitmaps = NUM_FONTS;
358 if (graphic_info == NULL) // still at startup phase
360 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
361 getFontBitmapID, getFontFromToken);
366 // ---------- initialize font graphic definitions ----------
368 // always start with reliable default values (normal font graphics)
369 for (i = 0; i < NUM_FONTS; i++)
370 font_info[i].graphic = IMG_FONT_INITIAL_1;
372 // initialize normal font/graphic mapping from static configuration
373 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
375 int font_nr = font_to_graphic[i].font_nr;
376 int special = font_to_graphic[i].special;
377 int graphic = font_to_graphic[i].graphic;
382 font_info[font_nr].graphic = graphic;
385 // always start with reliable default values (special font graphics)
386 for (i = 0; i < NUM_FONTS; i++)
388 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
390 font_info[i].special_graphic[j] = font_info[i].graphic;
391 font_info[i].special_bitmap_id[j] = i;
395 // initialize special font/graphic mapping from static configuration
396 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
398 int font_nr = font_to_graphic[i].font_nr;
399 int special = font_to_graphic[i].special;
400 int graphic = font_to_graphic[i].graphic;
401 int base_graphic = font2baseimg(font_nr);
403 if (IS_SPECIAL_GFX_ARG(special))
405 boolean base_redefined =
406 getImageListEntryFromImageID(base_graphic)->redefined;
407 boolean special_redefined =
408 getImageListEntryFromImageID(graphic)->redefined;
409 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
411 /* if the base font ("font.title_1", for example) has been redefined,
412 but not the special font ("font.title_1.LEVELS", for example), do not
413 use an existing (in this case considered obsolete) special font
414 anymore, but use the automatically determined default font */
415 /* special case: cloned special fonts must be explicitly redefined,
416 but are not automatically redefined by redefining base font */
417 if (base_redefined && !special_redefined && !special_cloned)
420 font_info[font_nr].special_graphic[special] = graphic;
421 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
426 // initialize special font/graphic mapping from dynamic configuration
427 for (i = 0; i < num_property_mappings; i++)
429 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
430 int special = property_mapping[i].ext3_index;
431 int graphic = property_mapping[i].artwork_index;
433 if (font_nr < 0 || font_nr >= NUM_FONTS)
436 if (IS_SPECIAL_GFX_ARG(special))
438 font_info[font_nr].special_graphic[special] = graphic;
439 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
444 /* correct special font/graphic mapping for cloned fonts for downwards
445 compatibility of PREVIEW fonts -- this is only needed for implicit
446 redefinition of special font by redefined base font, and only if other
447 fonts are cloned from this special font (like in the "Zelda" level set) */
448 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
450 int font_nr = font_to_graphic[i].font_nr;
451 int special = font_to_graphic[i].special;
452 int graphic = font_to_graphic[i].graphic;
454 if (IS_SPECIAL_GFX_ARG(special))
456 boolean special_redefined =
457 getImageListEntryFromImageID(graphic)->redefined;
458 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
460 if (special_cloned && !special_redefined)
464 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
466 int font_nr2 = font_to_graphic[j].font_nr;
467 int special2 = font_to_graphic[j].special;
468 int graphic2 = font_to_graphic[j].graphic;
470 if (IS_SPECIAL_GFX_ARG(special2) &&
471 graphic2 == graphic_info[graphic].clone_from)
473 font_info[font_nr].special_graphic[special] =
474 font_info[font_nr2].special_graphic[special2];
475 font_info[font_nr].special_bitmap_id[special] =
476 font_info[font_nr2].special_bitmap_id[special2];
483 // reset non-redefined ".active" font graphics if normal font is redefined
484 // (this different treatment is needed because normal and active fonts are
485 // independently defined ("active" is not a property of font definitions!)
486 for (i = 0; i < NUM_FONTS; i++)
488 int font_nr_base = i;
489 int font_nr_active = FONT_ACTIVE(font_nr_base);
491 // check only those fonts with exist as normal and ".active" variant
492 if (font_nr_base != font_nr_active)
494 int base_graphic = font_info[font_nr_base].graphic;
495 int active_graphic = font_info[font_nr_active].graphic;
496 boolean base_redefined =
497 getImageListEntryFromImageID(base_graphic)->redefined;
498 boolean active_redefined =
499 getImageListEntryFromImageID(active_graphic)->redefined;
501 /* if the base font ("font.menu_1", for example) has been redefined,
502 but not the active font ("font.menu_1.active", for example), do not
503 use an existing (in this case considered obsolete) active font
504 anymore, but use the automatically determined default font */
505 if (base_redefined && !active_redefined)
506 font_info[font_nr_active].graphic = base_graphic;
508 // now also check each "special" font (which may be the same as above)
509 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
511 int base_graphic = font_info[font_nr_base].special_graphic[j];
512 int active_graphic = font_info[font_nr_active].special_graphic[j];
513 boolean base_redefined =
514 getImageListEntryFromImageID(base_graphic)->redefined;
515 boolean active_redefined =
516 getImageListEntryFromImageID(active_graphic)->redefined;
518 // same as above, but check special graphic definitions, for example:
519 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
520 if (base_redefined && !active_redefined)
522 font_info[font_nr_active].special_graphic[j] =
523 font_info[font_nr_base].special_graphic[j];
524 font_info[font_nr_active].special_bitmap_id[j] =
525 font_info[font_nr_base].special_bitmap_id[j];
531 // ---------- initialize font bitmap array ----------
533 if (font_bitmap_info != NULL)
534 FreeFontInfo(font_bitmap_info);
537 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
539 // ---------- initialize font bitmap definitions ----------
541 for (i = 0; i < NUM_FONTS; i++)
543 if (i < NUM_INITIAL_FONTS)
545 font_bitmap_info[i] = font_initial[i];
549 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
551 int font_bitmap_id = font_info[i].special_bitmap_id[j];
552 int graphic = font_info[i].special_graphic[j];
554 // set 'graphic_info' for font entries, if uninitialized (guessed)
555 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
557 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
558 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
561 // copy font relevant information from graphics information
562 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
563 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
564 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
565 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
566 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
568 font_bitmap_info[font_bitmap_id].offset_x =
569 graphic_info[graphic].offset_x;
570 font_bitmap_info[font_bitmap_id].offset_y =
571 graphic_info[graphic].offset_y;
573 font_bitmap_info[font_bitmap_id].draw_xoffset =
574 graphic_info[graphic].draw_xoffset;
575 font_bitmap_info[font_bitmap_id].draw_yoffset =
576 graphic_info[graphic].draw_yoffset;
578 font_bitmap_info[font_bitmap_id].num_chars =
579 graphic_info[graphic].anim_frames;
580 font_bitmap_info[font_bitmap_id].num_chars_per_line =
581 graphic_info[graphic].anim_frames_per_line;
585 InitFontInfo(font_bitmap_info, num_font_bitmaps,
586 getFontBitmapID, getFontFromToken);
589 static void InitGlobalAnimGraphicInfo(void)
591 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
592 int num_property_mappings = getImageListPropertyMappingSize();
595 if (graphic_info == NULL) // still at startup phase
598 // always start with reliable default values (no global animations)
599 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
600 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
601 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
602 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
604 // initialize global animation definitions from static configuration
605 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
607 int j = GLOBAL_ANIM_ID_PART_BASE;
608 int k = GFX_SPECIAL_ARG_DEFAULT;
610 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
613 // initialize global animation definitions from dynamic configuration
614 for (i = 0; i < num_property_mappings; i++)
616 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
617 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
618 int special = property_mapping[i].ext3_index;
619 int graphic = property_mapping[i].artwork_index;
621 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
624 // set animation part to base part, if not specified
625 if (!IS_GLOBAL_ANIM_PART(part_nr))
626 part_nr = GLOBAL_ANIM_ID_PART_BASE;
628 // set animation screen to default, if not specified
629 if (!IS_SPECIAL_GFX_ARG(special))
630 special = GFX_SPECIAL_ARG_DEFAULT;
632 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
634 // fix default value for ".draw_masked" (for backward compatibility)
635 struct GraphicInfo *g = &graphic_info[graphic];
636 struct FileInfo *image = getImageListEntryFromImageID(graphic);
637 char **parameter_raw = image->parameter;
638 int p = GFX_ARG_DRAW_MASKED;
639 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
640 image_config_suffix[p].token,
641 image_config_suffix[p].type);
643 // if ".draw_masked" parameter is undefined, use default value "TRUE"
644 if (draw_masked == ARG_UNDEFINED_VALUE)
645 g->draw_masked = TRUE;
649 printf("::: InitGlobalAnimGraphicInfo\n");
651 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
652 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
653 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
654 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
655 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
656 printf("::: - anim %d, part %d, mode %d => %d\n",
657 i, j, k, global_anim_info[i].graphic[j][k]);
661 static void InitGlobalAnimSoundInfo(void)
663 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
664 int num_property_mappings = getSoundListPropertyMappingSize();
667 // always start with reliable default values (no global animation sounds)
668 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
669 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
670 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
671 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
673 // initialize global animation sound definitions from dynamic configuration
674 for (i = 0; i < num_property_mappings; i++)
676 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
677 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
678 int special = property_mapping[i].ext3_index;
679 int sound = property_mapping[i].artwork_index;
681 // sound uses control definition; map it to position of graphic (artwork)
682 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
684 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
687 // set animation part to base part, if not specified
688 if (!IS_GLOBAL_ANIM_PART(part_nr))
689 part_nr = GLOBAL_ANIM_ID_PART_BASE;
691 // set animation screen to default, if not specified
692 if (!IS_SPECIAL_GFX_ARG(special))
693 special = GFX_SPECIAL_ARG_DEFAULT;
695 global_anim_info[anim_nr].sound[part_nr][special] = sound;
699 printf("::: InitGlobalAnimSoundInfo\n");
701 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
702 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
703 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
704 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
705 printf("::: - anim %d, part %d, mode %d => %d\n",
706 i, j, k, global_anim_info[i].sound[j][k]);
710 static void InitGlobalAnimMusicInfo(void)
712 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
713 int num_property_mappings = getMusicListPropertyMappingSize();
716 // always start with reliable default values (no global animation music)
717 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
718 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
719 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
720 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
722 // initialize global animation music definitions from dynamic configuration
723 for (i = 0; i < num_property_mappings; i++)
725 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
726 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
727 int special = property_mapping[i].ext2_index;
728 int music = property_mapping[i].artwork_index;
730 // music uses control definition; map it to position of graphic (artwork)
731 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
733 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
736 // set animation part to base part, if not specified
737 if (!IS_GLOBAL_ANIM_PART(part_nr))
738 part_nr = GLOBAL_ANIM_ID_PART_BASE;
740 // set animation screen to default, if not specified
741 if (!IS_SPECIAL_GFX_ARG(special))
742 special = GFX_SPECIAL_ARG_DEFAULT;
744 global_anim_info[anim_nr].music[part_nr][special] = music;
748 printf("::: InitGlobalAnimMusicInfo\n");
750 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
751 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
752 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
753 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
754 printf("::: - anim %d, part %d, mode %d => %d\n",
755 i, j, k, global_anim_info[i].music[j][k]);
759 static void InitElementGraphicInfo(void)
761 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
762 int num_property_mappings = getImageListPropertyMappingSize();
765 if (graphic_info == NULL) // still at startup phase
768 // set values to -1 to identify later as "uninitialized" values
769 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
771 for (act = 0; act < NUM_ACTIONS; act++)
773 element_info[i].graphic[act] = -1;
774 element_info[i].crumbled[act] = -1;
776 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
778 element_info[i].direction_graphic[act][dir] = -1;
779 element_info[i].direction_crumbled[act][dir] = -1;
786 // initialize normal element/graphic mapping from static configuration
787 for (i = 0; element_to_graphic[i].element > -1; i++)
789 int element = element_to_graphic[i].element;
790 int action = element_to_graphic[i].action;
791 int direction = element_to_graphic[i].direction;
792 boolean crumbled = element_to_graphic[i].crumbled;
793 int graphic = element_to_graphic[i].graphic;
794 int base_graphic = el2baseimg(element);
796 if (graphic_info[graphic].bitmap == NULL)
799 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
802 boolean base_redefined =
803 getImageListEntryFromImageID(base_graphic)->redefined;
804 boolean act_dir_redefined =
805 getImageListEntryFromImageID(graphic)->redefined;
807 /* if the base graphic ("emerald", for example) has been redefined,
808 but not the action graphic ("emerald.falling", for example), do not
809 use an existing (in this case considered obsolete) action graphic
810 anymore, but use the automatically determined default graphic */
811 if (base_redefined && !act_dir_redefined)
816 action = ACTION_DEFAULT;
821 element_info[element].direction_crumbled[action][direction] = graphic;
823 element_info[element].crumbled[action] = graphic;
828 element_info[element].direction_graphic[action][direction] = graphic;
830 element_info[element].graphic[action] = graphic;
834 // initialize normal element/graphic mapping from dynamic configuration
835 for (i = 0; i < num_property_mappings; i++)
837 int element = property_mapping[i].base_index;
838 int action = property_mapping[i].ext1_index;
839 int direction = property_mapping[i].ext2_index;
840 int special = property_mapping[i].ext3_index;
841 int graphic = property_mapping[i].artwork_index;
842 boolean crumbled = FALSE;
844 if (special == GFX_SPECIAL_ARG_CRUMBLED)
850 if (graphic_info[graphic].bitmap == NULL)
853 if (element >= MAX_NUM_ELEMENTS || special != -1)
857 action = ACTION_DEFAULT;
862 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
863 element_info[element].direction_crumbled[action][dir] = -1;
866 element_info[element].direction_crumbled[action][direction] = graphic;
868 element_info[element].crumbled[action] = graphic;
873 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
874 element_info[element].direction_graphic[action][dir] = -1;
877 element_info[element].direction_graphic[action][direction] = graphic;
879 element_info[element].graphic[action] = graphic;
883 // now copy all graphics that are defined to be cloned from other graphics
884 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
886 int graphic = element_info[i].graphic[ACTION_DEFAULT];
887 int crumbled_like, diggable_like;
892 crumbled_like = graphic_info[graphic].crumbled_like;
893 diggable_like = graphic_info[graphic].diggable_like;
895 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
897 for (act = 0; act < NUM_ACTIONS; act++)
898 element_info[i].crumbled[act] =
899 element_info[crumbled_like].crumbled[act];
900 for (act = 0; act < NUM_ACTIONS; act++)
901 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
902 element_info[i].direction_crumbled[act][dir] =
903 element_info[crumbled_like].direction_crumbled[act][dir];
906 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
908 element_info[i].graphic[ACTION_DIGGING] =
909 element_info[diggable_like].graphic[ACTION_DIGGING];
910 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
911 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
912 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
916 // set hardcoded definitions for some runtime elements without graphic
917 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
919 // set hardcoded definitions for some internal elements without graphic
920 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
922 if (IS_EDITOR_CASCADE_INACTIVE(i))
923 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
924 else if (IS_EDITOR_CASCADE_ACTIVE(i))
925 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
928 // now set all undefined/invalid graphics to -1 to set to default after it
929 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
931 for (act = 0; act < NUM_ACTIONS; act++)
935 graphic = element_info[i].graphic[act];
936 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
937 element_info[i].graphic[act] = -1;
939 graphic = element_info[i].crumbled[act];
940 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
941 element_info[i].crumbled[act] = -1;
943 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
945 graphic = element_info[i].direction_graphic[act][dir];
946 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
947 element_info[i].direction_graphic[act][dir] = -1;
949 graphic = element_info[i].direction_crumbled[act][dir];
950 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
951 element_info[i].direction_crumbled[act][dir] = -1;
958 // adjust graphics with 2nd tile for movement according to direction
959 // (do this before correcting '-1' values to minimize calculations)
960 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
962 for (act = 0; act < NUM_ACTIONS; act++)
964 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
966 int graphic = element_info[i].direction_graphic[act][dir];
967 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
969 if (act == ACTION_FALLING) // special case
970 graphic = element_info[i].graphic[act];
973 graphic_info[graphic].double_movement &&
974 graphic_info[graphic].swap_double_tiles != 0)
976 struct GraphicInfo *g = &graphic_info[graphic];
977 int src_x_front = g->src_x;
978 int src_y_front = g->src_y;
979 int src_x_back = g->src_x + g->offset2_x;
980 int src_y_back = g->src_y + g->offset2_y;
981 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
983 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
984 src_y_front < src_y_back);
985 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
986 boolean swap_movement_tiles_autodetected =
987 (!frames_are_ordered_diagonally &&
988 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
989 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
990 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
991 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
993 // swap frontside and backside graphic tile coordinates, if needed
994 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
996 // get current (wrong) backside tile coordinates
997 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
999 // set frontside tile coordinates to backside tile coordinates
1000 g->src_x = src_x_back;
1001 g->src_y = src_y_back;
1003 // invert tile offset to point to new backside tile coordinates
1007 // do not swap front and backside tiles again after correction
1008 g->swap_double_tiles = 0;
1015 UPDATE_BUSY_STATE();
1017 // now set all '-1' values to element specific default values
1018 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1020 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1021 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1022 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1023 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1025 if (default_graphic == -1)
1026 default_graphic = IMG_UNKNOWN;
1028 if (default_crumbled == -1)
1029 default_crumbled = default_graphic;
1031 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1033 default_direction_graphic[dir] =
1034 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1035 default_direction_crumbled[dir] =
1036 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1038 if (default_direction_graphic[dir] == -1)
1039 default_direction_graphic[dir] = default_graphic;
1041 if (default_direction_crumbled[dir] == -1)
1042 default_direction_crumbled[dir] = default_direction_graphic[dir];
1045 for (act = 0; act < NUM_ACTIONS; act++)
1047 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1048 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1049 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1050 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1051 act == ACTION_TURNING_FROM_RIGHT ||
1052 act == ACTION_TURNING_FROM_UP ||
1053 act == ACTION_TURNING_FROM_DOWN);
1055 // generic default action graphic (defined by "[default]" directive)
1056 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1057 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1058 int default_remove_graphic = IMG_EMPTY;
1060 if (act_remove && default_action_graphic != -1)
1061 default_remove_graphic = default_action_graphic;
1063 // look for special default action graphic (classic game specific)
1064 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1065 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1066 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1067 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1068 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1069 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1070 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1071 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1073 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1074 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1075 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1076 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1077 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1078 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1079 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1080 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1082 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1083 // !!! make this better !!!
1084 if (i == EL_EMPTY_SPACE)
1086 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1087 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1090 if (default_action_graphic == -1)
1091 default_action_graphic = default_graphic;
1093 if (default_action_crumbled == -1)
1094 default_action_crumbled = default_action_graphic;
1096 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1098 // use action graphic as the default direction graphic, if undefined
1099 int default_action_direction_graphic = element_info[i].graphic[act];
1100 int default_action_direction_crumbled = element_info[i].crumbled[act];
1102 // no graphic for current action -- use default direction graphic
1103 if (default_action_direction_graphic == -1)
1104 default_action_direction_graphic =
1105 (act_remove ? default_remove_graphic :
1107 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1108 default_action_graphic != default_graphic ?
1109 default_action_graphic :
1110 default_direction_graphic[dir]);
1112 if (element_info[i].direction_graphic[act][dir] == -1)
1113 element_info[i].direction_graphic[act][dir] =
1114 default_action_direction_graphic;
1116 if (default_action_direction_crumbled == -1)
1117 default_action_direction_crumbled =
1118 element_info[i].direction_graphic[act][dir];
1120 if (element_info[i].direction_crumbled[act][dir] == -1)
1121 element_info[i].direction_crumbled[act][dir] =
1122 default_action_direction_crumbled;
1125 // no graphic for this specific action -- use default action graphic
1126 if (element_info[i].graphic[act] == -1)
1127 element_info[i].graphic[act] =
1128 (act_remove ? default_remove_graphic :
1129 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1130 default_action_graphic);
1132 if (element_info[i].crumbled[act] == -1)
1133 element_info[i].crumbled[act] = element_info[i].graphic[act];
1137 UPDATE_BUSY_STATE();
1140 static void InitElementSpecialGraphicInfo(void)
1142 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1143 int num_property_mappings = getImageListPropertyMappingSize();
1146 // always start with reliable default values
1147 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1148 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1149 element_info[i].special_graphic[j] =
1150 element_info[i].graphic[ACTION_DEFAULT];
1152 // initialize special element/graphic mapping from static configuration
1153 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1155 int element = element_to_special_graphic[i].element;
1156 int special = element_to_special_graphic[i].special;
1157 int graphic = element_to_special_graphic[i].graphic;
1158 int base_graphic = el2baseimg(element);
1159 boolean base_redefined =
1160 getImageListEntryFromImageID(base_graphic)->redefined;
1161 boolean special_redefined =
1162 getImageListEntryFromImageID(graphic)->redefined;
1164 /* if the base graphic ("emerald", for example) has been redefined,
1165 but not the special graphic ("emerald.EDITOR", for example), do not
1166 use an existing (in this case considered obsolete) special graphic
1167 anymore, but use the automatically created (down-scaled) graphic */
1168 if (base_redefined && !special_redefined)
1171 element_info[element].special_graphic[special] = graphic;
1174 // initialize special element/graphic mapping from dynamic configuration
1175 for (i = 0; i < num_property_mappings; i++)
1177 int element = property_mapping[i].base_index;
1178 int action = property_mapping[i].ext1_index;
1179 int direction = property_mapping[i].ext2_index;
1180 int special = property_mapping[i].ext3_index;
1181 int graphic = property_mapping[i].artwork_index;
1183 // for action ".active", replace element with active element, if exists
1184 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1186 element = ELEMENT_ACTIVE(element);
1190 if (element >= MAX_NUM_ELEMENTS)
1193 // do not change special graphic if action or direction was specified
1194 if (action != -1 || direction != -1)
1197 if (IS_SPECIAL_GFX_ARG(special))
1198 element_info[element].special_graphic[special] = graphic;
1201 // now set all undefined/invalid graphics to default
1202 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1203 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1204 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1205 element_info[i].special_graphic[j] =
1206 element_info[i].graphic[ACTION_DEFAULT];
1209 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1211 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1212 return get_parameter_value(value_raw, suffix, type);
1214 if (strEqual(value_raw, ARG_UNDEFINED))
1215 return ARG_UNDEFINED_VALUE;
1217 if (type == TYPE_ELEMENT)
1219 char *value = getHashEntry(element_token_hash, value_raw);
1223 Error(ERR_INFO_LINE, "-");
1224 Error(ERR_INFO, "warning: error found in config file:");
1225 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1226 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1227 Error(ERR_INFO, "custom graphic rejected for this element/action");
1228 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1229 Error(ERR_INFO_LINE, "-");
1232 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1234 else if (type == TYPE_GRAPHIC)
1236 char *value = getHashEntry(graphic_token_hash, value_raw);
1237 int fallback_graphic = IMG_CHAR_EXCLAM;
1241 Error(ERR_INFO_LINE, "-");
1242 Error(ERR_INFO, "warning: error found in config file:");
1243 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1244 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1245 Error(ERR_INFO, "custom graphic rejected for this element/action");
1246 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1247 Error(ERR_INFO_LINE, "-");
1250 return (value != NULL ? atoi(value) : fallback_graphic);
1256 static int get_scaled_graphic_width(int graphic)
1258 int original_width = getOriginalImageWidthFromImageID(graphic);
1259 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1261 return original_width * scale_up_factor;
1264 static int get_scaled_graphic_height(int graphic)
1266 int original_height = getOriginalImageHeightFromImageID(graphic);
1267 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1269 return original_height * scale_up_factor;
1272 static void set_graphic_parameters_ext(int graphic, int *parameter,
1273 Bitmap **src_bitmaps)
1275 struct GraphicInfo *g = &graphic_info[graphic];
1276 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1277 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1278 int anim_frames_per_line = 1;
1280 // always start with reliable default values
1281 g->src_image_width = 0;
1282 g->src_image_height = 0;
1285 g->width = TILEX; // default for element graphics
1286 g->height = TILEY; // default for element graphics
1287 g->offset_x = 0; // one or both of these values ...
1288 g->offset_y = 0; // ... will be corrected later
1289 g->offset2_x = 0; // one or both of these values ...
1290 g->offset2_y = 0; // ... will be corrected later
1291 g->swap_double_tiles = -1; // auto-detect tile swapping
1292 g->crumbled_like = -1; // do not use clone element
1293 g->diggable_like = -1; // do not use clone element
1294 g->border_size = TILEX / 8; // "CRUMBLED" border size
1295 g->scale_up_factor = 1; // default: no scaling up
1296 g->tile_size = TILESIZE; // default: standard tile size
1297 g->clone_from = -1; // do not use clone graphic
1298 g->init_delay_fixed = 0;
1299 g->init_delay_random = 0;
1300 g->anim_delay_fixed = 0;
1301 g->anim_delay_random = 0;
1302 g->post_delay_fixed = 0;
1303 g->post_delay_random = 0;
1304 g->init_event = ANIM_EVENT_DEFAULT;
1305 g->anim_event = ANIM_EVENT_DEFAULT;
1306 g->init_event_action = -1;
1307 g->anim_event_action = -1;
1308 g->draw_masked = FALSE;
1310 g->fade_mode = FADE_MODE_DEFAULT;
1314 g->align = ALIGN_CENTER; // default for title screens
1315 g->valign = VALIGN_MIDDLE; // default for title screens
1316 g->sort_priority = 0; // default for title screens
1318 g->style = STYLE_DEFAULT;
1320 g->bitmaps = src_bitmaps;
1321 g->bitmap = src_bitmap;
1323 // optional zoom factor for scaling up the image to a larger size
1324 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1325 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1326 if (g->scale_up_factor < 1)
1327 g->scale_up_factor = 1; // no scaling
1329 // optional tile size for using non-standard image size
1330 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1332 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1335 // CHECK: should tile sizes less than standard tile size be allowed?
1336 if (g->tile_size < TILESIZE)
1337 g->tile_size = TILESIZE; // standard tile size
1340 // when setting tile size, also set width and height accordingly
1341 g->width = g->tile_size;
1342 g->height = g->tile_size;
1345 if (g->use_image_size)
1347 // set new default bitmap size (with scaling, but without small images)
1348 g->width = get_scaled_graphic_width(graphic);
1349 g->height = get_scaled_graphic_height(graphic);
1352 // optional width and height of each animation frame
1353 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1354 g->width = parameter[GFX_ARG_WIDTH];
1355 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1356 g->height = parameter[GFX_ARG_HEIGHT];
1358 // optional x and y tile position of animation frame sequence
1359 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1360 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1361 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1362 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1364 // optional x and y pixel position of animation frame sequence
1365 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1366 g->src_x = parameter[GFX_ARG_X];
1367 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1368 g->src_y = parameter[GFX_ARG_Y];
1374 Error(ERR_INFO_LINE, "-");
1375 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1376 g->width, getTokenFromImageID(graphic), TILEX);
1377 Error(ERR_INFO_LINE, "-");
1379 g->width = TILEX; // will be checked to be inside bitmap later
1384 Error(ERR_INFO_LINE, "-");
1385 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1386 g->height, getTokenFromImageID(graphic), TILEY);
1387 Error(ERR_INFO_LINE, "-");
1389 g->height = TILEY; // will be checked to be inside bitmap later
1395 // get final bitmap size (with scaling, but without small images)
1396 int src_image_width = get_scaled_graphic_width(graphic);
1397 int src_image_height = get_scaled_graphic_height(graphic);
1399 if (src_image_width == 0 || src_image_height == 0)
1401 // only happens when loaded outside artwork system (like "global.busy")
1402 src_image_width = src_bitmap->width;
1403 src_image_height = src_bitmap->height;
1406 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1408 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1409 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1413 anim_frames_per_row = MAX(1, src_image_width / g->width);
1414 anim_frames_per_col = MAX(1, src_image_height / g->height);
1417 g->src_image_width = src_image_width;
1418 g->src_image_height = src_image_height;
1421 // correct x or y offset dependent of vertical or horizontal frame order
1422 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1424 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1425 parameter[GFX_ARG_OFFSET] : g->height);
1426 anim_frames_per_line = anim_frames_per_col;
1428 else // frames are ordered horizontally
1430 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1431 parameter[GFX_ARG_OFFSET] : g->width);
1432 anim_frames_per_line = anim_frames_per_row;
1435 // optionally, the x and y offset of frames can be specified directly
1436 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1437 g->offset_x = parameter[GFX_ARG_XOFFSET];
1438 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1439 g->offset_y = parameter[GFX_ARG_YOFFSET];
1441 // optionally, moving animations may have separate start and end graphics
1442 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1444 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1445 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1447 // correct x or y offset2 dependent of vertical or horizontal frame order
1448 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1449 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1450 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1451 else // frames are ordered horizontally
1452 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1453 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1455 // optionally, the x and y offset of 2nd graphic can be specified directly
1456 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1457 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1458 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1459 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1461 // optionally, the second movement tile can be specified as start tile
1462 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1463 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1465 // automatically determine correct number of frames, if not defined
1466 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1467 g->anim_frames = parameter[GFX_ARG_FRAMES];
1468 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1469 g->anim_frames = anim_frames_per_row;
1470 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1471 g->anim_frames = anim_frames_per_col;
1475 if (g->anim_frames == 0) // frames must be at least 1
1478 g->anim_frames_per_line =
1479 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1480 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1482 g->anim_delay = parameter[GFX_ARG_DELAY];
1483 if (g->anim_delay == 0) // delay must be at least 1
1486 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1488 // automatically determine correct start frame, if not defined
1489 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1490 g->anim_start_frame = 0;
1491 else if (g->anim_mode & ANIM_REVERSE)
1492 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1494 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1496 // animation synchronized with global frame counter, not move position
1497 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1499 // optional element for cloning crumble graphics
1500 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1501 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1503 // optional element for cloning digging graphics
1504 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1505 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1507 // optional border size for "crumbling" diggable graphics
1508 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1509 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1511 // used for global animations and player "boring" and "sleeping" actions
1512 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1513 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1514 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1515 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1516 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1517 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1518 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1519 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1520 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1521 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1522 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1523 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1525 // used for global animations
1526 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1527 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1528 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1529 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1530 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1531 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1532 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1533 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1535 // used for toon animations and global animations
1536 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1537 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1538 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1539 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1540 g->direction = parameter[GFX_ARG_DIRECTION];
1541 g->position = parameter[GFX_ARG_POSITION];
1542 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1543 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1545 // this is only used for drawing font characters
1546 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1547 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1549 // use a different default value for global animations and toons
1550 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1551 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1552 g->draw_masked = TRUE;
1554 // this is used for drawing envelopes, global animations and toons
1555 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1556 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1558 // used for toon animations and global animations
1559 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1560 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1562 // optional graphic for cloning all graphics settings
1563 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1564 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1566 // optional settings for drawing title screens and title messages
1567 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1568 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1569 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1570 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1571 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1572 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1573 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1574 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1575 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1576 g->align = parameter[GFX_ARG_ALIGN];
1577 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1578 g->valign = parameter[GFX_ARG_VALIGN];
1579 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1580 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1582 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1583 g->class = parameter[GFX_ARG_CLASS];
1584 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1585 g->style = parameter[GFX_ARG_STYLE];
1587 // this is only used for drawing menu buttons and text
1588 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1589 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1590 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1591 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1594 static void set_graphic_parameters(int graphic)
1596 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1597 char **parameter_raw = image->parameter;
1598 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1599 int parameter[NUM_GFX_ARGS];
1602 // if fallback to default artwork is done, also use the default parameters
1603 if (image->fallback_to_default)
1604 parameter_raw = image->default_parameter;
1606 // get integer values from string parameters
1607 for (i = 0; i < NUM_GFX_ARGS; i++)
1608 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1609 image_config_suffix[i].token,
1610 image_config_suffix[i].type);
1612 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1614 UPDATE_BUSY_STATE();
1617 static void set_cloned_graphic_parameters(int graphic)
1619 int fallback_graphic = IMG_CHAR_EXCLAM;
1620 int max_num_images = getImageListSize();
1621 int clone_graphic = graphic_info[graphic].clone_from;
1622 int num_references_followed = 1;
1624 while (graphic_info[clone_graphic].clone_from != -1 &&
1625 num_references_followed < max_num_images)
1627 clone_graphic = graphic_info[clone_graphic].clone_from;
1629 num_references_followed++;
1632 if (num_references_followed >= max_num_images)
1634 Error(ERR_INFO_LINE, "-");
1635 Error(ERR_INFO, "warning: error found in config file:");
1636 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1637 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1638 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1639 Error(ERR_INFO, "custom graphic rejected for this element/action");
1641 if (graphic == fallback_graphic)
1642 Error(ERR_EXIT, "no fallback graphic available");
1644 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1645 Error(ERR_INFO_LINE, "-");
1647 graphic_info[graphic] = graphic_info[fallback_graphic];
1651 graphic_info[graphic] = graphic_info[clone_graphic];
1652 graphic_info[graphic].clone_from = clone_graphic;
1656 static void InitGraphicInfo(void)
1658 int fallback_graphic = IMG_CHAR_EXCLAM;
1659 int num_images = getImageListSize();
1662 // use image size as default values for width and height for these images
1663 static int full_size_graphics[] =
1666 IMG_GLOBAL_BORDER_MAIN,
1667 IMG_GLOBAL_BORDER_SCORES,
1668 IMG_GLOBAL_BORDER_EDITOR,
1669 IMG_GLOBAL_BORDER_PLAYING,
1672 IMG_BACKGROUND_ENVELOPE_1,
1673 IMG_BACKGROUND_ENVELOPE_2,
1674 IMG_BACKGROUND_ENVELOPE_3,
1675 IMG_BACKGROUND_ENVELOPE_4,
1676 IMG_BACKGROUND_REQUEST,
1679 IMG_BACKGROUND_TITLE_INITIAL,
1680 IMG_BACKGROUND_TITLE,
1681 IMG_BACKGROUND_MAIN,
1682 IMG_BACKGROUND_LEVELS,
1683 IMG_BACKGROUND_LEVELNR,
1684 IMG_BACKGROUND_SCORES,
1685 IMG_BACKGROUND_EDITOR,
1686 IMG_BACKGROUND_INFO,
1687 IMG_BACKGROUND_INFO_ELEMENTS,
1688 IMG_BACKGROUND_INFO_MUSIC,
1689 IMG_BACKGROUND_INFO_CREDITS,
1690 IMG_BACKGROUND_INFO_PROGRAM,
1691 IMG_BACKGROUND_INFO_VERSION,
1692 IMG_BACKGROUND_INFO_LEVELSET,
1693 IMG_BACKGROUND_SETUP,
1694 IMG_BACKGROUND_PLAYING,
1695 IMG_BACKGROUND_DOOR,
1696 IMG_BACKGROUND_TAPE,
1697 IMG_BACKGROUND_PANEL,
1698 IMG_BACKGROUND_PALETTE,
1699 IMG_BACKGROUND_TOOLBOX,
1701 IMG_TITLESCREEN_INITIAL_1,
1702 IMG_TITLESCREEN_INITIAL_2,
1703 IMG_TITLESCREEN_INITIAL_3,
1704 IMG_TITLESCREEN_INITIAL_4,
1705 IMG_TITLESCREEN_INITIAL_5,
1712 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1713 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1714 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1715 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1716 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1717 IMG_BACKGROUND_TITLEMESSAGE_1,
1718 IMG_BACKGROUND_TITLEMESSAGE_2,
1719 IMG_BACKGROUND_TITLEMESSAGE_3,
1720 IMG_BACKGROUND_TITLEMESSAGE_4,
1721 IMG_BACKGROUND_TITLEMESSAGE_5,
1726 checked_free(graphic_info);
1728 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1730 // initialize "use_image_size" flag with default value
1731 for (i = 0; i < num_images; i++)
1732 graphic_info[i].use_image_size = FALSE;
1734 // initialize "use_image_size" flag from static configuration above
1735 for (i = 0; full_size_graphics[i] != -1; i++)
1736 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1738 // first set all graphic paramaters ...
1739 for (i = 0; i < num_images; i++)
1740 set_graphic_parameters(i);
1742 // ... then copy these parameters for cloned graphics
1743 for (i = 0; i < num_images; i++)
1744 if (graphic_info[i].clone_from != -1)
1745 set_cloned_graphic_parameters(i);
1747 for (i = 0; i < num_images; i++)
1749 Bitmap *src_bitmap = graphic_info[i].bitmap;
1753 int src_bitmap_width, src_bitmap_height;
1755 // now check if no animation frames are outside of the loaded image
1757 if (graphic_info[i].bitmap == NULL)
1758 continue; // skip check for optional images that are undefined
1760 // get image size (this can differ from the standard element tile size!)
1761 width = graphic_info[i].width;
1762 height = graphic_info[i].height;
1764 // get final bitmap size (with scaling, but without small images)
1765 src_bitmap_width = graphic_info[i].src_image_width;
1766 src_bitmap_height = graphic_info[i].src_image_height;
1768 // check if first animation frame is inside specified bitmap
1770 // do not use getGraphicSourceXY() here to get position of first frame;
1771 // this avoids calculating wrong start position for out-of-bounds frame
1772 src_x = graphic_info[i].src_x;
1773 src_y = graphic_info[i].src_y;
1775 if (program.headless)
1778 if (src_x < 0 || src_y < 0 ||
1779 src_x + width > src_bitmap_width ||
1780 src_y + height > src_bitmap_height)
1782 Error(ERR_INFO_LINE, "-");
1783 Error(ERR_INFO, "warning: error found in config file:");
1784 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1785 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1786 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1787 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1789 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1790 src_x, src_y, src_bitmap_width, src_bitmap_height);
1791 Error(ERR_INFO, "custom graphic rejected for this element/action");
1793 if (i == fallback_graphic)
1794 Error(ERR_EXIT, "no fallback graphic available");
1796 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1797 Error(ERR_INFO_LINE, "-");
1799 graphic_info[i] = graphic_info[fallback_graphic];
1801 // if first frame out of bounds, do not check last frame anymore
1805 // check if last animation frame is inside specified bitmap
1807 last_frame = graphic_info[i].anim_frames - 1;
1808 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1810 if (src_x < 0 || src_y < 0 ||
1811 src_x + width > src_bitmap_width ||
1812 src_y + height > src_bitmap_height)
1814 Error(ERR_INFO_LINE, "-");
1815 Error(ERR_INFO, "warning: error found in config file:");
1816 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1817 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1818 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1819 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1821 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1822 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1823 Error(ERR_INFO, "custom graphic rejected for this element/action");
1825 if (i == fallback_graphic)
1826 Error(ERR_EXIT, "no fallback graphic available");
1828 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1829 Error(ERR_INFO_LINE, "-");
1831 graphic_info[i] = graphic_info[fallback_graphic];
1836 static void InitGraphicCompatibilityInfo(void)
1838 struct FileInfo *fi_global_door =
1839 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1840 int num_images = getImageListSize();
1843 /* the following compatibility handling is needed for the following case:
1844 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1845 graphics mainly used for door and panel graphics, like editor, tape and
1846 in-game buttons with hard-coded bitmap positions and button sizes; as
1847 these graphics now have individual definitions, redefining "global.door"
1848 to change all these graphics at once like before does not work anymore
1849 (because all those individual definitions still have their default values);
1850 to solve this, remap all those individual definitions that are not
1851 redefined to the new bitmap of "global.door" if it was redefined */
1853 // special compatibility handling if image "global.door" was redefined
1854 if (fi_global_door->redefined)
1856 for (i = 0; i < num_images; i++)
1858 struct FileInfo *fi = getImageListEntryFromImageID(i);
1860 // process only those images that still use the default settings
1863 // process all images which default to same image as "global.door"
1864 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1866 // printf("::: special treatment needed for token '%s'\n", fi->token);
1868 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1869 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1875 InitGraphicCompatibilityInfo_Doors();
1878 static void InitElementSoundInfo(void)
1880 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1881 int num_property_mappings = getSoundListPropertyMappingSize();
1884 // set values to -1 to identify later as "uninitialized" values
1885 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1886 for (act = 0; act < NUM_ACTIONS; act++)
1887 element_info[i].sound[act] = -1;
1889 // initialize element/sound mapping from static configuration
1890 for (i = 0; element_to_sound[i].element > -1; i++)
1892 int element = element_to_sound[i].element;
1893 int action = element_to_sound[i].action;
1894 int sound = element_to_sound[i].sound;
1895 boolean is_class = element_to_sound[i].is_class;
1898 action = ACTION_DEFAULT;
1901 element_info[element].sound[action] = sound;
1903 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1904 if (strEqual(element_info[j].class_name,
1905 element_info[element].class_name))
1906 element_info[j].sound[action] = sound;
1909 // initialize element class/sound mapping from dynamic configuration
1910 for (i = 0; i < num_property_mappings; i++)
1912 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1913 int action = property_mapping[i].ext1_index;
1914 int sound = property_mapping[i].artwork_index;
1916 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1920 action = ACTION_DEFAULT;
1922 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1923 if (strEqual(element_info[j].class_name,
1924 element_info[element_class].class_name))
1925 element_info[j].sound[action] = sound;
1928 // initialize element/sound mapping from dynamic configuration
1929 for (i = 0; i < num_property_mappings; i++)
1931 int element = property_mapping[i].base_index;
1932 int action = property_mapping[i].ext1_index;
1933 int sound = property_mapping[i].artwork_index;
1935 if (element >= MAX_NUM_ELEMENTS)
1939 action = ACTION_DEFAULT;
1941 element_info[element].sound[action] = sound;
1944 // now set all '-1' values to element specific default values
1945 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1947 for (act = 0; act < NUM_ACTIONS; act++)
1949 // generic default action sound (defined by "[default]" directive)
1950 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1952 // look for special default action sound (classic game specific)
1953 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1954 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1955 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1956 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1957 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1958 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1959 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1960 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1962 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1963 // !!! make this better !!!
1964 if (i == EL_EMPTY_SPACE)
1965 default_action_sound = element_info[EL_DEFAULT].sound[act];
1967 // no sound for this specific action -- use default action sound
1968 if (element_info[i].sound[act] == -1)
1969 element_info[i].sound[act] = default_action_sound;
1973 // copy sound settings to some elements that are only stored in level file
1974 // in native R'n'D levels, but are used by game engine in native EM levels
1975 for (i = 0; copy_properties[i][0] != -1; i++)
1976 for (j = 1; j <= 4; j++)
1977 for (act = 0; act < NUM_ACTIONS; act++)
1978 element_info[copy_properties[i][j]].sound[act] =
1979 element_info[copy_properties[i][0]].sound[act];
1982 static void InitGameModeSoundInfo(void)
1986 // set values to -1 to identify later as "uninitialized" values
1987 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1990 // initialize gamemode/sound mapping from static configuration
1991 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1993 int gamemode = gamemode_to_sound[i].gamemode;
1994 int sound = gamemode_to_sound[i].sound;
1997 gamemode = GAME_MODE_DEFAULT;
1999 menu.sound[gamemode] = sound;
2002 // now set all '-1' values to levelset specific default values
2003 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2004 if (menu.sound[i] == -1)
2005 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2008 static void set_sound_parameters(int sound, char **parameter_raw)
2010 int parameter[NUM_SND_ARGS];
2013 // get integer values from string parameters
2014 for (i = 0; i < NUM_SND_ARGS; i++)
2016 get_parameter_value(parameter_raw[i],
2017 sound_config_suffix[i].token,
2018 sound_config_suffix[i].type);
2020 // explicit loop mode setting in configuration overrides default value
2021 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2022 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2024 // sound volume to change the original volume when loading the sound file
2025 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2027 // sound priority to give certain sounds a higher or lower priority
2028 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2031 static void InitSoundInfo(void)
2033 int *sound_effect_properties;
2034 int num_sounds = getSoundListSize();
2037 checked_free(sound_info);
2039 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2040 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2042 // initialize sound effect for all elements to "no sound"
2043 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2044 for (j = 0; j < NUM_ACTIONS; j++)
2045 element_info[i].sound[j] = SND_UNDEFINED;
2047 for (i = 0; i < num_sounds; i++)
2049 struct FileInfo *sound = getSoundListEntry(i);
2050 int len_effect_text = strlen(sound->token);
2052 sound_effect_properties[i] = ACTION_OTHER;
2053 sound_info[i].loop = FALSE; // default: play sound only once
2055 // determine all loop sounds and identify certain sound classes
2057 for (j = 0; element_action_info[j].suffix; j++)
2059 int len_action_text = strlen(element_action_info[j].suffix);
2061 if (len_action_text < len_effect_text &&
2062 strEqual(&sound->token[len_effect_text - len_action_text],
2063 element_action_info[j].suffix))
2065 sound_effect_properties[i] = element_action_info[j].value;
2066 sound_info[i].loop = element_action_info[j].is_loop_sound;
2072 // associate elements and some selected sound actions
2074 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2076 if (element_info[j].class_name)
2078 int len_class_text = strlen(element_info[j].class_name);
2080 if (len_class_text + 1 < len_effect_text &&
2081 strncmp(sound->token,
2082 element_info[j].class_name, len_class_text) == 0 &&
2083 sound->token[len_class_text] == '.')
2085 int sound_action_value = sound_effect_properties[i];
2087 element_info[j].sound[sound_action_value] = i;
2092 set_sound_parameters(i, sound->parameter);
2095 free(sound_effect_properties);
2098 static void InitGameModeMusicInfo(void)
2100 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2101 int num_property_mappings = getMusicListPropertyMappingSize();
2102 int default_levelset_music = -1;
2105 // set values to -1 to identify later as "uninitialized" values
2106 for (i = 0; i < MAX_LEVELS; i++)
2107 levelset.music[i] = -1;
2108 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2111 // initialize gamemode/music mapping from static configuration
2112 for (i = 0; gamemode_to_music[i].music > -1; i++)
2114 int gamemode = gamemode_to_music[i].gamemode;
2115 int music = gamemode_to_music[i].music;
2118 gamemode = GAME_MODE_DEFAULT;
2120 menu.music[gamemode] = music;
2123 // initialize gamemode/music mapping from dynamic configuration
2124 for (i = 0; i < num_property_mappings; i++)
2126 int prefix = property_mapping[i].base_index;
2127 int gamemode = property_mapping[i].ext2_index;
2128 int level = property_mapping[i].ext3_index;
2129 int music = property_mapping[i].artwork_index;
2131 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2135 gamemode = GAME_MODE_DEFAULT;
2137 // level specific music only allowed for in-game music
2138 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2139 gamemode = GAME_MODE_PLAYING;
2144 default_levelset_music = music;
2147 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2148 levelset.music[level] = music;
2149 if (gamemode != GAME_MODE_PLAYING)
2150 menu.music[gamemode] = music;
2153 // now set all '-1' values to menu specific default values
2154 // (undefined values of "levelset.music[]" might stay at "-1" to
2155 // allow dynamic selection of music files from music directory!)
2156 for (i = 0; i < MAX_LEVELS; i++)
2157 if (levelset.music[i] == -1)
2158 levelset.music[i] = default_levelset_music;
2159 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2160 if (menu.music[i] == -1)
2161 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2164 static void set_music_parameters(int music, char **parameter_raw)
2166 int parameter[NUM_MUS_ARGS];
2169 // get integer values from string parameters
2170 for (i = 0; i < NUM_MUS_ARGS; i++)
2172 get_parameter_value(parameter_raw[i],
2173 music_config_suffix[i].token,
2174 music_config_suffix[i].type);
2176 // explicit loop mode setting in configuration overrides default value
2177 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2178 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2181 static void InitMusicInfo(void)
2183 int num_music = getMusicListSize();
2186 checked_free(music_info);
2188 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2190 for (i = 0; i < num_music; i++)
2192 struct FileInfo *music = getMusicListEntry(i);
2193 int len_music_text = strlen(music->token);
2195 music_info[i].loop = TRUE; // default: play music in loop mode
2197 // determine all loop music
2199 for (j = 0; music_prefix_info[j].prefix; j++)
2201 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2203 if (len_prefix_text < len_music_text &&
2204 strncmp(music->token,
2205 music_prefix_info[j].prefix, len_prefix_text) == 0)
2207 music_info[i].loop = music_prefix_info[j].is_loop_music;
2213 set_music_parameters(i, music->parameter);
2217 static void ReinitializeGraphics(void)
2219 print_timestamp_init("ReinitializeGraphics");
2221 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2223 InitGraphicInfo(); // graphic properties mapping
2224 print_timestamp_time("InitGraphicInfo");
2225 InitElementGraphicInfo(); // element game graphic mapping
2226 print_timestamp_time("InitElementGraphicInfo");
2227 InitElementSpecialGraphicInfo(); // element special graphic mapping
2228 print_timestamp_time("InitElementSpecialGraphicInfo");
2230 InitElementSmallImages(); // scale elements to all needed sizes
2231 print_timestamp_time("InitElementSmallImages");
2232 InitScaledImages(); // scale all other images, if needed
2233 print_timestamp_time("InitScaledImages");
2234 InitBitmapPointers(); // set standard size bitmap pointers
2235 print_timestamp_time("InitBitmapPointers");
2236 InitFontGraphicInfo(); // initialize text drawing functions
2237 print_timestamp_time("InitFontGraphicInfo");
2238 InitGlobalAnimGraphicInfo(); // initialize global animation config
2239 print_timestamp_time("InitGlobalAnimGraphicInfo");
2241 InitImageTextures(); // create textures for certain images
2242 print_timestamp_time("InitImageTextures");
2244 InitGraphicInfo_EM(); // graphic mapping for EM engine
2245 print_timestamp_time("InitGraphicInfo_EM");
2247 InitGraphicCompatibilityInfo();
2248 print_timestamp_time("InitGraphicCompatibilityInfo");
2250 SetMainBackgroundImage(IMG_BACKGROUND);
2251 print_timestamp_time("SetMainBackgroundImage");
2252 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2253 print_timestamp_time("SetDoorBackgroundImage");
2256 print_timestamp_time("InitGadgets");
2258 print_timestamp_time("InitDoors");
2260 print_timestamp_done("ReinitializeGraphics");
2263 static void ReinitializeSounds(void)
2265 InitSoundInfo(); // sound properties mapping
2266 InitElementSoundInfo(); // element game sound mapping
2267 InitGameModeSoundInfo(); // game mode sound mapping
2268 InitGlobalAnimSoundInfo(); // global animation sound settings
2270 InitPlayLevelSound(); // internal game sound settings
2273 static void ReinitializeMusic(void)
2275 InitMusicInfo(); // music properties mapping
2276 InitGameModeMusicInfo(); // game mode music mapping
2277 InitGlobalAnimMusicInfo(); // global animation music settings
2280 static int get_special_property_bit(int element, int property_bit_nr)
2282 struct PropertyBitInfo
2288 static struct PropertyBitInfo pb_can_move_into_acid[] =
2290 // the player may be able fall into acid when gravity is activated
2295 { EL_SP_MURPHY, 0 },
2296 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2298 // all elements that can move may be able to also move into acid
2301 { EL_BUG_RIGHT, 1 },
2304 { EL_SPACESHIP, 2 },
2305 { EL_SPACESHIP_LEFT, 2 },
2306 { EL_SPACESHIP_RIGHT, 2 },
2307 { EL_SPACESHIP_UP, 2 },
2308 { EL_SPACESHIP_DOWN, 2 },
2309 { EL_BD_BUTTERFLY, 3 },
2310 { EL_BD_BUTTERFLY_LEFT, 3 },
2311 { EL_BD_BUTTERFLY_RIGHT, 3 },
2312 { EL_BD_BUTTERFLY_UP, 3 },
2313 { EL_BD_BUTTERFLY_DOWN, 3 },
2314 { EL_BD_FIREFLY, 4 },
2315 { EL_BD_FIREFLY_LEFT, 4 },
2316 { EL_BD_FIREFLY_RIGHT, 4 },
2317 { EL_BD_FIREFLY_UP, 4 },
2318 { EL_BD_FIREFLY_DOWN, 4 },
2320 { EL_YAMYAM_LEFT, 5 },
2321 { EL_YAMYAM_RIGHT, 5 },
2322 { EL_YAMYAM_UP, 5 },
2323 { EL_YAMYAM_DOWN, 5 },
2324 { EL_DARK_YAMYAM, 6 },
2327 { EL_PACMAN_LEFT, 8 },
2328 { EL_PACMAN_RIGHT, 8 },
2329 { EL_PACMAN_UP, 8 },
2330 { EL_PACMAN_DOWN, 8 },
2332 { EL_MOLE_LEFT, 9 },
2333 { EL_MOLE_RIGHT, 9 },
2335 { EL_MOLE_DOWN, 9 },
2339 { EL_SATELLITE, 13 },
2340 { EL_SP_SNIKSNAK, 14 },
2341 { EL_SP_ELECTRON, 15 },
2344 { EL_EMC_ANDROID, 18 },
2349 static struct PropertyBitInfo pb_dont_collide_with[] =
2351 { EL_SP_SNIKSNAK, 0 },
2352 { EL_SP_ELECTRON, 1 },
2360 struct PropertyBitInfo *pb_info;
2363 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2364 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2369 struct PropertyBitInfo *pb_info = NULL;
2372 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2373 if (pb_definition[i].bit_nr == property_bit_nr)
2374 pb_info = pb_definition[i].pb_info;
2376 if (pb_info == NULL)
2379 for (i = 0; pb_info[i].element != -1; i++)
2380 if (pb_info[i].element == element)
2381 return pb_info[i].bit_nr;
2386 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2387 boolean property_value)
2389 int bit_nr = get_special_property_bit(element, property_bit_nr);
2394 *bitfield |= (1 << bit_nr);
2396 *bitfield &= ~(1 << bit_nr);
2400 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2402 int bit_nr = get_special_property_bit(element, property_bit_nr);
2405 return ((*bitfield & (1 << bit_nr)) != 0);
2410 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2412 static int group_nr;
2413 static struct ElementGroupInfo *group;
2414 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2417 if (actual_group == NULL) // not yet initialized
2420 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2422 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2423 group_element - EL_GROUP_START + 1);
2425 // replace element which caused too deep recursion by question mark
2426 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2431 if (recursion_depth == 0) // initialization
2433 group = actual_group;
2434 group_nr = GROUP_NR(group_element);
2436 group->num_elements_resolved = 0;
2437 group->choice_pos = 0;
2439 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2440 element_info[i].in_group[group_nr] = FALSE;
2443 for (i = 0; i < actual_group->num_elements; i++)
2445 int element = actual_group->element[i];
2447 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2450 if (IS_GROUP_ELEMENT(element))
2451 ResolveGroupElementExt(element, recursion_depth + 1);
2454 group->element_resolved[group->num_elements_resolved++] = element;
2455 element_info[element].in_group[group_nr] = TRUE;
2460 void ResolveGroupElement(int group_element)
2462 ResolveGroupElementExt(group_element, 0);
2465 void InitElementPropertiesStatic(void)
2467 static boolean clipboard_elements_initialized = FALSE;
2469 static int ep_diggable[] =
2474 EL_SP_BUGGY_BASE_ACTIVATING,
2477 EL_INVISIBLE_SAND_ACTIVE,
2480 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2481 // (if amoeba can grow into anything diggable, maybe keep these out)
2486 EL_SP_BUGGY_BASE_ACTIVE,
2493 static int ep_collectible_only[] =
2515 EL_DYNABOMB_INCREASE_NUMBER,
2516 EL_DYNABOMB_INCREASE_SIZE,
2517 EL_DYNABOMB_INCREASE_POWER,
2535 // !!! handle separately !!!
2536 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2542 static int ep_dont_run_into[] =
2544 // same elements as in 'ep_dont_touch'
2550 // same elements as in 'ep_dont_collide_with'
2562 // !!! maybe this should better be handled by 'ep_diggable' !!!
2567 EL_SP_BUGGY_BASE_ACTIVE,
2574 static int ep_dont_collide_with[] =
2576 // same elements as in 'ep_dont_touch'
2593 static int ep_dont_touch[] =
2603 static int ep_indestructible[] =
2607 EL_ACID_POOL_TOPLEFT,
2608 EL_ACID_POOL_TOPRIGHT,
2609 EL_ACID_POOL_BOTTOMLEFT,
2610 EL_ACID_POOL_BOTTOM,
2611 EL_ACID_POOL_BOTTOMRIGHT,
2612 EL_SP_HARDWARE_GRAY,
2613 EL_SP_HARDWARE_GREEN,
2614 EL_SP_HARDWARE_BLUE,
2616 EL_SP_HARDWARE_YELLOW,
2617 EL_SP_HARDWARE_BASE_1,
2618 EL_SP_HARDWARE_BASE_2,
2619 EL_SP_HARDWARE_BASE_3,
2620 EL_SP_HARDWARE_BASE_4,
2621 EL_SP_HARDWARE_BASE_5,
2622 EL_SP_HARDWARE_BASE_6,
2623 EL_INVISIBLE_STEELWALL,
2624 EL_INVISIBLE_STEELWALL_ACTIVE,
2625 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2626 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2627 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2628 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2629 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2630 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2631 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2632 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2633 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2634 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2635 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2636 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2638 EL_LIGHT_SWITCH_ACTIVE,
2639 EL_SIGN_EXCLAMATION,
2640 EL_SIGN_RADIOACTIVITY,
2647 EL_SIGN_ENTRY_FORBIDDEN,
2648 EL_SIGN_EMERGENCY_EXIT,
2656 EL_STEEL_EXIT_CLOSED,
2658 EL_STEEL_EXIT_OPENING,
2659 EL_STEEL_EXIT_CLOSING,
2660 EL_EM_STEEL_EXIT_CLOSED,
2661 EL_EM_STEEL_EXIT_OPEN,
2662 EL_EM_STEEL_EXIT_OPENING,
2663 EL_EM_STEEL_EXIT_CLOSING,
2664 EL_DC_STEELWALL_1_LEFT,
2665 EL_DC_STEELWALL_1_RIGHT,
2666 EL_DC_STEELWALL_1_TOP,
2667 EL_DC_STEELWALL_1_BOTTOM,
2668 EL_DC_STEELWALL_1_HORIZONTAL,
2669 EL_DC_STEELWALL_1_VERTICAL,
2670 EL_DC_STEELWALL_1_TOPLEFT,
2671 EL_DC_STEELWALL_1_TOPRIGHT,
2672 EL_DC_STEELWALL_1_BOTTOMLEFT,
2673 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2674 EL_DC_STEELWALL_1_TOPLEFT_2,
2675 EL_DC_STEELWALL_1_TOPRIGHT_2,
2676 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2677 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2678 EL_DC_STEELWALL_2_LEFT,
2679 EL_DC_STEELWALL_2_RIGHT,
2680 EL_DC_STEELWALL_2_TOP,
2681 EL_DC_STEELWALL_2_BOTTOM,
2682 EL_DC_STEELWALL_2_HORIZONTAL,
2683 EL_DC_STEELWALL_2_VERTICAL,
2684 EL_DC_STEELWALL_2_MIDDLE,
2685 EL_DC_STEELWALL_2_SINGLE,
2686 EL_STEELWALL_SLIPPERY,
2700 EL_GATE_1_GRAY_ACTIVE,
2701 EL_GATE_2_GRAY_ACTIVE,
2702 EL_GATE_3_GRAY_ACTIVE,
2703 EL_GATE_4_GRAY_ACTIVE,
2712 EL_EM_GATE_1_GRAY_ACTIVE,
2713 EL_EM_GATE_2_GRAY_ACTIVE,
2714 EL_EM_GATE_3_GRAY_ACTIVE,
2715 EL_EM_GATE_4_GRAY_ACTIVE,
2724 EL_EMC_GATE_5_GRAY_ACTIVE,
2725 EL_EMC_GATE_6_GRAY_ACTIVE,
2726 EL_EMC_GATE_7_GRAY_ACTIVE,
2727 EL_EMC_GATE_8_GRAY_ACTIVE,
2729 EL_DC_GATE_WHITE_GRAY,
2730 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2731 EL_DC_GATE_FAKE_GRAY,
2733 EL_SWITCHGATE_OPENING,
2734 EL_SWITCHGATE_CLOSED,
2735 EL_SWITCHGATE_CLOSING,
2736 EL_DC_SWITCHGATE_SWITCH_UP,
2737 EL_DC_SWITCHGATE_SWITCH_DOWN,
2739 EL_TIMEGATE_OPENING,
2741 EL_TIMEGATE_CLOSING,
2742 EL_DC_TIMEGATE_SWITCH,
2743 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2747 EL_TUBE_VERTICAL_LEFT,
2748 EL_TUBE_VERTICAL_RIGHT,
2749 EL_TUBE_HORIZONTAL_UP,
2750 EL_TUBE_HORIZONTAL_DOWN,
2755 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2756 EL_EXPANDABLE_STEELWALL_VERTICAL,
2757 EL_EXPANDABLE_STEELWALL_ANY,
2762 static int ep_slippery[] =
2776 EL_ROBOT_WHEEL_ACTIVE,
2782 EL_ACID_POOL_TOPLEFT,
2783 EL_ACID_POOL_TOPRIGHT,
2793 EL_STEELWALL_SLIPPERY,
2796 EL_EMC_WALL_SLIPPERY_1,
2797 EL_EMC_WALL_SLIPPERY_2,
2798 EL_EMC_WALL_SLIPPERY_3,
2799 EL_EMC_WALL_SLIPPERY_4,
2801 EL_EMC_MAGIC_BALL_ACTIVE,
2806 static int ep_can_change[] =
2811 static int ep_can_move[] =
2813 // same elements as in 'pb_can_move_into_acid'
2836 static int ep_can_fall[] =
2850 EL_QUICKSAND_FAST_FULL,
2852 EL_BD_MAGIC_WALL_FULL,
2853 EL_DC_MAGIC_WALL_FULL,
2867 static int ep_can_smash_player[] =
2893 static int ep_can_smash_enemies[] =
2902 static int ep_can_smash_everything[] =
2911 static int ep_explodes_by_fire[] =
2913 // same elements as in 'ep_explodes_impact'
2918 // same elements as in 'ep_explodes_smashed'
2928 EL_EM_DYNAMITE_ACTIVE,
2929 EL_DYNABOMB_PLAYER_1_ACTIVE,
2930 EL_DYNABOMB_PLAYER_2_ACTIVE,
2931 EL_DYNABOMB_PLAYER_3_ACTIVE,
2932 EL_DYNABOMB_PLAYER_4_ACTIVE,
2933 EL_DYNABOMB_INCREASE_NUMBER,
2934 EL_DYNABOMB_INCREASE_SIZE,
2935 EL_DYNABOMB_INCREASE_POWER,
2936 EL_SP_DISK_RED_ACTIVE,
2950 static int ep_explodes_smashed[] =
2952 // same elements as in 'ep_explodes_impact'
2966 static int ep_explodes_impact[] =
2975 static int ep_walkable_over[] =
2979 EL_SOKOBAN_FIELD_EMPTY,
2986 EL_EM_STEEL_EXIT_OPEN,
2987 EL_EM_STEEL_EXIT_OPENING,
2996 EL_GATE_1_GRAY_ACTIVE,
2997 EL_GATE_2_GRAY_ACTIVE,
2998 EL_GATE_3_GRAY_ACTIVE,
2999 EL_GATE_4_GRAY_ACTIVE,
3007 static int ep_walkable_inside[] =
3012 EL_TUBE_VERTICAL_LEFT,
3013 EL_TUBE_VERTICAL_RIGHT,
3014 EL_TUBE_HORIZONTAL_UP,
3015 EL_TUBE_HORIZONTAL_DOWN,
3024 static int ep_walkable_under[] =
3029 static int ep_passable_over[] =
3039 EL_EM_GATE_1_GRAY_ACTIVE,
3040 EL_EM_GATE_2_GRAY_ACTIVE,
3041 EL_EM_GATE_3_GRAY_ACTIVE,
3042 EL_EM_GATE_4_GRAY_ACTIVE,
3051 EL_EMC_GATE_5_GRAY_ACTIVE,
3052 EL_EMC_GATE_6_GRAY_ACTIVE,
3053 EL_EMC_GATE_7_GRAY_ACTIVE,
3054 EL_EMC_GATE_8_GRAY_ACTIVE,
3056 EL_DC_GATE_WHITE_GRAY,
3057 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3064 static int ep_passable_inside[] =
3070 EL_SP_PORT_HORIZONTAL,
3071 EL_SP_PORT_VERTICAL,
3073 EL_SP_GRAVITY_PORT_LEFT,
3074 EL_SP_GRAVITY_PORT_RIGHT,
3075 EL_SP_GRAVITY_PORT_UP,
3076 EL_SP_GRAVITY_PORT_DOWN,
3077 EL_SP_GRAVITY_ON_PORT_LEFT,
3078 EL_SP_GRAVITY_ON_PORT_RIGHT,
3079 EL_SP_GRAVITY_ON_PORT_UP,
3080 EL_SP_GRAVITY_ON_PORT_DOWN,
3081 EL_SP_GRAVITY_OFF_PORT_LEFT,
3082 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3083 EL_SP_GRAVITY_OFF_PORT_UP,
3084 EL_SP_GRAVITY_OFF_PORT_DOWN,
3089 static int ep_passable_under[] =
3094 static int ep_droppable[] =
3099 static int ep_explodes_1x1_old[] =
3104 static int ep_pushable[] =
3116 EL_SOKOBAN_FIELD_FULL,
3125 static int ep_explodes_cross_old[] =
3130 static int ep_protected[] =
3132 // same elements as in 'ep_walkable_inside'
3136 EL_TUBE_VERTICAL_LEFT,
3137 EL_TUBE_VERTICAL_RIGHT,
3138 EL_TUBE_HORIZONTAL_UP,
3139 EL_TUBE_HORIZONTAL_DOWN,
3145 // same elements as in 'ep_passable_over'
3154 EL_EM_GATE_1_GRAY_ACTIVE,
3155 EL_EM_GATE_2_GRAY_ACTIVE,
3156 EL_EM_GATE_3_GRAY_ACTIVE,
3157 EL_EM_GATE_4_GRAY_ACTIVE,
3166 EL_EMC_GATE_5_GRAY_ACTIVE,
3167 EL_EMC_GATE_6_GRAY_ACTIVE,
3168 EL_EMC_GATE_7_GRAY_ACTIVE,
3169 EL_EMC_GATE_8_GRAY_ACTIVE,
3171 EL_DC_GATE_WHITE_GRAY,
3172 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3176 // same elements as in 'ep_passable_inside'
3181 EL_SP_PORT_HORIZONTAL,
3182 EL_SP_PORT_VERTICAL,
3184 EL_SP_GRAVITY_PORT_LEFT,
3185 EL_SP_GRAVITY_PORT_RIGHT,
3186 EL_SP_GRAVITY_PORT_UP,
3187 EL_SP_GRAVITY_PORT_DOWN,
3188 EL_SP_GRAVITY_ON_PORT_LEFT,
3189 EL_SP_GRAVITY_ON_PORT_RIGHT,
3190 EL_SP_GRAVITY_ON_PORT_UP,
3191 EL_SP_GRAVITY_ON_PORT_DOWN,
3192 EL_SP_GRAVITY_OFF_PORT_LEFT,
3193 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3194 EL_SP_GRAVITY_OFF_PORT_UP,
3195 EL_SP_GRAVITY_OFF_PORT_DOWN,
3200 static int ep_throwable[] =
3205 static int ep_can_explode[] =
3207 // same elements as in 'ep_explodes_impact'
3212 // same elements as in 'ep_explodes_smashed'
3218 // elements that can explode by explosion or by dragonfire
3222 EL_EM_DYNAMITE_ACTIVE,
3223 EL_DYNABOMB_PLAYER_1_ACTIVE,
3224 EL_DYNABOMB_PLAYER_2_ACTIVE,
3225 EL_DYNABOMB_PLAYER_3_ACTIVE,
3226 EL_DYNABOMB_PLAYER_4_ACTIVE,
3227 EL_DYNABOMB_INCREASE_NUMBER,
3228 EL_DYNABOMB_INCREASE_SIZE,
3229 EL_DYNABOMB_INCREASE_POWER,
3230 EL_SP_DISK_RED_ACTIVE,
3238 // elements that can explode only by explosion
3244 static int ep_gravity_reachable[] =
3250 EL_INVISIBLE_SAND_ACTIVE,
3255 EL_SP_PORT_HORIZONTAL,
3256 EL_SP_PORT_VERTICAL,
3258 EL_SP_GRAVITY_PORT_LEFT,
3259 EL_SP_GRAVITY_PORT_RIGHT,
3260 EL_SP_GRAVITY_PORT_UP,
3261 EL_SP_GRAVITY_PORT_DOWN,
3262 EL_SP_GRAVITY_ON_PORT_LEFT,
3263 EL_SP_GRAVITY_ON_PORT_RIGHT,
3264 EL_SP_GRAVITY_ON_PORT_UP,
3265 EL_SP_GRAVITY_ON_PORT_DOWN,
3266 EL_SP_GRAVITY_OFF_PORT_LEFT,
3267 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3268 EL_SP_GRAVITY_OFF_PORT_UP,
3269 EL_SP_GRAVITY_OFF_PORT_DOWN,
3275 static int ep_player[] =
3282 EL_SOKOBAN_FIELD_PLAYER,
3288 static int ep_can_pass_magic_wall[] =
3302 static int ep_can_pass_dc_magic_wall[] =
3318 static int ep_switchable[] =
3322 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3323 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3324 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3325 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3326 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3327 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3328 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3329 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3330 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3331 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3332 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3333 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3334 EL_SWITCHGATE_SWITCH_UP,
3335 EL_SWITCHGATE_SWITCH_DOWN,
3336 EL_DC_SWITCHGATE_SWITCH_UP,
3337 EL_DC_SWITCHGATE_SWITCH_DOWN,
3339 EL_LIGHT_SWITCH_ACTIVE,
3341 EL_DC_TIMEGATE_SWITCH,
3342 EL_BALLOON_SWITCH_LEFT,
3343 EL_BALLOON_SWITCH_RIGHT,
3344 EL_BALLOON_SWITCH_UP,
3345 EL_BALLOON_SWITCH_DOWN,
3346 EL_BALLOON_SWITCH_ANY,
3347 EL_BALLOON_SWITCH_NONE,
3350 EL_EMC_MAGIC_BALL_SWITCH,
3351 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3356 static int ep_bd_element[] =
3390 static int ep_sp_element[] =
3392 // should always be valid
3395 // standard classic Supaplex elements
3402 EL_SP_HARDWARE_GRAY,
3410 EL_SP_GRAVITY_PORT_RIGHT,
3411 EL_SP_GRAVITY_PORT_DOWN,
3412 EL_SP_GRAVITY_PORT_LEFT,
3413 EL_SP_GRAVITY_PORT_UP,
3418 EL_SP_PORT_VERTICAL,
3419 EL_SP_PORT_HORIZONTAL,
3425 EL_SP_HARDWARE_BASE_1,
3426 EL_SP_HARDWARE_GREEN,
3427 EL_SP_HARDWARE_BLUE,
3429 EL_SP_HARDWARE_YELLOW,
3430 EL_SP_HARDWARE_BASE_2,
3431 EL_SP_HARDWARE_BASE_3,
3432 EL_SP_HARDWARE_BASE_4,
3433 EL_SP_HARDWARE_BASE_5,
3434 EL_SP_HARDWARE_BASE_6,
3438 // additional elements that appeared in newer Supaplex levels
3441 // additional gravity port elements (not switching, but setting gravity)
3442 EL_SP_GRAVITY_ON_PORT_LEFT,
3443 EL_SP_GRAVITY_ON_PORT_RIGHT,
3444 EL_SP_GRAVITY_ON_PORT_UP,
3445 EL_SP_GRAVITY_ON_PORT_DOWN,
3446 EL_SP_GRAVITY_OFF_PORT_LEFT,
3447 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3448 EL_SP_GRAVITY_OFF_PORT_UP,
3449 EL_SP_GRAVITY_OFF_PORT_DOWN,
3451 // more than one Murphy in a level results in an inactive clone
3454 // runtime Supaplex elements
3455 EL_SP_DISK_RED_ACTIVE,
3456 EL_SP_TERMINAL_ACTIVE,
3457 EL_SP_BUGGY_BASE_ACTIVATING,
3458 EL_SP_BUGGY_BASE_ACTIVE,
3465 static int ep_sb_element[] =
3470 EL_SOKOBAN_FIELD_EMPTY,
3471 EL_SOKOBAN_FIELD_FULL,
3472 EL_SOKOBAN_FIELD_PLAYER,
3477 EL_INVISIBLE_STEELWALL,
3482 static int ep_gem[] =
3494 static int ep_food_dark_yamyam[] =
3522 static int ep_food_penguin[] =
3536 static int ep_food_pig[] =
3548 static int ep_historic_wall[] =
3559 EL_GATE_1_GRAY_ACTIVE,
3560 EL_GATE_2_GRAY_ACTIVE,
3561 EL_GATE_3_GRAY_ACTIVE,
3562 EL_GATE_4_GRAY_ACTIVE,
3571 EL_EM_GATE_1_GRAY_ACTIVE,
3572 EL_EM_GATE_2_GRAY_ACTIVE,
3573 EL_EM_GATE_3_GRAY_ACTIVE,
3574 EL_EM_GATE_4_GRAY_ACTIVE,
3581 EL_EXPANDABLE_WALL_HORIZONTAL,
3582 EL_EXPANDABLE_WALL_VERTICAL,
3583 EL_EXPANDABLE_WALL_ANY,
3584 EL_EXPANDABLE_WALL_GROWING,
3585 EL_BD_EXPANDABLE_WALL,
3592 EL_SP_HARDWARE_GRAY,
3593 EL_SP_HARDWARE_GREEN,
3594 EL_SP_HARDWARE_BLUE,
3596 EL_SP_HARDWARE_YELLOW,
3597 EL_SP_HARDWARE_BASE_1,
3598 EL_SP_HARDWARE_BASE_2,
3599 EL_SP_HARDWARE_BASE_3,
3600 EL_SP_HARDWARE_BASE_4,
3601 EL_SP_HARDWARE_BASE_5,
3602 EL_SP_HARDWARE_BASE_6,
3604 EL_SP_TERMINAL_ACTIVE,
3607 EL_INVISIBLE_STEELWALL,
3608 EL_INVISIBLE_STEELWALL_ACTIVE,
3610 EL_INVISIBLE_WALL_ACTIVE,
3611 EL_STEELWALL_SLIPPERY,
3628 static int ep_historic_solid[] =
3632 EL_EXPANDABLE_WALL_HORIZONTAL,
3633 EL_EXPANDABLE_WALL_VERTICAL,
3634 EL_EXPANDABLE_WALL_ANY,
3635 EL_BD_EXPANDABLE_WALL,
3648 EL_QUICKSAND_FILLING,
3649 EL_QUICKSAND_EMPTYING,
3651 EL_MAGIC_WALL_ACTIVE,
3652 EL_MAGIC_WALL_EMPTYING,
3653 EL_MAGIC_WALL_FILLING,
3657 EL_BD_MAGIC_WALL_ACTIVE,
3658 EL_BD_MAGIC_WALL_EMPTYING,
3659 EL_BD_MAGIC_WALL_FULL,
3660 EL_BD_MAGIC_WALL_FILLING,
3661 EL_BD_MAGIC_WALL_DEAD,
3670 EL_SP_TERMINAL_ACTIVE,
3674 EL_INVISIBLE_WALL_ACTIVE,
3675 EL_SWITCHGATE_SWITCH_UP,
3676 EL_SWITCHGATE_SWITCH_DOWN,
3678 EL_TIMEGATE_SWITCH_ACTIVE,
3690 // the following elements are a direct copy of "indestructible" elements,
3691 // except "EL_ACID", which is "indestructible", but not "solid"!
3696 EL_ACID_POOL_TOPLEFT,
3697 EL_ACID_POOL_TOPRIGHT,
3698 EL_ACID_POOL_BOTTOMLEFT,
3699 EL_ACID_POOL_BOTTOM,
3700 EL_ACID_POOL_BOTTOMRIGHT,
3701 EL_SP_HARDWARE_GRAY,
3702 EL_SP_HARDWARE_GREEN,
3703 EL_SP_HARDWARE_BLUE,
3705 EL_SP_HARDWARE_YELLOW,
3706 EL_SP_HARDWARE_BASE_1,
3707 EL_SP_HARDWARE_BASE_2,
3708 EL_SP_HARDWARE_BASE_3,
3709 EL_SP_HARDWARE_BASE_4,
3710 EL_SP_HARDWARE_BASE_5,
3711 EL_SP_HARDWARE_BASE_6,
3712 EL_INVISIBLE_STEELWALL,
3713 EL_INVISIBLE_STEELWALL_ACTIVE,
3714 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3715 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3716 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3717 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3718 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3719 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3720 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3721 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3722 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3723 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3724 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3725 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3727 EL_LIGHT_SWITCH_ACTIVE,
3728 EL_SIGN_EXCLAMATION,
3729 EL_SIGN_RADIOACTIVITY,
3736 EL_SIGN_ENTRY_FORBIDDEN,
3737 EL_SIGN_EMERGENCY_EXIT,
3745 EL_STEEL_EXIT_CLOSED,
3747 EL_STEEL_EXIT_OPENING,
3748 EL_STEEL_EXIT_CLOSING,
3749 EL_EM_STEEL_EXIT_CLOSED,
3750 EL_EM_STEEL_EXIT_OPEN,
3751 EL_EM_STEEL_EXIT_OPENING,
3752 EL_EM_STEEL_EXIT_CLOSING,
3753 EL_DC_STEELWALL_1_LEFT,
3754 EL_DC_STEELWALL_1_RIGHT,
3755 EL_DC_STEELWALL_1_TOP,
3756 EL_DC_STEELWALL_1_BOTTOM,
3757 EL_DC_STEELWALL_1_HORIZONTAL,
3758 EL_DC_STEELWALL_1_VERTICAL,
3759 EL_DC_STEELWALL_1_TOPLEFT,
3760 EL_DC_STEELWALL_1_TOPRIGHT,
3761 EL_DC_STEELWALL_1_BOTTOMLEFT,
3762 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3763 EL_DC_STEELWALL_1_TOPLEFT_2,
3764 EL_DC_STEELWALL_1_TOPRIGHT_2,
3765 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3766 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3767 EL_DC_STEELWALL_2_LEFT,
3768 EL_DC_STEELWALL_2_RIGHT,
3769 EL_DC_STEELWALL_2_TOP,
3770 EL_DC_STEELWALL_2_BOTTOM,
3771 EL_DC_STEELWALL_2_HORIZONTAL,
3772 EL_DC_STEELWALL_2_VERTICAL,
3773 EL_DC_STEELWALL_2_MIDDLE,
3774 EL_DC_STEELWALL_2_SINGLE,
3775 EL_STEELWALL_SLIPPERY,
3789 EL_GATE_1_GRAY_ACTIVE,
3790 EL_GATE_2_GRAY_ACTIVE,
3791 EL_GATE_3_GRAY_ACTIVE,
3792 EL_GATE_4_GRAY_ACTIVE,
3801 EL_EM_GATE_1_GRAY_ACTIVE,
3802 EL_EM_GATE_2_GRAY_ACTIVE,
3803 EL_EM_GATE_3_GRAY_ACTIVE,
3804 EL_EM_GATE_4_GRAY_ACTIVE,
3813 EL_EMC_GATE_5_GRAY_ACTIVE,
3814 EL_EMC_GATE_6_GRAY_ACTIVE,
3815 EL_EMC_GATE_7_GRAY_ACTIVE,
3816 EL_EMC_GATE_8_GRAY_ACTIVE,
3818 EL_DC_GATE_WHITE_GRAY,
3819 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3820 EL_DC_GATE_FAKE_GRAY,
3822 EL_SWITCHGATE_OPENING,
3823 EL_SWITCHGATE_CLOSED,
3824 EL_SWITCHGATE_CLOSING,
3825 EL_DC_SWITCHGATE_SWITCH_UP,
3826 EL_DC_SWITCHGATE_SWITCH_DOWN,
3828 EL_TIMEGATE_OPENING,
3830 EL_TIMEGATE_CLOSING,
3831 EL_DC_TIMEGATE_SWITCH,
3832 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3836 EL_TUBE_VERTICAL_LEFT,
3837 EL_TUBE_VERTICAL_RIGHT,
3838 EL_TUBE_HORIZONTAL_UP,
3839 EL_TUBE_HORIZONTAL_DOWN,
3844 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3845 EL_EXPANDABLE_STEELWALL_VERTICAL,
3846 EL_EXPANDABLE_STEELWALL_ANY,
3851 static int ep_classic_enemy[] =
3868 static int ep_belt[] =
3870 EL_CONVEYOR_BELT_1_LEFT,
3871 EL_CONVEYOR_BELT_1_MIDDLE,
3872 EL_CONVEYOR_BELT_1_RIGHT,
3873 EL_CONVEYOR_BELT_2_LEFT,
3874 EL_CONVEYOR_BELT_2_MIDDLE,
3875 EL_CONVEYOR_BELT_2_RIGHT,
3876 EL_CONVEYOR_BELT_3_LEFT,
3877 EL_CONVEYOR_BELT_3_MIDDLE,
3878 EL_CONVEYOR_BELT_3_RIGHT,
3879 EL_CONVEYOR_BELT_4_LEFT,
3880 EL_CONVEYOR_BELT_4_MIDDLE,
3881 EL_CONVEYOR_BELT_4_RIGHT,
3886 static int ep_belt_active[] =
3888 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3889 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3890 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3891 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3892 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3893 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3894 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3895 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3896 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3897 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3898 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3899 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3904 static int ep_belt_switch[] =
3906 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3907 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3908 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3909 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3910 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3911 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3912 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3913 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3914 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3915 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3916 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3917 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3922 static int ep_tube[] =
3929 EL_TUBE_HORIZONTAL_UP,
3930 EL_TUBE_HORIZONTAL_DOWN,
3932 EL_TUBE_VERTICAL_LEFT,
3933 EL_TUBE_VERTICAL_RIGHT,
3939 static int ep_acid_pool[] =
3941 EL_ACID_POOL_TOPLEFT,
3942 EL_ACID_POOL_TOPRIGHT,
3943 EL_ACID_POOL_BOTTOMLEFT,
3944 EL_ACID_POOL_BOTTOM,
3945 EL_ACID_POOL_BOTTOMRIGHT,
3950 static int ep_keygate[] =
3960 EL_GATE_1_GRAY_ACTIVE,
3961 EL_GATE_2_GRAY_ACTIVE,
3962 EL_GATE_3_GRAY_ACTIVE,
3963 EL_GATE_4_GRAY_ACTIVE,
3972 EL_EM_GATE_1_GRAY_ACTIVE,
3973 EL_EM_GATE_2_GRAY_ACTIVE,
3974 EL_EM_GATE_3_GRAY_ACTIVE,
3975 EL_EM_GATE_4_GRAY_ACTIVE,
3984 EL_EMC_GATE_5_GRAY_ACTIVE,
3985 EL_EMC_GATE_6_GRAY_ACTIVE,
3986 EL_EMC_GATE_7_GRAY_ACTIVE,
3987 EL_EMC_GATE_8_GRAY_ACTIVE,
3989 EL_DC_GATE_WHITE_GRAY,
3990 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3995 static int ep_amoeboid[] =
4007 static int ep_amoebalive[] =
4018 static int ep_has_editor_content[] =
4024 EL_SOKOBAN_FIELD_PLAYER,
4041 static int ep_can_turn_each_move[] =
4043 // !!! do something with this one !!!
4047 static int ep_can_grow[] =
4061 static int ep_active_bomb[] =
4064 EL_EM_DYNAMITE_ACTIVE,
4065 EL_DYNABOMB_PLAYER_1_ACTIVE,
4066 EL_DYNABOMB_PLAYER_2_ACTIVE,
4067 EL_DYNABOMB_PLAYER_3_ACTIVE,
4068 EL_DYNABOMB_PLAYER_4_ACTIVE,
4069 EL_SP_DISK_RED_ACTIVE,
4074 static int ep_inactive[] =
4084 EL_QUICKSAND_FAST_EMPTY,
4107 EL_GATE_1_GRAY_ACTIVE,
4108 EL_GATE_2_GRAY_ACTIVE,
4109 EL_GATE_3_GRAY_ACTIVE,
4110 EL_GATE_4_GRAY_ACTIVE,
4119 EL_EM_GATE_1_GRAY_ACTIVE,
4120 EL_EM_GATE_2_GRAY_ACTIVE,
4121 EL_EM_GATE_3_GRAY_ACTIVE,
4122 EL_EM_GATE_4_GRAY_ACTIVE,
4131 EL_EMC_GATE_5_GRAY_ACTIVE,
4132 EL_EMC_GATE_6_GRAY_ACTIVE,
4133 EL_EMC_GATE_7_GRAY_ACTIVE,
4134 EL_EMC_GATE_8_GRAY_ACTIVE,
4136 EL_DC_GATE_WHITE_GRAY,
4137 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4138 EL_DC_GATE_FAKE_GRAY,
4141 EL_INVISIBLE_STEELWALL,
4149 EL_WALL_EMERALD_YELLOW,
4150 EL_DYNABOMB_INCREASE_NUMBER,
4151 EL_DYNABOMB_INCREASE_SIZE,
4152 EL_DYNABOMB_INCREASE_POWER,
4156 EL_SOKOBAN_FIELD_EMPTY,
4157 EL_SOKOBAN_FIELD_FULL,
4158 EL_WALL_EMERALD_RED,
4159 EL_WALL_EMERALD_PURPLE,
4160 EL_ACID_POOL_TOPLEFT,
4161 EL_ACID_POOL_TOPRIGHT,
4162 EL_ACID_POOL_BOTTOMLEFT,
4163 EL_ACID_POOL_BOTTOM,
4164 EL_ACID_POOL_BOTTOMRIGHT,
4168 EL_BD_MAGIC_WALL_DEAD,
4170 EL_DC_MAGIC_WALL_DEAD,
4171 EL_AMOEBA_TO_DIAMOND,
4179 EL_SP_GRAVITY_PORT_RIGHT,
4180 EL_SP_GRAVITY_PORT_DOWN,
4181 EL_SP_GRAVITY_PORT_LEFT,
4182 EL_SP_GRAVITY_PORT_UP,
4183 EL_SP_PORT_HORIZONTAL,
4184 EL_SP_PORT_VERTICAL,
4195 EL_SP_HARDWARE_GRAY,
4196 EL_SP_HARDWARE_GREEN,
4197 EL_SP_HARDWARE_BLUE,
4199 EL_SP_HARDWARE_YELLOW,
4200 EL_SP_HARDWARE_BASE_1,
4201 EL_SP_HARDWARE_BASE_2,
4202 EL_SP_HARDWARE_BASE_3,
4203 EL_SP_HARDWARE_BASE_4,
4204 EL_SP_HARDWARE_BASE_5,
4205 EL_SP_HARDWARE_BASE_6,
4206 EL_SP_GRAVITY_ON_PORT_LEFT,
4207 EL_SP_GRAVITY_ON_PORT_RIGHT,
4208 EL_SP_GRAVITY_ON_PORT_UP,
4209 EL_SP_GRAVITY_ON_PORT_DOWN,
4210 EL_SP_GRAVITY_OFF_PORT_LEFT,
4211 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4212 EL_SP_GRAVITY_OFF_PORT_UP,
4213 EL_SP_GRAVITY_OFF_PORT_DOWN,
4214 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4215 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4216 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4217 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4218 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4219 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4220 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4221 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4222 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4223 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4224 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4225 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4226 EL_SIGN_EXCLAMATION,
4227 EL_SIGN_RADIOACTIVITY,
4234 EL_SIGN_ENTRY_FORBIDDEN,
4235 EL_SIGN_EMERGENCY_EXIT,
4243 EL_DC_STEELWALL_1_LEFT,
4244 EL_DC_STEELWALL_1_RIGHT,
4245 EL_DC_STEELWALL_1_TOP,
4246 EL_DC_STEELWALL_1_BOTTOM,
4247 EL_DC_STEELWALL_1_HORIZONTAL,
4248 EL_DC_STEELWALL_1_VERTICAL,
4249 EL_DC_STEELWALL_1_TOPLEFT,
4250 EL_DC_STEELWALL_1_TOPRIGHT,
4251 EL_DC_STEELWALL_1_BOTTOMLEFT,
4252 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4253 EL_DC_STEELWALL_1_TOPLEFT_2,
4254 EL_DC_STEELWALL_1_TOPRIGHT_2,
4255 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4256 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4257 EL_DC_STEELWALL_2_LEFT,
4258 EL_DC_STEELWALL_2_RIGHT,
4259 EL_DC_STEELWALL_2_TOP,
4260 EL_DC_STEELWALL_2_BOTTOM,
4261 EL_DC_STEELWALL_2_HORIZONTAL,
4262 EL_DC_STEELWALL_2_VERTICAL,
4263 EL_DC_STEELWALL_2_MIDDLE,
4264 EL_DC_STEELWALL_2_SINGLE,
4265 EL_STEELWALL_SLIPPERY,
4270 EL_EMC_WALL_SLIPPERY_1,
4271 EL_EMC_WALL_SLIPPERY_2,
4272 EL_EMC_WALL_SLIPPERY_3,
4273 EL_EMC_WALL_SLIPPERY_4,
4294 static int ep_em_slippery_wall[] =
4299 static int ep_gfx_crumbled[] =
4310 static int ep_editor_cascade_active[] =
4312 EL_INTERNAL_CASCADE_BD_ACTIVE,
4313 EL_INTERNAL_CASCADE_EM_ACTIVE,
4314 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4315 EL_INTERNAL_CASCADE_RND_ACTIVE,
4316 EL_INTERNAL_CASCADE_SB_ACTIVE,
4317 EL_INTERNAL_CASCADE_SP_ACTIVE,
4318 EL_INTERNAL_CASCADE_DC_ACTIVE,
4319 EL_INTERNAL_CASCADE_DX_ACTIVE,
4320 EL_INTERNAL_CASCADE_MM_ACTIVE,
4321 EL_INTERNAL_CASCADE_DF_ACTIVE,
4322 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4323 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4324 EL_INTERNAL_CASCADE_CE_ACTIVE,
4325 EL_INTERNAL_CASCADE_GE_ACTIVE,
4326 EL_INTERNAL_CASCADE_REF_ACTIVE,
4327 EL_INTERNAL_CASCADE_USER_ACTIVE,
4328 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4333 static int ep_editor_cascade_inactive[] =
4335 EL_INTERNAL_CASCADE_BD,
4336 EL_INTERNAL_CASCADE_EM,
4337 EL_INTERNAL_CASCADE_EMC,
4338 EL_INTERNAL_CASCADE_RND,
4339 EL_INTERNAL_CASCADE_SB,
4340 EL_INTERNAL_CASCADE_SP,
4341 EL_INTERNAL_CASCADE_DC,
4342 EL_INTERNAL_CASCADE_DX,
4343 EL_INTERNAL_CASCADE_MM,
4344 EL_INTERNAL_CASCADE_DF,
4345 EL_INTERNAL_CASCADE_CHARS,
4346 EL_INTERNAL_CASCADE_STEEL_CHARS,
4347 EL_INTERNAL_CASCADE_CE,
4348 EL_INTERNAL_CASCADE_GE,
4349 EL_INTERNAL_CASCADE_REF,
4350 EL_INTERNAL_CASCADE_USER,
4351 EL_INTERNAL_CASCADE_DYNAMIC,
4356 static int ep_obsolete[] =
4360 EL_EM_KEY_1_FILE_OBSOLETE,
4361 EL_EM_KEY_2_FILE_OBSOLETE,
4362 EL_EM_KEY_3_FILE_OBSOLETE,
4363 EL_EM_KEY_4_FILE_OBSOLETE,
4364 EL_ENVELOPE_OBSOLETE,
4373 } element_properties[] =
4375 { ep_diggable, EP_DIGGABLE },
4376 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4377 { ep_dont_run_into, EP_DONT_RUN_INTO },
4378 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4379 { ep_dont_touch, EP_DONT_TOUCH },
4380 { ep_indestructible, EP_INDESTRUCTIBLE },
4381 { ep_slippery, EP_SLIPPERY },
4382 { ep_can_change, EP_CAN_CHANGE },
4383 { ep_can_move, EP_CAN_MOVE },
4384 { ep_can_fall, EP_CAN_FALL },
4385 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4386 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4387 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4388 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4389 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4390 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4391 { ep_walkable_over, EP_WALKABLE_OVER },
4392 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4393 { ep_walkable_under, EP_WALKABLE_UNDER },
4394 { ep_passable_over, EP_PASSABLE_OVER },
4395 { ep_passable_inside, EP_PASSABLE_INSIDE },
4396 { ep_passable_under, EP_PASSABLE_UNDER },
4397 { ep_droppable, EP_DROPPABLE },
4398 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4399 { ep_pushable, EP_PUSHABLE },
4400 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4401 { ep_protected, EP_PROTECTED },
4402 { ep_throwable, EP_THROWABLE },
4403 { ep_can_explode, EP_CAN_EXPLODE },
4404 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4406 { ep_player, EP_PLAYER },
4407 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4408 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4409 { ep_switchable, EP_SWITCHABLE },
4410 { ep_bd_element, EP_BD_ELEMENT },
4411 { ep_sp_element, EP_SP_ELEMENT },
4412 { ep_sb_element, EP_SB_ELEMENT },
4414 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4415 { ep_food_penguin, EP_FOOD_PENGUIN },
4416 { ep_food_pig, EP_FOOD_PIG },
4417 { ep_historic_wall, EP_HISTORIC_WALL },
4418 { ep_historic_solid, EP_HISTORIC_SOLID },
4419 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4420 { ep_belt, EP_BELT },
4421 { ep_belt_active, EP_BELT_ACTIVE },
4422 { ep_belt_switch, EP_BELT_SWITCH },
4423 { ep_tube, EP_TUBE },
4424 { ep_acid_pool, EP_ACID_POOL },
4425 { ep_keygate, EP_KEYGATE },
4426 { ep_amoeboid, EP_AMOEBOID },
4427 { ep_amoebalive, EP_AMOEBALIVE },
4428 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4429 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4430 { ep_can_grow, EP_CAN_GROW },
4431 { ep_active_bomb, EP_ACTIVE_BOMB },
4432 { ep_inactive, EP_INACTIVE },
4434 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4436 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4438 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4439 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4441 { ep_obsolete, EP_OBSOLETE },
4448 // always start with reliable default values (element has no properties)
4449 // (but never initialize clipboard elements after the very first time)
4450 // (to be able to use clipboard elements between several levels)
4451 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4452 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4453 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4454 SET_PROPERTY(i, j, FALSE);
4456 // set all base element properties from above array definitions
4457 for (i = 0; element_properties[i].elements != NULL; i++)
4458 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4459 SET_PROPERTY((element_properties[i].elements)[j],
4460 element_properties[i].property, TRUE);
4462 // copy properties to some elements that are only stored in level file
4463 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4464 for (j = 0; copy_properties[j][0] != -1; j++)
4465 if (HAS_PROPERTY(copy_properties[j][0], i))
4466 for (k = 1; k <= 4; k++)
4467 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4469 // set static element properties that are not listed in array definitions
4470 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4471 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4473 clipboard_elements_initialized = TRUE;
4476 void InitElementPropertiesEngine(int engine_version)
4478 static int no_wall_properties[] =
4481 EP_COLLECTIBLE_ONLY,
4483 EP_DONT_COLLIDE_WITH,
4486 EP_CAN_SMASH_PLAYER,
4487 EP_CAN_SMASH_ENEMIES,
4488 EP_CAN_SMASH_EVERYTHING,
4493 EP_FOOD_DARK_YAMYAM,
4509 /* important: after initialization in InitElementPropertiesStatic(), the
4510 elements are not again initialized to a default value; therefore all
4511 changes have to make sure that they leave the element with a defined
4512 property (which means that conditional property changes must be set to
4513 a reliable default value before) */
4515 // resolve group elements
4516 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4517 ResolveGroupElement(EL_GROUP_START + i);
4519 // set all special, combined or engine dependent element properties
4520 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4522 // do not change (already initialized) clipboard elements here
4523 if (IS_CLIPBOARD_ELEMENT(i))
4526 // ---------- INACTIVE ----------------------------------------------------
4527 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4528 i <= EL_CHAR_END) ||
4529 (i >= EL_STEEL_CHAR_START &&
4530 i <= EL_STEEL_CHAR_END)));
4532 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4533 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4534 IS_WALKABLE_INSIDE(i) ||
4535 IS_WALKABLE_UNDER(i)));
4537 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4538 IS_PASSABLE_INSIDE(i) ||
4539 IS_PASSABLE_UNDER(i)));
4541 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4542 IS_PASSABLE_OVER(i)));
4544 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4545 IS_PASSABLE_INSIDE(i)));
4547 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4548 IS_PASSABLE_UNDER(i)));
4550 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4553 // ---------- COLLECTIBLE -------------------------------------------------
4554 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4558 // ---------- SNAPPABLE ---------------------------------------------------
4559 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4560 IS_COLLECTIBLE(i) ||
4564 // ---------- WALL --------------------------------------------------------
4565 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4567 for (j = 0; no_wall_properties[j] != -1; j++)
4568 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4569 i >= EL_FIRST_RUNTIME_UNREAL)
4570 SET_PROPERTY(i, EP_WALL, FALSE);
4572 if (IS_HISTORIC_WALL(i))
4573 SET_PROPERTY(i, EP_WALL, TRUE);
4575 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4576 if (engine_version < VERSION_IDENT(2,2,0,0))
4577 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4579 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4581 !IS_COLLECTIBLE(i)));
4583 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4584 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4585 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4587 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4590 // ---------- EXPLOSION_PROOF ---------------------------------------------
4592 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4593 else if (engine_version < VERSION_IDENT(2,2,0,0))
4594 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4596 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4600 if (IS_CUSTOM_ELEMENT(i))
4602 // these are additional properties which are initially false when set
4604 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4606 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4607 if (DONT_COLLIDE_WITH(i))
4608 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4610 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4611 if (CAN_SMASH_EVERYTHING(i))
4612 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4613 if (CAN_SMASH_ENEMIES(i))
4614 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4617 // ---------- CAN_SMASH ---------------------------------------------------
4618 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4619 CAN_SMASH_ENEMIES(i) ||
4620 CAN_SMASH_EVERYTHING(i)));
4622 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4623 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4624 EXPLODES_BY_FIRE(i)));
4626 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4627 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4628 EXPLODES_SMASHED(i)));
4630 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4631 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4632 EXPLODES_IMPACT(i)));
4634 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4635 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4637 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4638 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4639 i == EL_BLACK_ORB));
4641 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4642 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4644 IS_CUSTOM_ELEMENT(i)));
4646 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4647 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4648 i == EL_SP_ELECTRON));
4650 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4651 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4652 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4653 getMoveIntoAcidProperty(&level, i));
4655 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4656 if (MAYBE_DONT_COLLIDE_WITH(i))
4657 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4658 getDontCollideWithProperty(&level, i));
4660 // ---------- SP_PORT -----------------------------------------------------
4661 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4662 IS_PASSABLE_INSIDE(i)));
4664 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4665 for (j = 0; j < level.num_android_clone_elements; j++)
4666 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4668 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4670 // ---------- CAN_CHANGE --------------------------------------------------
4671 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4672 for (j = 0; j < element_info[i].num_change_pages; j++)
4673 if (element_info[i].change_page[j].can_change)
4674 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4676 // ---------- HAS_ACTION --------------------------------------------------
4677 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4678 for (j = 0; j < element_info[i].num_change_pages; j++)
4679 if (element_info[i].change_page[j].has_action)
4680 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4682 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4683 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4686 // ---------- GFX_CRUMBLED ------------------------------------------------
4687 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4688 element_info[i].crumbled[ACTION_DEFAULT] !=
4689 element_info[i].graphic[ACTION_DEFAULT]);
4691 // ---------- EDITOR_CASCADE ----------------------------------------------
4692 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4693 IS_EDITOR_CASCADE_INACTIVE(i)));
4696 // dynamically adjust element properties according to game engine version
4698 static int ep_em_slippery_wall[] =
4703 EL_EXPANDABLE_WALL_HORIZONTAL,
4704 EL_EXPANDABLE_WALL_VERTICAL,
4705 EL_EXPANDABLE_WALL_ANY,
4706 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4707 EL_EXPANDABLE_STEELWALL_VERTICAL,
4708 EL_EXPANDABLE_STEELWALL_ANY,
4709 EL_EXPANDABLE_STEELWALL_GROWING,
4713 static int ep_em_explodes_by_fire[] =
4716 EL_EM_DYNAMITE_ACTIVE,
4721 // special EM style gems behaviour
4722 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4723 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4724 level.em_slippery_gems);
4726 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4727 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4728 (level.em_slippery_gems &&
4729 engine_version > VERSION_IDENT(2,0,1,0)));
4731 // special EM style explosion behaviour regarding chain reactions
4732 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4733 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4734 level.em_explodes_by_fire);
4737 // this is needed because some graphics depend on element properties
4738 if (game_status == GAME_MODE_PLAYING)
4739 InitElementGraphicInfo();
4742 void InitElementPropertiesGfxElement(void)
4746 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4748 struct ElementInfo *ei = &element_info[i];
4750 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4754 static void InitGlobal(void)
4759 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4761 // check if element_name_info entry defined for each element in "main.h"
4762 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4763 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4765 element_info[i].token_name = element_name_info[i].token_name;
4766 element_info[i].class_name = element_name_info[i].class_name;
4767 element_info[i].editor_description= element_name_info[i].editor_description;
4770 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4772 // check if global_anim_name_info defined for each entry in "main.h"
4773 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4774 global_anim_name_info[i].token_name == NULL)
4775 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4777 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4780 // create hash from image config list
4781 image_config_hash = newSetupFileHash();
4782 for (i = 0; image_config[i].token != NULL; i++)
4783 setHashEntry(image_config_hash,
4784 image_config[i].token,
4785 image_config[i].value);
4787 // create hash from element token list
4788 element_token_hash = newSetupFileHash();
4789 for (i = 0; element_name_info[i].token_name != NULL; i++)
4790 setHashEntry(element_token_hash,
4791 element_name_info[i].token_name,
4794 // create hash from graphic token list
4795 graphic_token_hash = newSetupFileHash();
4796 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4797 if (strSuffix(image_config[i].value, ".png") ||
4798 strSuffix(image_config[i].value, ".pcx") ||
4799 strSuffix(image_config[i].value, ".wav") ||
4800 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4801 setHashEntry(graphic_token_hash,
4802 image_config[i].token,
4803 int2str(graphic++, 0));
4805 // create hash from font token list
4806 font_token_hash = newSetupFileHash();
4807 for (i = 0; font_info[i].token_name != NULL; i++)
4808 setHashEntry(font_token_hash,
4809 font_info[i].token_name,
4812 // set default filenames for all cloned graphics in static configuration
4813 for (i = 0; image_config[i].token != NULL; i++)
4815 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4817 char *token = image_config[i].token;
4818 char *token_clone_from = getStringCat2(token, ".clone_from");
4819 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4821 if (token_cloned != NULL)
4823 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4825 if (value_cloned != NULL)
4827 // set default filename in static configuration
4828 image_config[i].value = value_cloned;
4830 // set default filename in image config hash
4831 setHashEntry(image_config_hash, token, value_cloned);
4835 free(token_clone_from);
4839 // always start with reliable default values (all elements)
4840 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4841 ActiveElement[i] = i;
4843 // now add all entries that have an active state (active elements)
4844 for (i = 0; element_with_active_state[i].element != -1; i++)
4846 int element = element_with_active_state[i].element;
4847 int element_active = element_with_active_state[i].element_active;
4849 ActiveElement[element] = element_active;
4852 // always start with reliable default values (all buttons)
4853 for (i = 0; i < NUM_IMAGE_FILES; i++)
4854 ActiveButton[i] = i;
4856 // now add all entries that have an active state (active buttons)
4857 for (i = 0; button_with_active_state[i].button != -1; i++)
4859 int button = button_with_active_state[i].button;
4860 int button_active = button_with_active_state[i].button_active;
4862 ActiveButton[button] = button_active;
4865 // always start with reliable default values (all fonts)
4866 for (i = 0; i < NUM_FONTS; i++)
4869 // now add all entries that have an active state (active fonts)
4870 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4872 int font = font_with_active_state[i].font_nr;
4873 int font_active = font_with_active_state[i].font_nr_active;
4875 ActiveFont[font] = font_active;
4878 global.autoplay_leveldir = NULL;
4879 global.convert_leveldir = NULL;
4880 global.create_images_dir = NULL;
4882 global.frames_per_second = 0;
4883 global.show_frames_per_second = FALSE;
4885 global.border_status = GAME_MODE_LOADING;
4886 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4888 global.use_envelope_request = FALSE;
4891 static void Execute_Command(char *command)
4895 if (strEqual(command, "print graphicsinfo.conf"))
4897 Print("# You can configure additional/alternative image files here.\n");
4898 Print("# (The entries below are default and therefore commented out.)\n");
4900 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4902 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4905 for (i = 0; image_config[i].token != NULL; i++)
4906 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4907 image_config[i].value));
4911 else if (strEqual(command, "print soundsinfo.conf"))
4913 Print("# You can configure additional/alternative sound files here.\n");
4914 Print("# (The entries below are default and therefore commented out.)\n");
4916 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4918 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4921 for (i = 0; sound_config[i].token != NULL; i++)
4922 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4923 sound_config[i].value));
4927 else if (strEqual(command, "print musicinfo.conf"))
4929 Print("# You can configure additional/alternative music files here.\n");
4930 Print("# (The entries below are default and therefore commented out.)\n");
4932 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4934 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4937 for (i = 0; music_config[i].token != NULL; i++)
4938 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4939 music_config[i].value));
4943 else if (strEqual(command, "print editorsetup.conf"))
4945 Print("# You can configure your personal editor element list here.\n");
4946 Print("# (The entries below are default and therefore commented out.)\n");
4949 // this is needed to be able to check element list for cascade elements
4950 InitElementPropertiesStatic();
4951 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4953 PrintEditorElementList();
4957 else if (strEqual(command, "print helpanim.conf"))
4959 Print("# You can configure different element help animations here.\n");
4960 Print("# (The entries below are default and therefore commented out.)\n");
4963 for (i = 0; helpanim_config[i].token != NULL; i++)
4965 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4966 helpanim_config[i].value));
4968 if (strEqual(helpanim_config[i].token, "end"))
4974 else if (strEqual(command, "print helptext.conf"))
4976 Print("# You can configure different element help text here.\n");
4977 Print("# (The entries below are default and therefore commented out.)\n");
4980 for (i = 0; helptext_config[i].token != NULL; i++)
4981 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4982 helptext_config[i].value));
4986 else if (strPrefix(command, "dump level "))
4988 char *filename = &command[11];
4990 if (!fileExists(filename))
4991 Error(ERR_EXIT, "cannot open file '%s'", filename);
4993 LoadLevelFromFilename(&level, filename);
4998 else if (strPrefix(command, "dump tape "))
5000 char *filename = &command[10];
5002 if (!fileExists(filename))
5003 Error(ERR_EXIT, "cannot open file '%s'", filename);
5005 LoadTapeFromFilename(filename);
5010 else if (strPrefix(command, "autotest ") ||
5011 strPrefix(command, "autoplay ") ||
5012 strPrefix(command, "autoffwd ") ||
5013 strPrefix(command, "autowarp "))
5015 char *str_ptr = getStringCopy(&command[9]); // read command parameters
5017 global.autoplay_mode =
5018 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5019 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5020 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5021 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5022 AUTOPLAY_MODE_NONE);
5024 while (*str_ptr != '\0') // continue parsing string
5026 // cut leading whitespace from string, replace it by string terminator
5027 while (*str_ptr == ' ' || *str_ptr == '\t')
5030 if (*str_ptr == '\0') // end of string reached
5033 if (global.autoplay_leveldir == NULL) // read level set string
5035 global.autoplay_leveldir = str_ptr;
5036 global.autoplay_all = TRUE; // default: play all tapes
5038 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5039 global.autoplay_level[i] = FALSE;
5041 else // read level number string
5043 int level_nr = atoi(str_ptr); // get level_nr value
5045 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5046 global.autoplay_level[level_nr] = TRUE;
5048 global.autoplay_all = FALSE;
5051 // advance string pointer to the next whitespace (or end of string)
5052 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5056 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5057 program.headless = TRUE;
5059 else if (strPrefix(command, "convert "))
5061 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5062 char *str_ptr = strchr(str_copy, ' ');
5064 global.convert_leveldir = str_copy;
5065 global.convert_level_nr = -1;
5067 if (str_ptr != NULL) // level number follows
5069 *str_ptr++ = '\0'; // terminate leveldir string
5070 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5073 program.headless = TRUE;
5075 else if (strPrefix(command, "create images "))
5077 global.create_images_dir = getStringCopy(&command[14]);
5079 if (access(global.create_images_dir, W_OK) != 0)
5080 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5081 global.create_images_dir);
5083 else if (strPrefix(command, "create CE image "))
5085 CreateCustomElementImages(&command[16]);
5091 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5094 // disable networking if any valid command was recognized
5095 options.network = setup.network_mode = FALSE;
5098 static void InitSetup(void)
5100 LoadSetup(); // global setup info
5101 LoadSetup_AutoSetup(); // global auto setup info
5103 // set some options from setup file
5105 if (setup.options.verbose)
5106 options.verbose = TRUE;
5108 if (setup.debug.show_frames_per_second)
5109 global.show_frames_per_second = TRUE;
5112 static void InitGameInfo(void)
5114 game.restart_level = FALSE;
5115 game.restart_game_message = NULL;
5116 game.request_active = FALSE;
5119 static void InitPlayerInfo(void)
5123 // choose default local player
5124 local_player = &stored_player[0];
5126 for (i = 0; i < MAX_PLAYERS; i++)
5128 stored_player[i].connected_locally = FALSE;
5129 stored_player[i].connected_network = FALSE;
5132 local_player->connected_locally = TRUE;
5135 static void InitArtworkInfo(void)
5140 static char *get_string_in_brackets(char *string)
5142 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5144 sprintf(string_in_brackets, "[%s]", string);
5146 return string_in_brackets;
5149 static char *get_level_id_suffix(int id_nr)
5151 char *id_suffix = checked_malloc(1 + 3 + 1);
5153 if (id_nr < 0 || id_nr > 999)
5156 sprintf(id_suffix, ".%03d", id_nr);
5161 static void InitArtworkConfig(void)
5163 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5165 NUM_GLOBAL_ANIM_TOKENS + 1];
5166 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5167 NUM_GLOBAL_ANIM_TOKENS + 1];
5168 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5169 NUM_GLOBAL_ANIM_TOKENS + 1];
5170 static char *action_id_suffix[NUM_ACTIONS + 1];
5171 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5172 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5173 static char *level_id_suffix[MAX_LEVELS + 1];
5174 static char *dummy[1] = { NULL };
5175 static char *ignore_generic_tokens[] =
5180 "program_copyright",
5185 static char **ignore_image_tokens;
5186 static char **ignore_sound_tokens;
5187 static char **ignore_music_tokens;
5188 int num_ignore_generic_tokens;
5189 int num_ignore_image_tokens;
5190 int num_ignore_sound_tokens;
5191 int num_ignore_music_tokens;
5194 // dynamically determine list of generic tokens to be ignored
5195 num_ignore_generic_tokens = 0;
5196 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5197 num_ignore_generic_tokens++;
5199 // dynamically determine list of image tokens to be ignored
5200 num_ignore_image_tokens = num_ignore_generic_tokens;
5201 for (i = 0; image_config_vars[i].token != NULL; i++)
5202 num_ignore_image_tokens++;
5203 ignore_image_tokens =
5204 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5205 for (i = 0; i < num_ignore_generic_tokens; i++)
5206 ignore_image_tokens[i] = ignore_generic_tokens[i];
5207 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5208 ignore_image_tokens[num_ignore_generic_tokens + i] =
5209 image_config_vars[i].token;
5210 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5212 // dynamically determine list of sound tokens to be ignored
5213 num_ignore_sound_tokens = num_ignore_generic_tokens;
5214 ignore_sound_tokens =
5215 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5216 for (i = 0; i < num_ignore_generic_tokens; i++)
5217 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5218 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5220 // dynamically determine list of music tokens to be ignored
5221 num_ignore_music_tokens = num_ignore_generic_tokens;
5222 ignore_music_tokens =
5223 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5224 for (i = 0; i < num_ignore_generic_tokens; i++)
5225 ignore_music_tokens[i] = ignore_generic_tokens[i];
5226 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5228 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5229 image_id_prefix[i] = element_info[i].token_name;
5230 for (i = 0; i < NUM_FONTS; i++)
5231 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5232 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5233 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5234 global_anim_info[i].token_name;
5235 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5237 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5238 sound_id_prefix[i] = element_info[i].token_name;
5239 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5240 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5241 get_string_in_brackets(element_info[i].class_name);
5242 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5243 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5244 global_anim_info[i].token_name;
5245 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5247 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5248 music_id_prefix[i] = music_prefix_info[i].prefix;
5249 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5250 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5251 global_anim_info[i].token_name;
5252 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5254 for (i = 0; i < NUM_ACTIONS; i++)
5255 action_id_suffix[i] = element_action_info[i].suffix;
5256 action_id_suffix[NUM_ACTIONS] = NULL;
5258 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5259 direction_id_suffix[i] = element_direction_info[i].suffix;
5260 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5262 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5263 special_id_suffix[i] = special_suffix_info[i].suffix;
5264 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5266 for (i = 0; i < MAX_LEVELS; i++)
5267 level_id_suffix[i] = get_level_id_suffix(i);
5268 level_id_suffix[MAX_LEVELS] = NULL;
5270 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5271 image_id_prefix, action_id_suffix, direction_id_suffix,
5272 special_id_suffix, ignore_image_tokens);
5273 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5274 sound_id_prefix, action_id_suffix, dummy,
5275 special_id_suffix, ignore_sound_tokens);
5276 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5277 music_id_prefix, action_id_suffix, special_id_suffix,
5278 level_id_suffix, ignore_music_tokens);
5281 static void InitMixer(void)
5288 static void InitVideoOverlay(void)
5290 // if virtual buttons are not loaded from setup file, repeat initializing
5291 // virtual buttons grid with default values now that video is initialized
5292 if (!setup.touch.grid_initialized)
5295 InitTileCursorInfo();
5299 void InitGfxBuffers(void)
5301 static int win_xsize_last = -1;
5302 static int win_ysize_last = -1;
5304 // create additional image buffers for double-buffering and cross-fading
5306 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5308 // used to temporarily store the backbuffer -- only re-create if changed
5309 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5310 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5312 win_xsize_last = WIN_XSIZE;
5313 win_ysize_last = WIN_YSIZE;
5316 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5317 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5318 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5319 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5321 // initialize screen properties
5322 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5323 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5325 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5326 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5327 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5328 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5329 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5330 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5332 // required if door size definitions have changed
5333 InitGraphicCompatibilityInfo_Doors();
5335 InitGfxBuffers_EM();
5336 InitGfxBuffers_SP();
5339 static void InitGfx(void)
5341 struct GraphicInfo *graphic_info_last = graphic_info;
5342 char *filename_font_initial = NULL;
5343 char *filename_anim_initial = NULL;
5344 Bitmap *bitmap_font_initial = NULL;
5347 // determine settings for initial font (for displaying startup messages)
5348 for (i = 0; image_config[i].token != NULL; i++)
5350 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5352 char font_token[128];
5355 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5356 len_font_token = strlen(font_token);
5358 if (strEqual(image_config[i].token, font_token))
5359 filename_font_initial = image_config[i].value;
5360 else if (strlen(image_config[i].token) > len_font_token &&
5361 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5363 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5364 font_initial[j].src_x = atoi(image_config[i].value);
5365 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5366 font_initial[j].src_y = atoi(image_config[i].value);
5367 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5368 font_initial[j].width = atoi(image_config[i].value);
5369 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5370 font_initial[j].height = atoi(image_config[i].value);
5375 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5377 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5378 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5381 if (filename_font_initial == NULL) // should not happen
5382 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5385 InitGfxCustomArtworkInfo();
5386 InitGfxOtherSettings();
5388 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5390 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5391 font_initial[j].bitmap = bitmap_font_initial;
5393 InitFontGraphicInfo();
5397 DrawInitText("Loading graphics", 120, FC_GREEN);
5399 // initialize settings for busy animation with default values
5400 int parameter[NUM_GFX_ARGS];
5401 for (i = 0; i < NUM_GFX_ARGS; i++)
5402 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5403 image_config_suffix[i].token,
5404 image_config_suffix[i].type);
5406 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5407 int len_anim_token = strlen(anim_token);
5409 // read settings for busy animation from default custom artwork config
5410 char *gfx_config_filename = getPath3(options.graphics_directory,
5412 GRAPHICSINFO_FILENAME);
5414 if (fileExists(gfx_config_filename))
5416 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5418 if (setup_file_hash)
5420 char *filename = getHashEntry(setup_file_hash, anim_token);
5424 filename_anim_initial = getStringCopy(filename);
5426 for (j = 0; image_config_suffix[j].token != NULL; j++)
5428 int type = image_config_suffix[j].type;
5429 char *suffix = image_config_suffix[j].token;
5430 char *token = getStringCat2(anim_token, suffix);
5431 char *value = getHashEntry(setup_file_hash, token);
5433 checked_free(token);
5436 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5440 freeSetupFileHash(setup_file_hash);
5444 if (filename_anim_initial == NULL)
5446 // read settings for busy animation from static default artwork config
5447 for (i = 0; image_config[i].token != NULL; i++)
5449 if (strEqual(image_config[i].token, anim_token))
5450 filename_anim_initial = getStringCopy(image_config[i].value);
5451 else if (strlen(image_config[i].token) > len_anim_token &&
5452 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5454 for (j = 0; image_config_suffix[j].token != NULL; j++)
5456 if (strEqual(&image_config[i].token[len_anim_token],
5457 image_config_suffix[j].token))
5459 get_graphic_parameter_value(image_config[i].value,
5460 image_config_suffix[j].token,
5461 image_config_suffix[j].type);
5467 if (filename_anim_initial == NULL) // should not happen
5468 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5470 anim_initial.bitmaps =
5471 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5473 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5474 LoadCustomImage(filename_anim_initial);
5476 checked_free(filename_anim_initial);
5478 graphic_info = &anim_initial; // graphic == 0 => anim_initial
5480 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5482 graphic_info = graphic_info_last;
5484 init.busy.width = anim_initial.width;
5485 init.busy.height = anim_initial.height;
5487 InitMenuDesignSettings_Static();
5489 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5490 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5491 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5492 InitGfxDrawTileCursorFunction(DrawTileCursor);
5494 gfx.fade_border_source_status = global.border_status;
5495 gfx.fade_border_target_status = global.border_status;
5496 gfx.masked_border_bitmap_ptr = backbuffer;
5498 // use copy of busy animation to prevent change while reloading artwork
5502 static void InitGfxBackground(void)
5504 fieldbuffer = bitmap_db_field;
5505 SetDrawtoField(DRAW_TO_BACKBUFFER);
5507 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5509 redraw_mask = REDRAW_ALL;
5512 static void InitLevelInfo(void)
5514 LoadLevelInfo(); // global level info
5515 LoadLevelSetup_LastSeries(); // last played series info
5516 LoadLevelSetup_SeriesInfo(); // last played level info
5518 if (global.autoplay_leveldir &&
5519 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5521 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5522 global.autoplay_leveldir);
5523 if (leveldir_current == NULL)
5524 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5527 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5530 static void InitLevelArtworkInfo(void)
5532 LoadLevelArtworkInfo();
5535 static void InitImages(void)
5537 print_timestamp_init("InitImages");
5540 printf("::: leveldir_current->identifier == '%s'\n",
5541 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5542 printf("::: leveldir_current->graphics_path == '%s'\n",
5543 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5544 printf("::: leveldir_current->graphics_set == '%s'\n",
5545 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5546 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5547 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5550 setLevelArtworkDir(artwork.gfx_first);
5553 printf("::: leveldir_current->identifier == '%s'\n",
5554 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5555 printf("::: leveldir_current->graphics_path == '%s'\n",
5556 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5557 printf("::: leveldir_current->graphics_set == '%s'\n",
5558 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5559 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5560 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5564 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5565 leveldir_current->identifier,
5566 artwork.gfx_current_identifier,
5567 artwork.gfx_current->identifier,
5568 leveldir_current->graphics_set,
5569 leveldir_current->graphics_path);
5572 UPDATE_BUSY_STATE();
5574 ReloadCustomImages();
5575 print_timestamp_time("ReloadCustomImages");
5577 UPDATE_BUSY_STATE();
5579 LoadCustomElementDescriptions();
5580 print_timestamp_time("LoadCustomElementDescriptions");
5582 UPDATE_BUSY_STATE();
5584 LoadMenuDesignSettings();
5585 print_timestamp_time("LoadMenuDesignSettings");
5587 UPDATE_BUSY_STATE();
5589 ReinitializeGraphics();
5590 print_timestamp_time("ReinitializeGraphics");
5592 LoadMenuDesignSettings_AfterGraphics();
5593 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5595 UPDATE_BUSY_STATE();
5597 print_timestamp_done("InitImages");
5600 static void InitSound(char *identifier)
5602 print_timestamp_init("InitSound");
5604 if (identifier == NULL)
5605 identifier = artwork.snd_current->identifier;
5607 // set artwork path to send it to the sound server process
5608 setLevelArtworkDir(artwork.snd_first);
5610 InitReloadCustomSounds(identifier);
5611 print_timestamp_time("InitReloadCustomSounds");
5613 ReinitializeSounds();
5614 print_timestamp_time("ReinitializeSounds");
5616 print_timestamp_done("InitSound");
5619 static void InitMusic(char *identifier)
5621 print_timestamp_init("InitMusic");
5623 if (identifier == NULL)
5624 identifier = artwork.mus_current->identifier;
5626 // set artwork path to send it to the sound server process
5627 setLevelArtworkDir(artwork.mus_first);
5629 InitReloadCustomMusic(identifier);
5630 print_timestamp_time("InitReloadCustomMusic");
5632 ReinitializeMusic();
5633 print_timestamp_time("ReinitializeMusic");
5635 print_timestamp_done("InitMusic");
5638 static void InitArtworkDone(void)
5640 if (program.headless)
5643 InitGlobalAnimations();
5646 static void InitNetworkSettings(void)
5648 boolean network_enabled = (options.network || setup.network_mode);
5649 char *network_server = (options.server_host != NULL ? options.server_host :
5650 setup.network_server_hostname);
5652 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5653 network_server = NULL;
5655 InitNetworkInfo(network_enabled,
5659 options.server_port);
5662 void InitNetworkServer(void)
5664 if (!network.enabled || network.connected)
5667 LimitScreenUpdates(FALSE);
5669 if (game_status == GAME_MODE_LOADING)
5672 if (!ConnectToServer(network.server_host, network.server_port))
5674 network.enabled = FALSE;
5676 setup.network_mode = FALSE;
5680 SendToServer_ProtocolVersion();
5681 SendToServer_PlayerName(setup.player_name);
5682 SendToServer_NrWanted(setup.network_player_nr + 1);
5684 network.connected = TRUE;
5687 // short time to recognize result of network initialization
5688 if (game_status == GAME_MODE_LOADING)
5689 Delay_WithScreenUpdates(1000);
5692 static boolean CheckArtworkConfigForCustomElements(char *filename)
5694 SetupFileHash *setup_file_hash;
5695 boolean redefined_ce_found = FALSE;
5697 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5699 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5701 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5703 char *token = HASH_ITERATION_TOKEN(itr);
5705 if (strPrefix(token, "custom_"))
5707 redefined_ce_found = TRUE;
5712 END_HASH_ITERATION(setup_file_hash, itr)
5714 freeSetupFileHash(setup_file_hash);
5717 return redefined_ce_found;
5720 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5722 char *filename_base, *filename_local;
5723 boolean redefined_ce_found = FALSE;
5725 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5728 printf("::: leveldir_current->identifier == '%s'\n",
5729 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5730 printf("::: leveldir_current->graphics_path == '%s'\n",
5731 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5732 printf("::: leveldir_current->graphics_set == '%s'\n",
5733 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5734 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5735 leveldir_current == NULL ? "[NULL]" :
5736 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5739 // first look for special artwork configured in level series config
5740 filename_base = getCustomArtworkLevelConfigFilename(type);
5743 printf("::: filename_base == '%s'\n", filename_base);
5746 if (fileExists(filename_base))
5747 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5749 filename_local = getCustomArtworkConfigFilename(type);
5752 printf("::: filename_local == '%s'\n", filename_local);
5755 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5756 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5759 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5762 return redefined_ce_found;
5765 static void InitOverrideArtwork(void)
5767 boolean redefined_ce_found = FALSE;
5769 // to check if this level set redefines any CEs, do not use overriding
5770 gfx.override_level_graphics = FALSE;
5771 gfx.override_level_sounds = FALSE;
5772 gfx.override_level_music = FALSE;
5774 // now check if this level set has definitions for custom elements
5775 if (setup.override_level_graphics == AUTO ||
5776 setup.override_level_sounds == AUTO ||
5777 setup.override_level_music == AUTO)
5778 redefined_ce_found =
5779 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5780 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5781 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5784 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5787 if (redefined_ce_found)
5789 // this level set has CE definitions: change "AUTO" to "FALSE"
5790 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5791 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5792 gfx.override_level_music = (setup.override_level_music == TRUE);
5796 // this level set has no CE definitions: change "AUTO" to "TRUE"
5797 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5798 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5799 gfx.override_level_music = (setup.override_level_music != FALSE);
5803 printf("::: => %d, %d, %d\n",
5804 gfx.override_level_graphics,
5805 gfx.override_level_sounds,
5806 gfx.override_level_music);
5810 static char *getNewArtworkIdentifier(int type)
5812 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5813 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5814 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5815 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5816 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5817 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5818 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5819 char *leveldir_identifier = leveldir_current->identifier;
5820 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
5821 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5822 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5823 char *artwork_current_identifier;
5824 char *artwork_new_identifier = NULL; // default: nothing has changed
5826 // leveldir_current may be invalid (level group, parent link)
5827 if (!validLevelSeries(leveldir_current))
5830 /* 1st step: determine artwork set to be activated in descending order:
5831 --------------------------------------------------------------------
5832 1. setup artwork (when configured to override everything else)
5833 2. artwork set configured in "levelinfo.conf" of current level set
5834 (artwork in level directory will have priority when loading later)
5835 3. artwork in level directory (stored in artwork sub-directory)
5836 4. setup artwork (currently configured in setup menu) */
5838 if (setup_override_artwork)
5839 artwork_current_identifier = setup_artwork_set;
5840 else if (leveldir_artwork_set != NULL)
5841 artwork_current_identifier = leveldir_artwork_set;
5842 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5843 artwork_current_identifier = leveldir_identifier;
5845 artwork_current_identifier = setup_artwork_set;
5848 /* 2nd step: check if it is really needed to reload artwork set
5849 ------------------------------------------------------------ */
5851 // ---------- reload if level set and also artwork set has changed ----------
5852 if (leveldir_current_identifier[type] != leveldir_identifier &&
5853 (last_has_level_artwork_set[type] || has_level_artwork_set))
5854 artwork_new_identifier = artwork_current_identifier;
5856 leveldir_current_identifier[type] = leveldir_identifier;
5857 last_has_level_artwork_set[type] = has_level_artwork_set;
5859 // ---------- reload if "override artwork" setting has changed --------------
5860 if (last_override_level_artwork[type] != setup_override_artwork)
5861 artwork_new_identifier = artwork_current_identifier;
5863 last_override_level_artwork[type] = setup_override_artwork;
5865 // ---------- reload if current artwork identifier has changed --------------
5866 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5867 artwork_current_identifier))
5868 artwork_new_identifier = artwork_current_identifier;
5870 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5872 // ---------- do not reload directly after starting -------------------------
5873 if (!initialized[type])
5874 artwork_new_identifier = NULL;
5876 initialized[type] = TRUE;
5878 return artwork_new_identifier;
5881 void ReloadCustomArtwork(int force_reload)
5883 int last_game_status = game_status; // save current game status
5884 char *gfx_new_identifier;
5885 char *snd_new_identifier;
5886 char *mus_new_identifier;
5887 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5888 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5889 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5890 boolean reload_needed;
5892 InitOverrideArtwork();
5894 force_reload_gfx |= AdjustGraphicsForEMC();
5896 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5897 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5898 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5900 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5901 snd_new_identifier != NULL || force_reload_snd ||
5902 mus_new_identifier != NULL || force_reload_mus);
5907 print_timestamp_init("ReloadCustomArtwork");
5909 SetGameStatus(GAME_MODE_LOADING);
5911 FadeOut(REDRAW_ALL);
5913 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5914 print_timestamp_time("ClearRectangle");
5918 if (gfx_new_identifier != NULL || force_reload_gfx)
5921 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5922 artwork.gfx_current_identifier,
5924 artwork.gfx_current->identifier,
5925 leveldir_current->graphics_set);
5929 print_timestamp_time("InitImages");
5932 if (snd_new_identifier != NULL || force_reload_snd)
5934 InitSound(snd_new_identifier);
5935 print_timestamp_time("InitSound");
5938 if (mus_new_identifier != NULL || force_reload_mus)
5940 InitMusic(mus_new_identifier);
5941 print_timestamp_time("InitMusic");
5946 SetGameStatus(last_game_status); // restore current game status
5948 init_last = init; // switch to new busy animation
5950 FadeOut(REDRAW_ALL);
5952 RedrawGlobalBorder();
5954 // force redraw of (open or closed) door graphics
5955 SetDoorState(DOOR_OPEN_ALL);
5956 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5958 FadeSetEnterScreen();
5959 FadeSkipNextFadeOut();
5961 print_timestamp_done("ReloadCustomArtwork");
5963 LimitScreenUpdates(FALSE);
5966 void KeyboardAutoRepeatOffUnlessAutoplay(void)
5968 if (global.autoplay_leveldir == NULL)
5969 KeyboardAutoRepeatOff();
5972 void DisplayExitMessage(char *format, va_list ap)
5974 // also check for initialized video (headless flag may be temporarily unset)
5975 if (program.headless || !video.initialized)
5978 // check if draw buffer and fonts for exit message are already available
5979 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5982 int font_1 = FC_RED;
5983 int font_2 = FC_YELLOW;
5984 int font_3 = FC_BLUE;
5985 int font_width = getFontWidth(font_2);
5986 int font_height = getFontHeight(font_2);
5989 int sxsize = WIN_XSIZE - 2 * sx;
5990 int sysize = WIN_YSIZE - 2 * sy;
5991 int line_length = sxsize / font_width;
5992 int max_lines = sysize / font_height;
5993 int num_lines_printed;
5997 gfx.sxsize = sxsize;
5998 gfx.sysize = sysize;
6002 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6004 DrawTextSCentered(sy, font_1, "Fatal error:");
6005 sy += 3 * font_height;;
6008 DrawTextBufferVA(sx, sy, format, ap, font_2,
6009 line_length, line_length, max_lines,
6010 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6011 sy += (num_lines_printed + 3) * font_height;
6013 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6014 sy += 3 * font_height;
6017 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6018 line_length, line_length, max_lines,
6019 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6021 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6023 redraw_mask = REDRAW_ALL;
6025 // force drawing exit message even if screen updates are currently limited
6026 LimitScreenUpdates(FALSE);
6030 // deactivate toons on error message screen
6031 setup.toons = FALSE;
6033 WaitForEventToContinue();
6037 // ============================================================================
6039 // ============================================================================
6043 print_timestamp_init("OpenAll");
6045 SetGameStatus(GAME_MODE_LOADING);
6049 InitGlobal(); // initialize some global variables
6051 print_timestamp_time("[init global stuff]");
6055 print_timestamp_time("[init setup/config stuff (1)]");
6059 if (options.execute_command)
6060 Execute_Command(options.execute_command);
6062 InitNetworkSettings();
6064 if (network.serveronly)
6066 #if defined(PLATFORM_UNIX)
6067 NetworkServer(network.server_port, TRUE);
6069 Error(ERR_WARN, "networking only supported in Unix version");
6072 exit(0); // never reached, server loops forever
6076 print_timestamp_time("[init setup/config stuff (2)]");
6078 print_timestamp_time("[init setup/config stuff (3)]");
6079 InitArtworkInfo(); // needed before loading gfx, sound & music
6080 print_timestamp_time("[init setup/config stuff (4)]");
6081 InitArtworkConfig(); // needed before forking sound child process
6082 print_timestamp_time("[init setup/config stuff (5)]");
6084 print_timestamp_time("[init setup/config stuff (6)]");
6086 InitRND(NEW_RANDOMIZE);
6087 InitSimpleRandom(NEW_RANDOMIZE);
6091 print_timestamp_time("[init setup/config stuff]");
6093 InitVideoDefaults();
6095 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6098 print_timestamp_time("[init video stuff]");
6100 InitElementPropertiesStatic();
6101 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6102 InitElementPropertiesGfxElement();
6104 print_timestamp_time("[init element properties stuff]");
6108 print_timestamp_time("InitGfx");
6111 print_timestamp_time("InitLevelInfo");
6113 InitLevelArtworkInfo();
6114 print_timestamp_time("InitLevelArtworkInfo");
6116 InitOverrideArtwork(); // needs to know current level directory
6117 print_timestamp_time("InitOverrideArtwork");
6119 InitImages(); // needs to know current level directory
6120 print_timestamp_time("InitImages");
6122 InitSound(NULL); // needs to know current level directory
6123 print_timestamp_time("InitSound");
6125 InitMusic(NULL); // needs to know current level directory
6126 print_timestamp_time("InitMusic");
6130 InitGfxBackground();
6136 if (global.autoplay_leveldir)
6141 else if (global.convert_leveldir)
6146 else if (global.create_images_dir)
6148 CreateLevelSketchImages();
6152 InitNetworkServer();
6154 SetGameStatus(GAME_MODE_MAIN);
6156 FadeSetEnterScreen();
6157 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6158 FadeSkipNextFadeOut();
6160 print_timestamp_time("[post-artwork]");
6162 print_timestamp_done("OpenAll");
6167 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6169 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6170 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6171 #if defined(PLATFORM_ANDROID)
6172 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6173 SDL_AndroidGetInternalStoragePath());
6174 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6175 SDL_AndroidGetExternalStoragePath());
6176 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6177 (SDL_AndroidGetExternalStorageState() &
6178 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6179 SDL_AndroidGetExternalStorageState() &
6180 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6185 void CloseAllAndExit(int exit_value)
6190 CloseAudio(); // called after freeing sounds (needed for SDL)
6198 // set a flag to tell the network server thread to quit and wait for it
6199 // using SDL_WaitThread()
6201 // Code used with SDL 1.2:
6202 // if (network_server) // terminate network server
6203 // SDL_KillThread(server_thread);
6205 CloseVideoDisplay();
6206 ClosePlatformDependentStuff();
6208 if (exit_value != 0 && !options.execute_command)
6210 // fall back to default level set (current set may have caused an error)
6211 SaveLevelSetup_LastSeries_Deactivate();
6213 // tell user where to find error log file which may contain more details
6214 // (error notification now directly displayed on screen inside R'n'D
6215 // NotifyUserAboutErrorFile(); // currently only works for Windows