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)
278 static int texture_graphics[] =
284 FreeAllImageTextures();
286 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
287 CreateImageTextures(i);
289 for (i = 0; i < MAX_NUM_TOONS; i++)
290 CreateImageTextures(IMG_TOON_1 + i);
292 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
294 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
296 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
298 int graphic = global_anim_info[i].graphic[j][k];
300 if (graphic == IMG_UNDEFINED)
303 CreateImageTextures(graphic);
308 for (i = 0; texture_graphics[i] > -1; i++)
309 CreateImageTextures(texture_graphics[i]);
313 // !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!!
314 void SetBitmaps_EM(Bitmap **em_bitmap)
316 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
317 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
322 // !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!!
323 void SetBitmaps_SP(Bitmap **sp_bitmap)
325 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
329 static int getFontBitmapID(int font_nr)
333 // (special case: do not use special font for GAME_MODE_LOADING)
334 if (game_status >= GAME_MODE_TITLE_INITIAL &&
335 game_status <= GAME_MODE_PSEUDO_PREVIEW)
336 special = game_status;
337 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
338 special = GFX_SPECIAL_ARG_MAIN;
341 return font_info[font_nr].special_bitmap_id[special];
346 static int getFontFromToken(char *token)
348 char *value = getHashEntry(font_token_hash, token);
353 // if font not found, use reliable default value
354 return FONT_INITIAL_1;
357 static void InitFontGraphicInfo(void)
359 static struct FontBitmapInfo *font_bitmap_info = NULL;
360 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
361 int num_property_mappings = getImageListPropertyMappingSize();
362 int num_font_bitmaps = NUM_FONTS;
365 if (graphic_info == NULL) // still at startup phase
367 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
368 getFontBitmapID, getFontFromToken);
373 // ---------- initialize font graphic definitions ----------
375 // always start with reliable default values (normal font graphics)
376 for (i = 0; i < NUM_FONTS; i++)
377 font_info[i].graphic = IMG_FONT_INITIAL_1;
379 // initialize normal font/graphic mapping from static configuration
380 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
382 int font_nr = font_to_graphic[i].font_nr;
383 int special = font_to_graphic[i].special;
384 int graphic = font_to_graphic[i].graphic;
389 font_info[font_nr].graphic = graphic;
392 // always start with reliable default values (special font graphics)
393 for (i = 0; i < NUM_FONTS; i++)
395 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
397 font_info[i].special_graphic[j] = font_info[i].graphic;
398 font_info[i].special_bitmap_id[j] = i;
402 // initialize special font/graphic mapping from static configuration
403 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
405 int font_nr = font_to_graphic[i].font_nr;
406 int special = font_to_graphic[i].special;
407 int graphic = font_to_graphic[i].graphic;
408 int base_graphic = font2baseimg(font_nr);
410 if (IS_SPECIAL_GFX_ARG(special))
412 boolean base_redefined =
413 getImageListEntryFromImageID(base_graphic)->redefined;
414 boolean special_redefined =
415 getImageListEntryFromImageID(graphic)->redefined;
416 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
418 /* if the base font ("font.title_1", for example) has been redefined,
419 but not the special font ("font.title_1.LEVELS", for example), do not
420 use an existing (in this case considered obsolete) special font
421 anymore, but use the automatically determined default font */
422 /* special case: cloned special fonts must be explicitly redefined,
423 but are not automatically redefined by redefining base font */
424 if (base_redefined && !special_redefined && !special_cloned)
427 font_info[font_nr].special_graphic[special] = graphic;
428 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
433 // initialize special font/graphic mapping from dynamic configuration
434 for (i = 0; i < num_property_mappings; i++)
436 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
437 int special = property_mapping[i].ext3_index;
438 int graphic = property_mapping[i].artwork_index;
440 if (font_nr < 0 || font_nr >= NUM_FONTS)
443 if (IS_SPECIAL_GFX_ARG(special))
445 font_info[font_nr].special_graphic[special] = graphic;
446 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
451 /* correct special font/graphic mapping for cloned fonts for downwards
452 compatibility of PREVIEW fonts -- this is only needed for implicit
453 redefinition of special font by redefined base font, and only if other
454 fonts are cloned from this special font (like in the "Zelda" level set) */
455 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
457 int font_nr = font_to_graphic[i].font_nr;
458 int special = font_to_graphic[i].special;
459 int graphic = font_to_graphic[i].graphic;
461 if (IS_SPECIAL_GFX_ARG(special))
463 boolean special_redefined =
464 getImageListEntryFromImageID(graphic)->redefined;
465 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
467 if (special_cloned && !special_redefined)
471 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
473 int font_nr2 = font_to_graphic[j].font_nr;
474 int special2 = font_to_graphic[j].special;
475 int graphic2 = font_to_graphic[j].graphic;
477 if (IS_SPECIAL_GFX_ARG(special2) &&
478 graphic2 == graphic_info[graphic].clone_from)
480 font_info[font_nr].special_graphic[special] =
481 font_info[font_nr2].special_graphic[special2];
482 font_info[font_nr].special_bitmap_id[special] =
483 font_info[font_nr2].special_bitmap_id[special2];
490 // reset non-redefined ".active" font graphics if normal font is redefined
491 // (this different treatment is needed because normal and active fonts are
492 // independently defined ("active" is not a property of font definitions!)
493 for (i = 0; i < NUM_FONTS; i++)
495 int font_nr_base = i;
496 int font_nr_active = FONT_ACTIVE(font_nr_base);
498 // check only those fonts with exist as normal and ".active" variant
499 if (font_nr_base != font_nr_active)
501 int base_graphic = font_info[font_nr_base].graphic;
502 int active_graphic = font_info[font_nr_active].graphic;
503 boolean base_redefined =
504 getImageListEntryFromImageID(base_graphic)->redefined;
505 boolean active_redefined =
506 getImageListEntryFromImageID(active_graphic)->redefined;
508 /* if the base font ("font.menu_1", for example) has been redefined,
509 but not the active font ("font.menu_1.active", for example), do not
510 use an existing (in this case considered obsolete) active font
511 anymore, but use the automatically determined default font */
512 if (base_redefined && !active_redefined)
513 font_info[font_nr_active].graphic = base_graphic;
515 // now also check each "special" font (which may be the same as above)
516 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
518 int base_graphic = font_info[font_nr_base].special_graphic[j];
519 int active_graphic = font_info[font_nr_active].special_graphic[j];
520 boolean base_redefined =
521 getImageListEntryFromImageID(base_graphic)->redefined;
522 boolean active_redefined =
523 getImageListEntryFromImageID(active_graphic)->redefined;
525 // same as above, but check special graphic definitions, for example:
526 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
527 if (base_redefined && !active_redefined)
529 font_info[font_nr_active].special_graphic[j] =
530 font_info[font_nr_base].special_graphic[j];
531 font_info[font_nr_active].special_bitmap_id[j] =
532 font_info[font_nr_base].special_bitmap_id[j];
538 // ---------- initialize font bitmap array ----------
540 if (font_bitmap_info != NULL)
541 FreeFontInfo(font_bitmap_info);
544 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
546 // ---------- initialize font bitmap definitions ----------
548 for (i = 0; i < NUM_FONTS; i++)
550 if (i < NUM_INITIAL_FONTS)
552 font_bitmap_info[i] = font_initial[i];
556 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
558 int font_bitmap_id = font_info[i].special_bitmap_id[j];
559 int graphic = font_info[i].special_graphic[j];
561 // set 'graphic_info' for font entries, if uninitialized (guessed)
562 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
564 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
565 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
568 // copy font relevant information from graphics information
569 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
570 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
571 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
572 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
573 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
575 font_bitmap_info[font_bitmap_id].offset_x =
576 graphic_info[graphic].offset_x;
577 font_bitmap_info[font_bitmap_id].offset_y =
578 graphic_info[graphic].offset_y;
580 font_bitmap_info[font_bitmap_id].draw_xoffset =
581 graphic_info[graphic].draw_xoffset;
582 font_bitmap_info[font_bitmap_id].draw_yoffset =
583 graphic_info[graphic].draw_yoffset;
585 font_bitmap_info[font_bitmap_id].num_chars =
586 graphic_info[graphic].anim_frames;
587 font_bitmap_info[font_bitmap_id].num_chars_per_line =
588 graphic_info[graphic].anim_frames_per_line;
592 InitFontInfo(font_bitmap_info, num_font_bitmaps,
593 getFontBitmapID, getFontFromToken);
596 static void InitGlobalAnimGraphicInfo(void)
598 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
599 int num_property_mappings = getImageListPropertyMappingSize();
602 if (graphic_info == NULL) // still at startup phase
605 // always start with reliable default values (no global animations)
606 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
607 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
608 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
609 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
611 // initialize global animation definitions from static configuration
612 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
614 int j = GLOBAL_ANIM_ID_PART_BASE;
615 int k = GFX_SPECIAL_ARG_DEFAULT;
617 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
620 // initialize global animation definitions from dynamic configuration
621 for (i = 0; i < num_property_mappings; i++)
623 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
624 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
625 int special = property_mapping[i].ext3_index;
626 int graphic = property_mapping[i].artwork_index;
628 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
631 // set animation part to base part, if not specified
632 if (!IS_GLOBAL_ANIM_PART(part_nr))
633 part_nr = GLOBAL_ANIM_ID_PART_BASE;
635 // set animation screen to default, if not specified
636 if (!IS_SPECIAL_GFX_ARG(special))
637 special = GFX_SPECIAL_ARG_DEFAULT;
639 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
641 // fix default value for ".draw_masked" (for backward compatibility)
642 struct GraphicInfo *g = &graphic_info[graphic];
643 struct FileInfo *image = getImageListEntryFromImageID(graphic);
644 char **parameter_raw = image->parameter;
645 int p = GFX_ARG_DRAW_MASKED;
646 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
647 image_config_suffix[p].token,
648 image_config_suffix[p].type);
650 // if ".draw_masked" parameter is undefined, use default value "TRUE"
651 if (draw_masked == ARG_UNDEFINED_VALUE)
652 g->draw_masked = TRUE;
656 printf("::: InitGlobalAnimGraphicInfo\n");
658 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
659 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
660 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
661 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
662 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
663 printf("::: - anim %d, part %d, mode %d => %d\n",
664 i, j, k, global_anim_info[i].graphic[j][k]);
668 static void InitGlobalAnimSoundInfo(void)
670 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
671 int num_property_mappings = getSoundListPropertyMappingSize();
674 // always start with reliable default values (no global animation sounds)
675 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
676 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
677 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
678 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
680 // initialize global animation sound definitions from dynamic configuration
681 for (i = 0; i < num_property_mappings; i++)
683 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
684 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
685 int special = property_mapping[i].ext3_index;
686 int sound = property_mapping[i].artwork_index;
688 // sound uses control definition; map it to position of graphic (artwork)
689 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
691 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
694 // set animation part to base part, if not specified
695 if (!IS_GLOBAL_ANIM_PART(part_nr))
696 part_nr = GLOBAL_ANIM_ID_PART_BASE;
698 // set animation screen to default, if not specified
699 if (!IS_SPECIAL_GFX_ARG(special))
700 special = GFX_SPECIAL_ARG_DEFAULT;
702 global_anim_info[anim_nr].sound[part_nr][special] = sound;
706 printf("::: InitGlobalAnimSoundInfo\n");
708 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
709 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
710 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
711 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
712 printf("::: - anim %d, part %d, mode %d => %d\n",
713 i, j, k, global_anim_info[i].sound[j][k]);
717 static void InitGlobalAnimMusicInfo(void)
719 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
720 int num_property_mappings = getMusicListPropertyMappingSize();
723 // always start with reliable default values (no global animation music)
724 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
725 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
726 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
727 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
729 // initialize global animation music definitions from dynamic configuration
730 for (i = 0; i < num_property_mappings; i++)
732 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
733 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
734 int special = property_mapping[i].ext2_index;
735 int music = property_mapping[i].artwork_index;
737 // music uses control definition; map it to position of graphic (artwork)
738 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
740 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
743 // set animation part to base part, if not specified
744 if (!IS_GLOBAL_ANIM_PART(part_nr))
745 part_nr = GLOBAL_ANIM_ID_PART_BASE;
747 // set animation screen to default, if not specified
748 if (!IS_SPECIAL_GFX_ARG(special))
749 special = GFX_SPECIAL_ARG_DEFAULT;
751 global_anim_info[anim_nr].music[part_nr][special] = music;
755 printf("::: InitGlobalAnimMusicInfo\n");
757 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
758 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
759 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
760 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
761 printf("::: - anim %d, part %d, mode %d => %d\n",
762 i, j, k, global_anim_info[i].music[j][k]);
766 static void InitElementGraphicInfo(void)
768 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
769 int num_property_mappings = getImageListPropertyMappingSize();
772 if (graphic_info == NULL) // still at startup phase
775 // set values to -1 to identify later as "uninitialized" values
776 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
778 for (act = 0; act < NUM_ACTIONS; act++)
780 element_info[i].graphic[act] = -1;
781 element_info[i].crumbled[act] = -1;
783 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
785 element_info[i].direction_graphic[act][dir] = -1;
786 element_info[i].direction_crumbled[act][dir] = -1;
793 // initialize normal element/graphic mapping from static configuration
794 for (i = 0; element_to_graphic[i].element > -1; i++)
796 int element = element_to_graphic[i].element;
797 int action = element_to_graphic[i].action;
798 int direction = element_to_graphic[i].direction;
799 boolean crumbled = element_to_graphic[i].crumbled;
800 int graphic = element_to_graphic[i].graphic;
801 int base_graphic = el2baseimg(element);
803 if (graphic_info[graphic].bitmap == NULL)
806 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
809 boolean base_redefined =
810 getImageListEntryFromImageID(base_graphic)->redefined;
811 boolean act_dir_redefined =
812 getImageListEntryFromImageID(graphic)->redefined;
814 /* if the base graphic ("emerald", for example) has been redefined,
815 but not the action graphic ("emerald.falling", for example), do not
816 use an existing (in this case considered obsolete) action graphic
817 anymore, but use the automatically determined default graphic */
818 if (base_redefined && !act_dir_redefined)
823 action = ACTION_DEFAULT;
828 element_info[element].direction_crumbled[action][direction] = graphic;
830 element_info[element].crumbled[action] = graphic;
835 element_info[element].direction_graphic[action][direction] = graphic;
837 element_info[element].graphic[action] = graphic;
841 // initialize normal element/graphic mapping from dynamic configuration
842 for (i = 0; i < num_property_mappings; i++)
844 int element = property_mapping[i].base_index;
845 int action = property_mapping[i].ext1_index;
846 int direction = property_mapping[i].ext2_index;
847 int special = property_mapping[i].ext3_index;
848 int graphic = property_mapping[i].artwork_index;
849 boolean crumbled = FALSE;
851 if (special == GFX_SPECIAL_ARG_CRUMBLED)
857 if (graphic_info[graphic].bitmap == NULL)
860 if (element >= MAX_NUM_ELEMENTS || special != -1)
864 action = ACTION_DEFAULT;
869 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
870 element_info[element].direction_crumbled[action][dir] = -1;
873 element_info[element].direction_crumbled[action][direction] = graphic;
875 element_info[element].crumbled[action] = graphic;
880 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
881 element_info[element].direction_graphic[action][dir] = -1;
884 element_info[element].direction_graphic[action][direction] = graphic;
886 element_info[element].graphic[action] = graphic;
890 // now copy all graphics that are defined to be cloned from other graphics
891 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
893 int graphic = element_info[i].graphic[ACTION_DEFAULT];
894 int crumbled_like, diggable_like;
899 crumbled_like = graphic_info[graphic].crumbled_like;
900 diggable_like = graphic_info[graphic].diggable_like;
902 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
904 for (act = 0; act < NUM_ACTIONS; act++)
905 element_info[i].crumbled[act] =
906 element_info[crumbled_like].crumbled[act];
907 for (act = 0; act < NUM_ACTIONS; act++)
908 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
909 element_info[i].direction_crumbled[act][dir] =
910 element_info[crumbled_like].direction_crumbled[act][dir];
913 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
915 element_info[i].graphic[ACTION_DIGGING] =
916 element_info[diggable_like].graphic[ACTION_DIGGING];
917 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
918 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
919 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
923 // set hardcoded definitions for some runtime elements without graphic
924 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
926 // set hardcoded definitions for some internal elements without graphic
927 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
929 if (IS_EDITOR_CASCADE_INACTIVE(i))
930 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
931 else if (IS_EDITOR_CASCADE_ACTIVE(i))
932 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
935 // now set all undefined/invalid graphics to -1 to set to default after it
936 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
938 for (act = 0; act < NUM_ACTIONS; act++)
942 graphic = element_info[i].graphic[act];
943 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
944 element_info[i].graphic[act] = -1;
946 graphic = element_info[i].crumbled[act];
947 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
948 element_info[i].crumbled[act] = -1;
950 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
952 graphic = element_info[i].direction_graphic[act][dir];
953 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
954 element_info[i].direction_graphic[act][dir] = -1;
956 graphic = element_info[i].direction_crumbled[act][dir];
957 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
958 element_info[i].direction_crumbled[act][dir] = -1;
965 // adjust graphics with 2nd tile for movement according to direction
966 // (do this before correcting '-1' values to minimize calculations)
967 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
969 for (act = 0; act < NUM_ACTIONS; act++)
971 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
973 int graphic = element_info[i].direction_graphic[act][dir];
974 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
976 if (act == ACTION_FALLING) // special case
977 graphic = element_info[i].graphic[act];
980 graphic_info[graphic].double_movement &&
981 graphic_info[graphic].swap_double_tiles != 0)
983 struct GraphicInfo *g = &graphic_info[graphic];
984 int src_x_front = g->src_x;
985 int src_y_front = g->src_y;
986 int src_x_back = g->src_x + g->offset2_x;
987 int src_y_back = g->src_y + g->offset2_y;
988 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
990 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
991 src_y_front < src_y_back);
992 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
993 boolean swap_movement_tiles_autodetected =
994 (!frames_are_ordered_diagonally &&
995 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
996 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
997 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
998 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
1000 // swap frontside and backside graphic tile coordinates, if needed
1001 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
1003 // get current (wrong) backside tile coordinates
1004 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1006 // set frontside tile coordinates to backside tile coordinates
1007 g->src_x = src_x_back;
1008 g->src_y = src_y_back;
1010 // invert tile offset to point to new backside tile coordinates
1014 // do not swap front and backside tiles again after correction
1015 g->swap_double_tiles = 0;
1022 UPDATE_BUSY_STATE();
1024 // now set all '-1' values to element specific default values
1025 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1027 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1028 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1029 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1030 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1032 if (default_graphic == -1)
1033 default_graphic = IMG_UNKNOWN;
1035 if (default_crumbled == -1)
1036 default_crumbled = default_graphic;
1038 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1040 default_direction_graphic[dir] =
1041 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1042 default_direction_crumbled[dir] =
1043 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1045 if (default_direction_graphic[dir] == -1)
1046 default_direction_graphic[dir] = default_graphic;
1048 if (default_direction_crumbled[dir] == -1)
1049 default_direction_crumbled[dir] = default_direction_graphic[dir];
1052 for (act = 0; act < NUM_ACTIONS; act++)
1054 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1055 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1056 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1057 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1058 act == ACTION_TURNING_FROM_RIGHT ||
1059 act == ACTION_TURNING_FROM_UP ||
1060 act == ACTION_TURNING_FROM_DOWN);
1062 // generic default action graphic (defined by "[default]" directive)
1063 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1064 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1065 int default_remove_graphic = IMG_EMPTY;
1067 if (act_remove && default_action_graphic != -1)
1068 default_remove_graphic = default_action_graphic;
1070 // look for special default action graphic (classic game specific)
1071 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1072 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1073 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1074 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1075 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1076 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1077 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1078 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1080 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1081 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1082 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1083 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1084 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1085 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1086 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1087 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1089 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1090 // !!! make this better !!!
1091 if (i == EL_EMPTY_SPACE)
1093 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1094 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1097 if (default_action_graphic == -1)
1098 default_action_graphic = default_graphic;
1100 if (default_action_crumbled == -1)
1101 default_action_crumbled = default_action_graphic;
1103 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1105 // use action graphic as the default direction graphic, if undefined
1106 int default_action_direction_graphic = element_info[i].graphic[act];
1107 int default_action_direction_crumbled = element_info[i].crumbled[act];
1109 // no graphic for current action -- use default direction graphic
1110 if (default_action_direction_graphic == -1)
1111 default_action_direction_graphic =
1112 (act_remove ? default_remove_graphic :
1114 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1115 default_action_graphic != default_graphic ?
1116 default_action_graphic :
1117 default_direction_graphic[dir]);
1119 if (element_info[i].direction_graphic[act][dir] == -1)
1120 element_info[i].direction_graphic[act][dir] =
1121 default_action_direction_graphic;
1123 if (default_action_direction_crumbled == -1)
1124 default_action_direction_crumbled =
1125 element_info[i].direction_graphic[act][dir];
1127 if (element_info[i].direction_crumbled[act][dir] == -1)
1128 element_info[i].direction_crumbled[act][dir] =
1129 default_action_direction_crumbled;
1132 // no graphic for this specific action -- use default action graphic
1133 if (element_info[i].graphic[act] == -1)
1134 element_info[i].graphic[act] =
1135 (act_remove ? default_remove_graphic :
1136 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1137 default_action_graphic);
1139 if (element_info[i].crumbled[act] == -1)
1140 element_info[i].crumbled[act] = element_info[i].graphic[act];
1144 UPDATE_BUSY_STATE();
1147 static void InitElementSpecialGraphicInfo(void)
1149 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1150 int num_property_mappings = getImageListPropertyMappingSize();
1153 // always start with reliable default values
1154 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1155 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1156 element_info[i].special_graphic[j] =
1157 element_info[i].graphic[ACTION_DEFAULT];
1159 // initialize special element/graphic mapping from static configuration
1160 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1162 int element = element_to_special_graphic[i].element;
1163 int special = element_to_special_graphic[i].special;
1164 int graphic = element_to_special_graphic[i].graphic;
1165 int base_graphic = el2baseimg(element);
1166 boolean base_redefined =
1167 getImageListEntryFromImageID(base_graphic)->redefined;
1168 boolean special_redefined =
1169 getImageListEntryFromImageID(graphic)->redefined;
1171 /* if the base graphic ("emerald", for example) has been redefined,
1172 but not the special graphic ("emerald.EDITOR", for example), do not
1173 use an existing (in this case considered obsolete) special graphic
1174 anymore, but use the automatically created (down-scaled) graphic */
1175 if (base_redefined && !special_redefined)
1178 element_info[element].special_graphic[special] = graphic;
1181 // initialize special element/graphic mapping from dynamic configuration
1182 for (i = 0; i < num_property_mappings; i++)
1184 int element = property_mapping[i].base_index;
1185 int action = property_mapping[i].ext1_index;
1186 int direction = property_mapping[i].ext2_index;
1187 int special = property_mapping[i].ext3_index;
1188 int graphic = property_mapping[i].artwork_index;
1190 // for action ".active", replace element with active element, if exists
1191 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1193 element = ELEMENT_ACTIVE(element);
1197 if (element >= MAX_NUM_ELEMENTS)
1200 // do not change special graphic if action or direction was specified
1201 if (action != -1 || direction != -1)
1204 if (IS_SPECIAL_GFX_ARG(special))
1205 element_info[element].special_graphic[special] = graphic;
1208 // now set all undefined/invalid graphics to default
1209 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1210 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1211 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1212 element_info[i].special_graphic[j] =
1213 element_info[i].graphic[ACTION_DEFAULT];
1216 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1218 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1219 return get_parameter_value(value_raw, suffix, type);
1221 if (strEqual(value_raw, ARG_UNDEFINED))
1222 return ARG_UNDEFINED_VALUE;
1224 if (type == TYPE_ELEMENT)
1226 char *value = getHashEntry(element_token_hash, value_raw);
1230 Error(ERR_INFO_LINE, "-");
1231 Error(ERR_INFO, "warning: error found in config file:");
1232 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1233 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1234 Error(ERR_INFO, "custom graphic rejected for this element/action");
1235 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1236 Error(ERR_INFO_LINE, "-");
1239 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1241 else if (type == TYPE_GRAPHIC)
1243 char *value = getHashEntry(graphic_token_hash, value_raw);
1244 int fallback_graphic = IMG_CHAR_EXCLAM;
1248 Error(ERR_INFO_LINE, "-");
1249 Error(ERR_INFO, "warning: error found in config file:");
1250 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1251 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1252 Error(ERR_INFO, "custom graphic rejected for this element/action");
1253 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1254 Error(ERR_INFO_LINE, "-");
1257 return (value != NULL ? atoi(value) : fallback_graphic);
1263 static int get_scaled_graphic_width(int graphic)
1265 int original_width = getOriginalImageWidthFromImageID(graphic);
1266 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1268 return original_width * scale_up_factor;
1271 static int get_scaled_graphic_height(int graphic)
1273 int original_height = getOriginalImageHeightFromImageID(graphic);
1274 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1276 return original_height * scale_up_factor;
1279 static void set_graphic_parameters_ext(int graphic, int *parameter,
1280 Bitmap **src_bitmaps)
1282 struct GraphicInfo *g = &graphic_info[graphic];
1283 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1284 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1285 int anim_frames_per_line = 1;
1287 // always start with reliable default values
1288 g->src_image_width = 0;
1289 g->src_image_height = 0;
1292 g->width = TILEX; // default for element graphics
1293 g->height = TILEY; // default for element graphics
1294 g->offset_x = 0; // one or both of these values ...
1295 g->offset_y = 0; // ... will be corrected later
1296 g->offset2_x = 0; // one or both of these values ...
1297 g->offset2_y = 0; // ... will be corrected later
1298 g->swap_double_tiles = -1; // auto-detect tile swapping
1299 g->crumbled_like = -1; // do not use clone element
1300 g->diggable_like = -1; // do not use clone element
1301 g->border_size = TILEX / 8; // "CRUMBLED" border size
1302 g->scale_up_factor = 1; // default: no scaling up
1303 g->tile_size = TILESIZE; // default: standard tile size
1304 g->clone_from = -1; // do not use clone graphic
1305 g->init_delay_fixed = 0;
1306 g->init_delay_random = 0;
1307 g->init_delay_action = -1;
1308 g->anim_delay_fixed = 0;
1309 g->anim_delay_random = 0;
1310 g->anim_delay_action = -1;
1311 g->post_delay_fixed = 0;
1312 g->post_delay_random = 0;
1313 g->post_delay_action = -1;
1314 g->init_event = ANIM_EVENT_UNDEFINED;
1315 g->anim_event = ANIM_EVENT_UNDEFINED;
1316 g->init_event_action = -1;
1317 g->anim_event_action = -1;
1318 g->draw_masked = FALSE;
1320 g->fade_mode = FADE_MODE_DEFAULT;
1324 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1325 g->align = ALIGN_CENTER; // default for title screens
1326 g->valign = VALIGN_MIDDLE; // default for title screens
1327 g->sort_priority = 0; // default for title screens
1329 g->style = STYLE_DEFAULT;
1331 g->bitmaps = src_bitmaps;
1332 g->bitmap = src_bitmap;
1334 // optional zoom factor for scaling up the image to a larger size
1335 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1336 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1337 if (g->scale_up_factor < 1)
1338 g->scale_up_factor = 1; // no scaling
1340 // optional tile size for using non-standard image size
1341 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1343 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1346 // CHECK: should tile sizes less than standard tile size be allowed?
1347 if (g->tile_size < TILESIZE)
1348 g->tile_size = TILESIZE; // standard tile size
1351 // when setting tile size, also set width and height accordingly
1352 g->width = g->tile_size;
1353 g->height = g->tile_size;
1356 if (g->use_image_size)
1358 // set new default bitmap size (with scaling, but without small images)
1359 g->width = get_scaled_graphic_width(graphic);
1360 g->height = get_scaled_graphic_height(graphic);
1363 // optional width and height of each animation frame
1364 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1365 g->width = parameter[GFX_ARG_WIDTH];
1366 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1367 g->height = parameter[GFX_ARG_HEIGHT];
1369 // optional x and y tile position of animation frame sequence
1370 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1371 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1372 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1373 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1375 // optional x and y pixel position of animation frame sequence
1376 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1377 g->src_x = parameter[GFX_ARG_X];
1378 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1379 g->src_y = parameter[GFX_ARG_Y];
1385 Error(ERR_INFO_LINE, "-");
1386 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1387 g->width, getTokenFromImageID(graphic), TILEX);
1388 Error(ERR_INFO_LINE, "-");
1390 g->width = TILEX; // will be checked to be inside bitmap later
1395 Error(ERR_INFO_LINE, "-");
1396 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1397 g->height, getTokenFromImageID(graphic), TILEY);
1398 Error(ERR_INFO_LINE, "-");
1400 g->height = TILEY; // will be checked to be inside bitmap later
1406 // get final bitmap size (with scaling, but without small images)
1407 int src_image_width = get_scaled_graphic_width(graphic);
1408 int src_image_height = get_scaled_graphic_height(graphic);
1410 if (src_image_width == 0 || src_image_height == 0)
1412 // only happens when loaded outside artwork system (like "global.busy")
1413 src_image_width = src_bitmap->width;
1414 src_image_height = src_bitmap->height;
1417 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1419 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1420 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1424 anim_frames_per_row = MAX(1, src_image_width / g->width);
1425 anim_frames_per_col = MAX(1, src_image_height / g->height);
1428 g->src_image_width = src_image_width;
1429 g->src_image_height = src_image_height;
1432 // correct x or y offset dependent of vertical or horizontal frame order
1433 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1435 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1436 parameter[GFX_ARG_OFFSET] : g->height);
1437 anim_frames_per_line = anim_frames_per_col;
1439 else // frames are ordered horizontally
1441 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1442 parameter[GFX_ARG_OFFSET] : g->width);
1443 anim_frames_per_line = anim_frames_per_row;
1446 // optionally, the x and y offset of frames can be specified directly
1447 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1448 g->offset_x = parameter[GFX_ARG_XOFFSET];
1449 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1450 g->offset_y = parameter[GFX_ARG_YOFFSET];
1452 // optionally, moving animations may have separate start and end graphics
1453 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1455 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1456 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1458 // correct x or y offset2 dependent of vertical or horizontal frame order
1459 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1460 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1461 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1462 else // frames are ordered horizontally
1463 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1464 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1466 // optionally, the x and y offset of 2nd graphic can be specified directly
1467 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1468 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1469 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1470 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1472 // optionally, the second movement tile can be specified as start tile
1473 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1474 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1476 // automatically determine correct number of frames, if not defined
1477 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1478 g->anim_frames = parameter[GFX_ARG_FRAMES];
1479 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1480 g->anim_frames = anim_frames_per_row;
1481 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1482 g->anim_frames = anim_frames_per_col;
1486 if (g->anim_frames < 1) // frames must be at least 1
1489 g->anim_frames_per_line =
1490 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1491 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1493 g->anim_delay = parameter[GFX_ARG_DELAY];
1494 if (g->anim_delay < 1) // delay must be at least 1
1497 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1499 // automatically determine correct start frame, if not defined
1500 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1501 g->anim_start_frame = 0;
1502 else if (g->anim_mode & ANIM_REVERSE)
1503 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1505 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1507 // animation synchronized with global frame counter, not move position
1508 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1510 // optional element for cloning crumble graphics
1511 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1512 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1514 // optional element for cloning digging graphics
1515 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1516 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1518 // optional border size for "crumbling" diggable graphics
1519 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1520 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1522 // used for global animations and player "boring" and "sleeping" actions
1523 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1524 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1525 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1526 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1527 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1528 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1529 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1530 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1531 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1532 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1533 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1534 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1536 // used for global animations
1537 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1538 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1539 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1540 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1541 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1542 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1543 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1544 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1545 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1546 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1547 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1548 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1549 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1550 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1552 // used for toon animations and global animations
1553 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1554 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1555 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1556 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1557 g->direction = parameter[GFX_ARG_DIRECTION];
1558 g->position = parameter[GFX_ARG_POSITION];
1559 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1560 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1562 if (g->step_delay < 1) // delay must be at least 1
1565 // this is only used for drawing font characters
1566 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1567 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1569 // use a different default value for global animations and toons
1570 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1571 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1572 g->draw_masked = TRUE;
1574 // this is used for drawing envelopes, global animations and toons
1575 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1576 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1578 // used for toon animations and global animations
1579 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1580 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1582 // optional graphic for cloning all graphics settings
1583 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1584 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1586 // optional settings for drawing title screens and title messages
1587 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1588 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1589 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1590 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1591 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1592 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1593 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1594 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1595 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1596 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1597 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1598 g->align = parameter[GFX_ARG_ALIGN];
1599 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1600 g->valign = parameter[GFX_ARG_VALIGN];
1601 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1602 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1604 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1605 g->class = parameter[GFX_ARG_CLASS];
1606 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1607 g->style = parameter[GFX_ARG_STYLE];
1609 // this is only used for drawing menu buttons and text
1610 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1611 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1612 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1613 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1616 static void set_graphic_parameters(int graphic)
1618 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1619 char **parameter_raw = image->parameter;
1620 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1621 int parameter[NUM_GFX_ARGS];
1624 // if fallback to default artwork is done, also use the default parameters
1625 if (image->fallback_to_default)
1626 parameter_raw = image->default_parameter;
1628 // get integer values from string parameters
1629 for (i = 0; i < NUM_GFX_ARGS; i++)
1630 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1631 image_config_suffix[i].token,
1632 image_config_suffix[i].type);
1634 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1636 UPDATE_BUSY_STATE();
1639 static void set_cloned_graphic_parameters(int graphic)
1641 int fallback_graphic = IMG_CHAR_EXCLAM;
1642 int max_num_images = getImageListSize();
1643 int clone_graphic = graphic_info[graphic].clone_from;
1644 int num_references_followed = 1;
1646 while (graphic_info[clone_graphic].clone_from != -1 &&
1647 num_references_followed < max_num_images)
1649 clone_graphic = graphic_info[clone_graphic].clone_from;
1651 num_references_followed++;
1654 if (num_references_followed >= max_num_images)
1656 Error(ERR_INFO_LINE, "-");
1657 Error(ERR_INFO, "warning: error found in config file:");
1658 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1659 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1660 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1661 Error(ERR_INFO, "custom graphic rejected for this element/action");
1663 if (graphic == fallback_graphic)
1664 Error(ERR_EXIT, "no fallback graphic available");
1666 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1667 Error(ERR_INFO_LINE, "-");
1669 graphic_info[graphic] = graphic_info[fallback_graphic];
1673 graphic_info[graphic] = graphic_info[clone_graphic];
1674 graphic_info[graphic].clone_from = clone_graphic;
1678 static void InitGraphicInfo(void)
1680 int fallback_graphic = IMG_CHAR_EXCLAM;
1681 int num_images = getImageListSize();
1684 // use image size as default values for width and height for these images
1685 static int full_size_graphics[] =
1688 IMG_GLOBAL_BORDER_MAIN,
1689 IMG_GLOBAL_BORDER_SCORES,
1690 IMG_GLOBAL_BORDER_EDITOR,
1691 IMG_GLOBAL_BORDER_PLAYING,
1694 IMG_BACKGROUND_ENVELOPE_1,
1695 IMG_BACKGROUND_ENVELOPE_2,
1696 IMG_BACKGROUND_ENVELOPE_3,
1697 IMG_BACKGROUND_ENVELOPE_4,
1698 IMG_BACKGROUND_REQUEST,
1701 IMG_BACKGROUND_TITLE_INITIAL,
1702 IMG_BACKGROUND_TITLE,
1703 IMG_BACKGROUND_MAIN,
1704 IMG_BACKGROUND_LEVELS,
1705 IMG_BACKGROUND_LEVELNR,
1706 IMG_BACKGROUND_SCORES,
1707 IMG_BACKGROUND_EDITOR,
1708 IMG_BACKGROUND_INFO,
1709 IMG_BACKGROUND_INFO_ELEMENTS,
1710 IMG_BACKGROUND_INFO_MUSIC,
1711 IMG_BACKGROUND_INFO_CREDITS,
1712 IMG_BACKGROUND_INFO_PROGRAM,
1713 IMG_BACKGROUND_INFO_VERSION,
1714 IMG_BACKGROUND_INFO_LEVELSET,
1715 IMG_BACKGROUND_SETUP,
1716 IMG_BACKGROUND_PLAYING,
1717 IMG_BACKGROUND_DOOR,
1718 IMG_BACKGROUND_TAPE,
1719 IMG_BACKGROUND_PANEL,
1720 IMG_BACKGROUND_PALETTE,
1721 IMG_BACKGROUND_TOOLBOX,
1723 IMG_TITLESCREEN_INITIAL_1,
1724 IMG_TITLESCREEN_INITIAL_2,
1725 IMG_TITLESCREEN_INITIAL_3,
1726 IMG_TITLESCREEN_INITIAL_4,
1727 IMG_TITLESCREEN_INITIAL_5,
1734 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1735 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1736 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1737 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1738 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1739 IMG_BACKGROUND_TITLEMESSAGE_1,
1740 IMG_BACKGROUND_TITLEMESSAGE_2,
1741 IMG_BACKGROUND_TITLEMESSAGE_3,
1742 IMG_BACKGROUND_TITLEMESSAGE_4,
1743 IMG_BACKGROUND_TITLEMESSAGE_5,
1748 FreeGlobalAnimEventInfo();
1750 checked_free(graphic_info);
1752 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1754 // initialize "use_image_size" flag with default value
1755 for (i = 0; i < num_images; i++)
1756 graphic_info[i].use_image_size = FALSE;
1758 // initialize "use_image_size" flag from static configuration above
1759 for (i = 0; full_size_graphics[i] != -1; i++)
1760 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1762 // first set all graphic paramaters ...
1763 for (i = 0; i < num_images; i++)
1764 set_graphic_parameters(i);
1766 // ... then copy these parameters for cloned graphics
1767 for (i = 0; i < num_images; i++)
1768 if (graphic_info[i].clone_from != -1)
1769 set_cloned_graphic_parameters(i);
1771 for (i = 0; i < num_images; i++)
1773 Bitmap *src_bitmap = graphic_info[i].bitmap;
1777 int src_bitmap_width, src_bitmap_height;
1779 // now check if no animation frames are outside of the loaded image
1781 if (graphic_info[i].bitmap == NULL)
1782 continue; // skip check for optional images that are undefined
1784 // get image size (this can differ from the standard element tile size!)
1785 width = graphic_info[i].width;
1786 height = graphic_info[i].height;
1788 // get final bitmap size (with scaling, but without small images)
1789 src_bitmap_width = graphic_info[i].src_image_width;
1790 src_bitmap_height = graphic_info[i].src_image_height;
1792 // check if first animation frame is inside specified bitmap
1794 // do not use getGraphicSourceXY() here to get position of first frame;
1795 // this avoids calculating wrong start position for out-of-bounds frame
1796 src_x = graphic_info[i].src_x;
1797 src_y = graphic_info[i].src_y;
1799 if (program.headless)
1802 if (src_x < 0 || src_y < 0 ||
1803 src_x + width > src_bitmap_width ||
1804 src_y + height > src_bitmap_height)
1806 Error(ERR_INFO_LINE, "-");
1807 Error(ERR_INFO, "warning: error found in config file:");
1808 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1809 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1810 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1811 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1813 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1814 src_x, src_y, src_bitmap_width, src_bitmap_height);
1815 Error(ERR_INFO, "custom graphic rejected for this element/action");
1817 if (i == fallback_graphic)
1818 Error(ERR_EXIT, "no fallback graphic available");
1820 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1821 Error(ERR_INFO_LINE, "-");
1823 graphic_info[i] = graphic_info[fallback_graphic];
1825 // if first frame out of bounds, do not check last frame anymore
1829 // check if last animation frame is inside specified bitmap
1831 last_frame = graphic_info[i].anim_frames - 1;
1832 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1834 if (src_x < 0 || src_y < 0 ||
1835 src_x + width > src_bitmap_width ||
1836 src_y + height > src_bitmap_height)
1838 Error(ERR_INFO_LINE, "-");
1839 Error(ERR_INFO, "warning: error found in config file:");
1840 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1841 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1842 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1843 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1845 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1846 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1847 Error(ERR_INFO, "custom graphic rejected for this element/action");
1849 if (i == fallback_graphic)
1850 Error(ERR_EXIT, "no fallback graphic available");
1852 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1853 Error(ERR_INFO_LINE, "-");
1855 graphic_info[i] = graphic_info[fallback_graphic];
1860 static void InitGraphicCompatibilityInfo(void)
1862 struct FileInfo *fi_global_door =
1863 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1864 int num_images = getImageListSize();
1867 /* the following compatibility handling is needed for the following case:
1868 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1869 graphics mainly used for door and panel graphics, like editor, tape and
1870 in-game buttons with hard-coded bitmap positions and button sizes; as
1871 these graphics now have individual definitions, redefining "global.door"
1872 to change all these graphics at once like before does not work anymore
1873 (because all those individual definitions still have their default values);
1874 to solve this, remap all those individual definitions that are not
1875 redefined to the new bitmap of "global.door" if it was redefined */
1877 // special compatibility handling if image "global.door" was redefined
1878 if (fi_global_door->redefined)
1880 for (i = 0; i < num_images; i++)
1882 struct FileInfo *fi = getImageListEntryFromImageID(i);
1884 // process only those images that still use the default settings
1887 // process all images which default to same image as "global.door"
1888 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1890 // printf("::: special treatment needed for token '%s'\n", fi->token);
1892 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1893 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1899 InitGraphicCompatibilityInfo_Doors();
1902 static void InitElementSoundInfo(void)
1904 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1905 int num_property_mappings = getSoundListPropertyMappingSize();
1908 // set values to -1 to identify later as "uninitialized" values
1909 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1910 for (act = 0; act < NUM_ACTIONS; act++)
1911 element_info[i].sound[act] = -1;
1913 // initialize element/sound mapping from static configuration
1914 for (i = 0; element_to_sound[i].element > -1; i++)
1916 int element = element_to_sound[i].element;
1917 int action = element_to_sound[i].action;
1918 int sound = element_to_sound[i].sound;
1919 boolean is_class = element_to_sound[i].is_class;
1922 action = ACTION_DEFAULT;
1925 element_info[element].sound[action] = sound;
1927 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1928 if (strEqual(element_info[j].class_name,
1929 element_info[element].class_name))
1930 element_info[j].sound[action] = sound;
1933 // initialize element class/sound mapping from dynamic configuration
1934 for (i = 0; i < num_property_mappings; i++)
1936 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1937 int action = property_mapping[i].ext1_index;
1938 int sound = property_mapping[i].artwork_index;
1940 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1944 action = ACTION_DEFAULT;
1946 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1947 if (strEqual(element_info[j].class_name,
1948 element_info[element_class].class_name))
1949 element_info[j].sound[action] = sound;
1952 // initialize element/sound mapping from dynamic configuration
1953 for (i = 0; i < num_property_mappings; i++)
1955 int element = property_mapping[i].base_index;
1956 int action = property_mapping[i].ext1_index;
1957 int sound = property_mapping[i].artwork_index;
1959 if (element >= MAX_NUM_ELEMENTS)
1963 action = ACTION_DEFAULT;
1965 element_info[element].sound[action] = sound;
1968 // now set all '-1' values to element specific default values
1969 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1971 for (act = 0; act < NUM_ACTIONS; act++)
1973 // generic default action sound (defined by "[default]" directive)
1974 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1976 // look for special default action sound (classic game specific)
1977 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1978 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1979 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1980 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1981 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1982 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1983 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1984 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1986 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1987 // !!! make this better !!!
1988 if (i == EL_EMPTY_SPACE)
1989 default_action_sound = element_info[EL_DEFAULT].sound[act];
1991 // no sound for this specific action -- use default action sound
1992 if (element_info[i].sound[act] == -1)
1993 element_info[i].sound[act] = default_action_sound;
1997 // copy sound settings to some elements that are only stored in level file
1998 // in native R'n'D levels, but are used by game engine in native EM levels
1999 for (i = 0; copy_properties[i][0] != -1; i++)
2000 for (j = 1; j <= 4; j++)
2001 for (act = 0; act < NUM_ACTIONS; act++)
2002 element_info[copy_properties[i][j]].sound[act] =
2003 element_info[copy_properties[i][0]].sound[act];
2006 static void InitGameModeSoundInfo(void)
2010 // set values to -1 to identify later as "uninitialized" values
2011 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2014 // initialize gamemode/sound mapping from static configuration
2015 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2017 int gamemode = gamemode_to_sound[i].gamemode;
2018 int sound = gamemode_to_sound[i].sound;
2021 gamemode = GAME_MODE_DEFAULT;
2023 menu.sound[gamemode] = sound;
2026 // now set all '-1' values to levelset specific default values
2027 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2028 if (menu.sound[i] == -1)
2029 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2032 static void set_sound_parameters(int sound, char **parameter_raw)
2034 int parameter[NUM_SND_ARGS];
2037 // get integer values from string parameters
2038 for (i = 0; i < NUM_SND_ARGS; i++)
2040 get_parameter_value(parameter_raw[i],
2041 sound_config_suffix[i].token,
2042 sound_config_suffix[i].type);
2044 // explicit loop mode setting in configuration overrides default value
2045 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2046 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2048 // sound volume to change the original volume when loading the sound file
2049 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2051 // sound priority to give certain sounds a higher or lower priority
2052 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2055 static void InitSoundInfo(void)
2057 int *sound_effect_properties;
2058 int num_sounds = getSoundListSize();
2061 checked_free(sound_info);
2063 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2064 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2066 // initialize sound effect for all elements to "no sound"
2067 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2068 for (j = 0; j < NUM_ACTIONS; j++)
2069 element_info[i].sound[j] = SND_UNDEFINED;
2071 for (i = 0; i < num_sounds; i++)
2073 struct FileInfo *sound = getSoundListEntry(i);
2074 int len_effect_text = strlen(sound->token);
2076 sound_effect_properties[i] = ACTION_OTHER;
2077 sound_info[i].loop = FALSE; // default: play sound only once
2079 // determine all loop sounds and identify certain sound classes
2081 for (j = 0; element_action_info[j].suffix; j++)
2083 int len_action_text = strlen(element_action_info[j].suffix);
2085 if (len_action_text < len_effect_text &&
2086 strEqual(&sound->token[len_effect_text - len_action_text],
2087 element_action_info[j].suffix))
2089 sound_effect_properties[i] = element_action_info[j].value;
2090 sound_info[i].loop = element_action_info[j].is_loop_sound;
2096 // associate elements and some selected sound actions
2098 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2100 if (element_info[j].class_name)
2102 int len_class_text = strlen(element_info[j].class_name);
2104 if (len_class_text + 1 < len_effect_text &&
2105 strncmp(sound->token,
2106 element_info[j].class_name, len_class_text) == 0 &&
2107 sound->token[len_class_text] == '.')
2109 int sound_action_value = sound_effect_properties[i];
2111 element_info[j].sound[sound_action_value] = i;
2116 set_sound_parameters(i, sound->parameter);
2119 free(sound_effect_properties);
2122 static void InitGameModeMusicInfo(void)
2124 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2125 int num_property_mappings = getMusicListPropertyMappingSize();
2126 int default_levelset_music = -1;
2129 // set values to -1 to identify later as "uninitialized" values
2130 for (i = 0; i < MAX_LEVELS; i++)
2131 levelset.music[i] = -1;
2132 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2135 // initialize gamemode/music mapping from static configuration
2136 for (i = 0; gamemode_to_music[i].music > -1; i++)
2138 int gamemode = gamemode_to_music[i].gamemode;
2139 int music = gamemode_to_music[i].music;
2142 gamemode = GAME_MODE_DEFAULT;
2144 menu.music[gamemode] = music;
2147 // initialize gamemode/music mapping from dynamic configuration
2148 for (i = 0; i < num_property_mappings; i++)
2150 int prefix = property_mapping[i].base_index;
2151 int gamemode = property_mapping[i].ext2_index;
2152 int level = property_mapping[i].ext3_index;
2153 int music = property_mapping[i].artwork_index;
2155 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2159 gamemode = GAME_MODE_DEFAULT;
2161 // level specific music only allowed for in-game music
2162 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2163 gamemode = GAME_MODE_PLAYING;
2168 default_levelset_music = music;
2171 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2172 levelset.music[level] = music;
2173 if (gamemode != GAME_MODE_PLAYING)
2174 menu.music[gamemode] = music;
2177 // now set all '-1' values to menu specific default values
2178 // (undefined values of "levelset.music[]" might stay at "-1" to
2179 // allow dynamic selection of music files from music directory!)
2180 for (i = 0; i < MAX_LEVELS; i++)
2181 if (levelset.music[i] == -1)
2182 levelset.music[i] = default_levelset_music;
2183 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2184 if (menu.music[i] == -1)
2185 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2188 static void set_music_parameters(int music, char **parameter_raw)
2190 int parameter[NUM_MUS_ARGS];
2193 // get integer values from string parameters
2194 for (i = 0; i < NUM_MUS_ARGS; i++)
2196 get_parameter_value(parameter_raw[i],
2197 music_config_suffix[i].token,
2198 music_config_suffix[i].type);
2200 // explicit loop mode setting in configuration overrides default value
2201 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2202 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2205 static void InitMusicInfo(void)
2207 int num_music = getMusicListSize();
2210 checked_free(music_info);
2212 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2214 for (i = 0; i < num_music; i++)
2216 struct FileInfo *music = getMusicListEntry(i);
2217 int len_music_text = strlen(music->token);
2219 music_info[i].loop = TRUE; // default: play music in loop mode
2221 // determine all loop music
2223 for (j = 0; music_prefix_info[j].prefix; j++)
2225 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2227 if (len_prefix_text < len_music_text &&
2228 strncmp(music->token,
2229 music_prefix_info[j].prefix, len_prefix_text) == 0)
2231 music_info[i].loop = music_prefix_info[j].is_loop_music;
2237 set_music_parameters(i, music->parameter);
2241 static void ReinitializeGraphics(void)
2243 print_timestamp_init("ReinitializeGraphics");
2245 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2247 InitGraphicInfo(); // graphic properties mapping
2248 print_timestamp_time("InitGraphicInfo");
2249 InitElementGraphicInfo(); // element game graphic mapping
2250 print_timestamp_time("InitElementGraphicInfo");
2251 InitElementSpecialGraphicInfo(); // element special graphic mapping
2252 print_timestamp_time("InitElementSpecialGraphicInfo");
2254 InitElementSmallImages(); // scale elements to all needed sizes
2255 print_timestamp_time("InitElementSmallImages");
2256 InitScaledImages(); // scale all other images, if needed
2257 print_timestamp_time("InitScaledImages");
2258 InitBitmapPointers(); // set standard size bitmap pointers
2259 print_timestamp_time("InitBitmapPointers");
2260 InitFontGraphicInfo(); // initialize text drawing functions
2261 print_timestamp_time("InitFontGraphicInfo");
2262 InitGlobalAnimGraphicInfo(); // initialize global animation config
2263 print_timestamp_time("InitGlobalAnimGraphicInfo");
2265 InitImageTextures(); // create textures for certain images
2266 print_timestamp_time("InitImageTextures");
2268 InitGraphicInfo_EM(); // graphic mapping for EM engine
2269 print_timestamp_time("InitGraphicInfo_EM");
2271 InitGraphicCompatibilityInfo();
2272 print_timestamp_time("InitGraphicCompatibilityInfo");
2274 SetMainBackgroundImage(IMG_BACKGROUND);
2275 print_timestamp_time("SetMainBackgroundImage");
2276 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2277 print_timestamp_time("SetDoorBackgroundImage");
2280 print_timestamp_time("InitGadgets");
2282 print_timestamp_time("InitDoors");
2284 print_timestamp_done("ReinitializeGraphics");
2287 static void ReinitializeSounds(void)
2289 InitSoundInfo(); // sound properties mapping
2290 InitElementSoundInfo(); // element game sound mapping
2291 InitGameModeSoundInfo(); // game mode sound mapping
2292 InitGlobalAnimSoundInfo(); // global animation sound settings
2294 InitPlayLevelSound(); // internal game sound settings
2297 static void ReinitializeMusic(void)
2299 InitMusicInfo(); // music properties mapping
2300 InitGameModeMusicInfo(); // game mode music mapping
2301 InitGlobalAnimMusicInfo(); // global animation music settings
2304 static int get_special_property_bit(int element, int property_bit_nr)
2306 struct PropertyBitInfo
2312 static struct PropertyBitInfo pb_can_move_into_acid[] =
2314 // the player may be able fall into acid when gravity is activated
2319 { EL_SP_MURPHY, 0 },
2320 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2322 // all elements that can move may be able to also move into acid
2325 { EL_BUG_RIGHT, 1 },
2328 { EL_SPACESHIP, 2 },
2329 { EL_SPACESHIP_LEFT, 2 },
2330 { EL_SPACESHIP_RIGHT, 2 },
2331 { EL_SPACESHIP_UP, 2 },
2332 { EL_SPACESHIP_DOWN, 2 },
2333 { EL_BD_BUTTERFLY, 3 },
2334 { EL_BD_BUTTERFLY_LEFT, 3 },
2335 { EL_BD_BUTTERFLY_RIGHT, 3 },
2336 { EL_BD_BUTTERFLY_UP, 3 },
2337 { EL_BD_BUTTERFLY_DOWN, 3 },
2338 { EL_BD_FIREFLY, 4 },
2339 { EL_BD_FIREFLY_LEFT, 4 },
2340 { EL_BD_FIREFLY_RIGHT, 4 },
2341 { EL_BD_FIREFLY_UP, 4 },
2342 { EL_BD_FIREFLY_DOWN, 4 },
2344 { EL_YAMYAM_LEFT, 5 },
2345 { EL_YAMYAM_RIGHT, 5 },
2346 { EL_YAMYAM_UP, 5 },
2347 { EL_YAMYAM_DOWN, 5 },
2348 { EL_DARK_YAMYAM, 6 },
2351 { EL_PACMAN_LEFT, 8 },
2352 { EL_PACMAN_RIGHT, 8 },
2353 { EL_PACMAN_UP, 8 },
2354 { EL_PACMAN_DOWN, 8 },
2356 { EL_MOLE_LEFT, 9 },
2357 { EL_MOLE_RIGHT, 9 },
2359 { EL_MOLE_DOWN, 9 },
2363 { EL_SATELLITE, 13 },
2364 { EL_SP_SNIKSNAK, 14 },
2365 { EL_SP_ELECTRON, 15 },
2368 { EL_EMC_ANDROID, 18 },
2373 static struct PropertyBitInfo pb_dont_collide_with[] =
2375 { EL_SP_SNIKSNAK, 0 },
2376 { EL_SP_ELECTRON, 1 },
2384 struct PropertyBitInfo *pb_info;
2387 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2388 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2393 struct PropertyBitInfo *pb_info = NULL;
2396 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2397 if (pb_definition[i].bit_nr == property_bit_nr)
2398 pb_info = pb_definition[i].pb_info;
2400 if (pb_info == NULL)
2403 for (i = 0; pb_info[i].element != -1; i++)
2404 if (pb_info[i].element == element)
2405 return pb_info[i].bit_nr;
2410 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2411 boolean property_value)
2413 int bit_nr = get_special_property_bit(element, property_bit_nr);
2418 *bitfield |= (1 << bit_nr);
2420 *bitfield &= ~(1 << bit_nr);
2424 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2426 int bit_nr = get_special_property_bit(element, property_bit_nr);
2429 return ((*bitfield & (1 << bit_nr)) != 0);
2434 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2436 static int group_nr;
2437 static struct ElementGroupInfo *group;
2438 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2441 if (actual_group == NULL) // not yet initialized
2444 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2446 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2447 group_element - EL_GROUP_START + 1);
2449 // replace element which caused too deep recursion by question mark
2450 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2455 if (recursion_depth == 0) // initialization
2457 group = actual_group;
2458 group_nr = GROUP_NR(group_element);
2460 group->num_elements_resolved = 0;
2461 group->choice_pos = 0;
2463 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2464 element_info[i].in_group[group_nr] = FALSE;
2467 for (i = 0; i < actual_group->num_elements; i++)
2469 int element = actual_group->element[i];
2471 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2474 if (IS_GROUP_ELEMENT(element))
2475 ResolveGroupElementExt(element, recursion_depth + 1);
2478 group->element_resolved[group->num_elements_resolved++] = element;
2479 element_info[element].in_group[group_nr] = TRUE;
2484 void ResolveGroupElement(int group_element)
2486 ResolveGroupElementExt(group_element, 0);
2489 void InitElementPropertiesStatic(void)
2491 static boolean clipboard_elements_initialized = FALSE;
2493 static int ep_diggable[] =
2498 EL_SP_BUGGY_BASE_ACTIVATING,
2501 EL_INVISIBLE_SAND_ACTIVE,
2504 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2505 // (if amoeba can grow into anything diggable, maybe keep these out)
2510 EL_SP_BUGGY_BASE_ACTIVE,
2517 static int ep_collectible_only[] =
2539 EL_DYNABOMB_INCREASE_NUMBER,
2540 EL_DYNABOMB_INCREASE_SIZE,
2541 EL_DYNABOMB_INCREASE_POWER,
2559 // !!! handle separately !!!
2560 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2566 static int ep_dont_run_into[] =
2568 // same elements as in 'ep_dont_touch'
2574 // same elements as in 'ep_dont_collide_with'
2586 // !!! maybe this should better be handled by 'ep_diggable' !!!
2591 EL_SP_BUGGY_BASE_ACTIVE,
2598 static int ep_dont_collide_with[] =
2600 // same elements as in 'ep_dont_touch'
2617 static int ep_dont_touch[] =
2627 static int ep_indestructible[] =
2631 EL_ACID_POOL_TOPLEFT,
2632 EL_ACID_POOL_TOPRIGHT,
2633 EL_ACID_POOL_BOTTOMLEFT,
2634 EL_ACID_POOL_BOTTOM,
2635 EL_ACID_POOL_BOTTOMRIGHT,
2636 EL_SP_HARDWARE_GRAY,
2637 EL_SP_HARDWARE_GREEN,
2638 EL_SP_HARDWARE_BLUE,
2640 EL_SP_HARDWARE_YELLOW,
2641 EL_SP_HARDWARE_BASE_1,
2642 EL_SP_HARDWARE_BASE_2,
2643 EL_SP_HARDWARE_BASE_3,
2644 EL_SP_HARDWARE_BASE_4,
2645 EL_SP_HARDWARE_BASE_5,
2646 EL_SP_HARDWARE_BASE_6,
2647 EL_INVISIBLE_STEELWALL,
2648 EL_INVISIBLE_STEELWALL_ACTIVE,
2649 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2650 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2651 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2652 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2653 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2654 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2655 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2656 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2657 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2658 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2659 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2660 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2662 EL_LIGHT_SWITCH_ACTIVE,
2663 EL_SIGN_EXCLAMATION,
2664 EL_SIGN_RADIOACTIVITY,
2671 EL_SIGN_ENTRY_FORBIDDEN,
2672 EL_SIGN_EMERGENCY_EXIT,
2680 EL_STEEL_EXIT_CLOSED,
2682 EL_STEEL_EXIT_OPENING,
2683 EL_STEEL_EXIT_CLOSING,
2684 EL_EM_STEEL_EXIT_CLOSED,
2685 EL_EM_STEEL_EXIT_OPEN,
2686 EL_EM_STEEL_EXIT_OPENING,
2687 EL_EM_STEEL_EXIT_CLOSING,
2688 EL_DC_STEELWALL_1_LEFT,
2689 EL_DC_STEELWALL_1_RIGHT,
2690 EL_DC_STEELWALL_1_TOP,
2691 EL_DC_STEELWALL_1_BOTTOM,
2692 EL_DC_STEELWALL_1_HORIZONTAL,
2693 EL_DC_STEELWALL_1_VERTICAL,
2694 EL_DC_STEELWALL_1_TOPLEFT,
2695 EL_DC_STEELWALL_1_TOPRIGHT,
2696 EL_DC_STEELWALL_1_BOTTOMLEFT,
2697 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2698 EL_DC_STEELWALL_1_TOPLEFT_2,
2699 EL_DC_STEELWALL_1_TOPRIGHT_2,
2700 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2701 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2702 EL_DC_STEELWALL_2_LEFT,
2703 EL_DC_STEELWALL_2_RIGHT,
2704 EL_DC_STEELWALL_2_TOP,
2705 EL_DC_STEELWALL_2_BOTTOM,
2706 EL_DC_STEELWALL_2_HORIZONTAL,
2707 EL_DC_STEELWALL_2_VERTICAL,
2708 EL_DC_STEELWALL_2_MIDDLE,
2709 EL_DC_STEELWALL_2_SINGLE,
2710 EL_STEELWALL_SLIPPERY,
2724 EL_GATE_1_GRAY_ACTIVE,
2725 EL_GATE_2_GRAY_ACTIVE,
2726 EL_GATE_3_GRAY_ACTIVE,
2727 EL_GATE_4_GRAY_ACTIVE,
2736 EL_EM_GATE_1_GRAY_ACTIVE,
2737 EL_EM_GATE_2_GRAY_ACTIVE,
2738 EL_EM_GATE_3_GRAY_ACTIVE,
2739 EL_EM_GATE_4_GRAY_ACTIVE,
2748 EL_EMC_GATE_5_GRAY_ACTIVE,
2749 EL_EMC_GATE_6_GRAY_ACTIVE,
2750 EL_EMC_GATE_7_GRAY_ACTIVE,
2751 EL_EMC_GATE_8_GRAY_ACTIVE,
2753 EL_DC_GATE_WHITE_GRAY,
2754 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2755 EL_DC_GATE_FAKE_GRAY,
2757 EL_SWITCHGATE_OPENING,
2758 EL_SWITCHGATE_CLOSED,
2759 EL_SWITCHGATE_CLOSING,
2760 EL_DC_SWITCHGATE_SWITCH_UP,
2761 EL_DC_SWITCHGATE_SWITCH_DOWN,
2763 EL_TIMEGATE_OPENING,
2765 EL_TIMEGATE_CLOSING,
2766 EL_DC_TIMEGATE_SWITCH,
2767 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2771 EL_TUBE_VERTICAL_LEFT,
2772 EL_TUBE_VERTICAL_RIGHT,
2773 EL_TUBE_HORIZONTAL_UP,
2774 EL_TUBE_HORIZONTAL_DOWN,
2779 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2780 EL_EXPANDABLE_STEELWALL_VERTICAL,
2781 EL_EXPANDABLE_STEELWALL_ANY,
2786 static int ep_slippery[] =
2800 EL_ROBOT_WHEEL_ACTIVE,
2806 EL_ACID_POOL_TOPLEFT,
2807 EL_ACID_POOL_TOPRIGHT,
2817 EL_STEELWALL_SLIPPERY,
2820 EL_EMC_WALL_SLIPPERY_1,
2821 EL_EMC_WALL_SLIPPERY_2,
2822 EL_EMC_WALL_SLIPPERY_3,
2823 EL_EMC_WALL_SLIPPERY_4,
2825 EL_EMC_MAGIC_BALL_ACTIVE,
2830 static int ep_can_change[] =
2835 static int ep_can_move[] =
2837 // same elements as in 'pb_can_move_into_acid'
2860 static int ep_can_fall[] =
2874 EL_QUICKSAND_FAST_FULL,
2876 EL_BD_MAGIC_WALL_FULL,
2877 EL_DC_MAGIC_WALL_FULL,
2891 static int ep_can_smash_player[] =
2917 static int ep_can_smash_enemies[] =
2926 static int ep_can_smash_everything[] =
2935 static int ep_explodes_by_fire[] =
2937 // same elements as in 'ep_explodes_impact'
2942 // same elements as in 'ep_explodes_smashed'
2952 EL_EM_DYNAMITE_ACTIVE,
2953 EL_DYNABOMB_PLAYER_1_ACTIVE,
2954 EL_DYNABOMB_PLAYER_2_ACTIVE,
2955 EL_DYNABOMB_PLAYER_3_ACTIVE,
2956 EL_DYNABOMB_PLAYER_4_ACTIVE,
2957 EL_DYNABOMB_INCREASE_NUMBER,
2958 EL_DYNABOMB_INCREASE_SIZE,
2959 EL_DYNABOMB_INCREASE_POWER,
2960 EL_SP_DISK_RED_ACTIVE,
2974 static int ep_explodes_smashed[] =
2976 // same elements as in 'ep_explodes_impact'
2990 static int ep_explodes_impact[] =
2999 static int ep_walkable_over[] =
3003 EL_SOKOBAN_FIELD_EMPTY,
3010 EL_EM_STEEL_EXIT_OPEN,
3011 EL_EM_STEEL_EXIT_OPENING,
3020 EL_GATE_1_GRAY_ACTIVE,
3021 EL_GATE_2_GRAY_ACTIVE,
3022 EL_GATE_3_GRAY_ACTIVE,
3023 EL_GATE_4_GRAY_ACTIVE,
3031 static int ep_walkable_inside[] =
3036 EL_TUBE_VERTICAL_LEFT,
3037 EL_TUBE_VERTICAL_RIGHT,
3038 EL_TUBE_HORIZONTAL_UP,
3039 EL_TUBE_HORIZONTAL_DOWN,
3048 static int ep_walkable_under[] =
3053 static int ep_passable_over[] =
3063 EL_EM_GATE_1_GRAY_ACTIVE,
3064 EL_EM_GATE_2_GRAY_ACTIVE,
3065 EL_EM_GATE_3_GRAY_ACTIVE,
3066 EL_EM_GATE_4_GRAY_ACTIVE,
3075 EL_EMC_GATE_5_GRAY_ACTIVE,
3076 EL_EMC_GATE_6_GRAY_ACTIVE,
3077 EL_EMC_GATE_7_GRAY_ACTIVE,
3078 EL_EMC_GATE_8_GRAY_ACTIVE,
3080 EL_DC_GATE_WHITE_GRAY,
3081 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3088 static int ep_passable_inside[] =
3094 EL_SP_PORT_HORIZONTAL,
3095 EL_SP_PORT_VERTICAL,
3097 EL_SP_GRAVITY_PORT_LEFT,
3098 EL_SP_GRAVITY_PORT_RIGHT,
3099 EL_SP_GRAVITY_PORT_UP,
3100 EL_SP_GRAVITY_PORT_DOWN,
3101 EL_SP_GRAVITY_ON_PORT_LEFT,
3102 EL_SP_GRAVITY_ON_PORT_RIGHT,
3103 EL_SP_GRAVITY_ON_PORT_UP,
3104 EL_SP_GRAVITY_ON_PORT_DOWN,
3105 EL_SP_GRAVITY_OFF_PORT_LEFT,
3106 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3107 EL_SP_GRAVITY_OFF_PORT_UP,
3108 EL_SP_GRAVITY_OFF_PORT_DOWN,
3113 static int ep_passable_under[] =
3118 static int ep_droppable[] =
3123 static int ep_explodes_1x1_old[] =
3128 static int ep_pushable[] =
3140 EL_SOKOBAN_FIELD_FULL,
3149 static int ep_explodes_cross_old[] =
3154 static int ep_protected[] =
3156 // same elements as in 'ep_walkable_inside'
3160 EL_TUBE_VERTICAL_LEFT,
3161 EL_TUBE_VERTICAL_RIGHT,
3162 EL_TUBE_HORIZONTAL_UP,
3163 EL_TUBE_HORIZONTAL_DOWN,
3169 // same elements as in 'ep_passable_over'
3178 EL_EM_GATE_1_GRAY_ACTIVE,
3179 EL_EM_GATE_2_GRAY_ACTIVE,
3180 EL_EM_GATE_3_GRAY_ACTIVE,
3181 EL_EM_GATE_4_GRAY_ACTIVE,
3190 EL_EMC_GATE_5_GRAY_ACTIVE,
3191 EL_EMC_GATE_6_GRAY_ACTIVE,
3192 EL_EMC_GATE_7_GRAY_ACTIVE,
3193 EL_EMC_GATE_8_GRAY_ACTIVE,
3195 EL_DC_GATE_WHITE_GRAY,
3196 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3200 // same elements as in 'ep_passable_inside'
3205 EL_SP_PORT_HORIZONTAL,
3206 EL_SP_PORT_VERTICAL,
3208 EL_SP_GRAVITY_PORT_LEFT,
3209 EL_SP_GRAVITY_PORT_RIGHT,
3210 EL_SP_GRAVITY_PORT_UP,
3211 EL_SP_GRAVITY_PORT_DOWN,
3212 EL_SP_GRAVITY_ON_PORT_LEFT,
3213 EL_SP_GRAVITY_ON_PORT_RIGHT,
3214 EL_SP_GRAVITY_ON_PORT_UP,
3215 EL_SP_GRAVITY_ON_PORT_DOWN,
3216 EL_SP_GRAVITY_OFF_PORT_LEFT,
3217 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3218 EL_SP_GRAVITY_OFF_PORT_UP,
3219 EL_SP_GRAVITY_OFF_PORT_DOWN,
3224 static int ep_throwable[] =
3229 static int ep_can_explode[] =
3231 // same elements as in 'ep_explodes_impact'
3236 // same elements as in 'ep_explodes_smashed'
3242 // elements that can explode by explosion or by dragonfire
3246 EL_EM_DYNAMITE_ACTIVE,
3247 EL_DYNABOMB_PLAYER_1_ACTIVE,
3248 EL_DYNABOMB_PLAYER_2_ACTIVE,
3249 EL_DYNABOMB_PLAYER_3_ACTIVE,
3250 EL_DYNABOMB_PLAYER_4_ACTIVE,
3251 EL_DYNABOMB_INCREASE_NUMBER,
3252 EL_DYNABOMB_INCREASE_SIZE,
3253 EL_DYNABOMB_INCREASE_POWER,
3254 EL_SP_DISK_RED_ACTIVE,
3262 // elements that can explode only by explosion
3268 static int ep_gravity_reachable[] =
3274 EL_INVISIBLE_SAND_ACTIVE,
3279 EL_SP_PORT_HORIZONTAL,
3280 EL_SP_PORT_VERTICAL,
3282 EL_SP_GRAVITY_PORT_LEFT,
3283 EL_SP_GRAVITY_PORT_RIGHT,
3284 EL_SP_GRAVITY_PORT_UP,
3285 EL_SP_GRAVITY_PORT_DOWN,
3286 EL_SP_GRAVITY_ON_PORT_LEFT,
3287 EL_SP_GRAVITY_ON_PORT_RIGHT,
3288 EL_SP_GRAVITY_ON_PORT_UP,
3289 EL_SP_GRAVITY_ON_PORT_DOWN,
3290 EL_SP_GRAVITY_OFF_PORT_LEFT,
3291 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3292 EL_SP_GRAVITY_OFF_PORT_UP,
3293 EL_SP_GRAVITY_OFF_PORT_DOWN,
3299 static int ep_player[] =
3306 EL_SOKOBAN_FIELD_PLAYER,
3312 static int ep_can_pass_magic_wall[] =
3326 static int ep_can_pass_dc_magic_wall[] =
3342 static int ep_switchable[] =
3346 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3347 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3348 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3349 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3350 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3351 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3352 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3353 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3354 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3355 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3356 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3357 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3358 EL_SWITCHGATE_SWITCH_UP,
3359 EL_SWITCHGATE_SWITCH_DOWN,
3360 EL_DC_SWITCHGATE_SWITCH_UP,
3361 EL_DC_SWITCHGATE_SWITCH_DOWN,
3363 EL_LIGHT_SWITCH_ACTIVE,
3365 EL_DC_TIMEGATE_SWITCH,
3366 EL_BALLOON_SWITCH_LEFT,
3367 EL_BALLOON_SWITCH_RIGHT,
3368 EL_BALLOON_SWITCH_UP,
3369 EL_BALLOON_SWITCH_DOWN,
3370 EL_BALLOON_SWITCH_ANY,
3371 EL_BALLOON_SWITCH_NONE,
3374 EL_EMC_MAGIC_BALL_SWITCH,
3375 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3380 static int ep_bd_element[] =
3414 static int ep_sp_element[] =
3416 // should always be valid
3419 // standard classic Supaplex elements
3426 EL_SP_HARDWARE_GRAY,
3434 EL_SP_GRAVITY_PORT_RIGHT,
3435 EL_SP_GRAVITY_PORT_DOWN,
3436 EL_SP_GRAVITY_PORT_LEFT,
3437 EL_SP_GRAVITY_PORT_UP,
3442 EL_SP_PORT_VERTICAL,
3443 EL_SP_PORT_HORIZONTAL,
3449 EL_SP_HARDWARE_BASE_1,
3450 EL_SP_HARDWARE_GREEN,
3451 EL_SP_HARDWARE_BLUE,
3453 EL_SP_HARDWARE_YELLOW,
3454 EL_SP_HARDWARE_BASE_2,
3455 EL_SP_HARDWARE_BASE_3,
3456 EL_SP_HARDWARE_BASE_4,
3457 EL_SP_HARDWARE_BASE_5,
3458 EL_SP_HARDWARE_BASE_6,
3462 // additional elements that appeared in newer Supaplex levels
3465 // additional gravity port elements (not switching, but setting gravity)
3466 EL_SP_GRAVITY_ON_PORT_LEFT,
3467 EL_SP_GRAVITY_ON_PORT_RIGHT,
3468 EL_SP_GRAVITY_ON_PORT_UP,
3469 EL_SP_GRAVITY_ON_PORT_DOWN,
3470 EL_SP_GRAVITY_OFF_PORT_LEFT,
3471 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3472 EL_SP_GRAVITY_OFF_PORT_UP,
3473 EL_SP_GRAVITY_OFF_PORT_DOWN,
3475 // more than one Murphy in a level results in an inactive clone
3478 // runtime Supaplex elements
3479 EL_SP_DISK_RED_ACTIVE,
3480 EL_SP_TERMINAL_ACTIVE,
3481 EL_SP_BUGGY_BASE_ACTIVATING,
3482 EL_SP_BUGGY_BASE_ACTIVE,
3489 static int ep_sb_element[] =
3494 EL_SOKOBAN_FIELD_EMPTY,
3495 EL_SOKOBAN_FIELD_FULL,
3496 EL_SOKOBAN_FIELD_PLAYER,
3501 EL_INVISIBLE_STEELWALL,
3506 static int ep_gem[] =
3518 static int ep_food_dark_yamyam[] =
3546 static int ep_food_penguin[] =
3560 static int ep_food_pig[] =
3572 static int ep_historic_wall[] =
3583 EL_GATE_1_GRAY_ACTIVE,
3584 EL_GATE_2_GRAY_ACTIVE,
3585 EL_GATE_3_GRAY_ACTIVE,
3586 EL_GATE_4_GRAY_ACTIVE,
3595 EL_EM_GATE_1_GRAY_ACTIVE,
3596 EL_EM_GATE_2_GRAY_ACTIVE,
3597 EL_EM_GATE_3_GRAY_ACTIVE,
3598 EL_EM_GATE_4_GRAY_ACTIVE,
3605 EL_EXPANDABLE_WALL_HORIZONTAL,
3606 EL_EXPANDABLE_WALL_VERTICAL,
3607 EL_EXPANDABLE_WALL_ANY,
3608 EL_EXPANDABLE_WALL_GROWING,
3609 EL_BD_EXPANDABLE_WALL,
3616 EL_SP_HARDWARE_GRAY,
3617 EL_SP_HARDWARE_GREEN,
3618 EL_SP_HARDWARE_BLUE,
3620 EL_SP_HARDWARE_YELLOW,
3621 EL_SP_HARDWARE_BASE_1,
3622 EL_SP_HARDWARE_BASE_2,
3623 EL_SP_HARDWARE_BASE_3,
3624 EL_SP_HARDWARE_BASE_4,
3625 EL_SP_HARDWARE_BASE_5,
3626 EL_SP_HARDWARE_BASE_6,
3628 EL_SP_TERMINAL_ACTIVE,
3631 EL_INVISIBLE_STEELWALL,
3632 EL_INVISIBLE_STEELWALL_ACTIVE,
3634 EL_INVISIBLE_WALL_ACTIVE,
3635 EL_STEELWALL_SLIPPERY,
3652 static int ep_historic_solid[] =
3656 EL_EXPANDABLE_WALL_HORIZONTAL,
3657 EL_EXPANDABLE_WALL_VERTICAL,
3658 EL_EXPANDABLE_WALL_ANY,
3659 EL_BD_EXPANDABLE_WALL,
3672 EL_QUICKSAND_FILLING,
3673 EL_QUICKSAND_EMPTYING,
3675 EL_MAGIC_WALL_ACTIVE,
3676 EL_MAGIC_WALL_EMPTYING,
3677 EL_MAGIC_WALL_FILLING,
3681 EL_BD_MAGIC_WALL_ACTIVE,
3682 EL_BD_MAGIC_WALL_EMPTYING,
3683 EL_BD_MAGIC_WALL_FULL,
3684 EL_BD_MAGIC_WALL_FILLING,
3685 EL_BD_MAGIC_WALL_DEAD,
3694 EL_SP_TERMINAL_ACTIVE,
3698 EL_INVISIBLE_WALL_ACTIVE,
3699 EL_SWITCHGATE_SWITCH_UP,
3700 EL_SWITCHGATE_SWITCH_DOWN,
3702 EL_TIMEGATE_SWITCH_ACTIVE,
3714 // the following elements are a direct copy of "indestructible" elements,
3715 // except "EL_ACID", which is "indestructible", but not "solid"!
3720 EL_ACID_POOL_TOPLEFT,
3721 EL_ACID_POOL_TOPRIGHT,
3722 EL_ACID_POOL_BOTTOMLEFT,
3723 EL_ACID_POOL_BOTTOM,
3724 EL_ACID_POOL_BOTTOMRIGHT,
3725 EL_SP_HARDWARE_GRAY,
3726 EL_SP_HARDWARE_GREEN,
3727 EL_SP_HARDWARE_BLUE,
3729 EL_SP_HARDWARE_YELLOW,
3730 EL_SP_HARDWARE_BASE_1,
3731 EL_SP_HARDWARE_BASE_2,
3732 EL_SP_HARDWARE_BASE_3,
3733 EL_SP_HARDWARE_BASE_4,
3734 EL_SP_HARDWARE_BASE_5,
3735 EL_SP_HARDWARE_BASE_6,
3736 EL_INVISIBLE_STEELWALL,
3737 EL_INVISIBLE_STEELWALL_ACTIVE,
3738 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3739 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3740 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3741 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3742 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3743 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3744 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3745 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3746 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3747 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3748 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3749 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3751 EL_LIGHT_SWITCH_ACTIVE,
3752 EL_SIGN_EXCLAMATION,
3753 EL_SIGN_RADIOACTIVITY,
3760 EL_SIGN_ENTRY_FORBIDDEN,
3761 EL_SIGN_EMERGENCY_EXIT,
3769 EL_STEEL_EXIT_CLOSED,
3771 EL_STEEL_EXIT_OPENING,
3772 EL_STEEL_EXIT_CLOSING,
3773 EL_EM_STEEL_EXIT_CLOSED,
3774 EL_EM_STEEL_EXIT_OPEN,
3775 EL_EM_STEEL_EXIT_OPENING,
3776 EL_EM_STEEL_EXIT_CLOSING,
3777 EL_DC_STEELWALL_1_LEFT,
3778 EL_DC_STEELWALL_1_RIGHT,
3779 EL_DC_STEELWALL_1_TOP,
3780 EL_DC_STEELWALL_1_BOTTOM,
3781 EL_DC_STEELWALL_1_HORIZONTAL,
3782 EL_DC_STEELWALL_1_VERTICAL,
3783 EL_DC_STEELWALL_1_TOPLEFT,
3784 EL_DC_STEELWALL_1_TOPRIGHT,
3785 EL_DC_STEELWALL_1_BOTTOMLEFT,
3786 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3787 EL_DC_STEELWALL_1_TOPLEFT_2,
3788 EL_DC_STEELWALL_1_TOPRIGHT_2,
3789 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3790 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3791 EL_DC_STEELWALL_2_LEFT,
3792 EL_DC_STEELWALL_2_RIGHT,
3793 EL_DC_STEELWALL_2_TOP,
3794 EL_DC_STEELWALL_2_BOTTOM,
3795 EL_DC_STEELWALL_2_HORIZONTAL,
3796 EL_DC_STEELWALL_2_VERTICAL,
3797 EL_DC_STEELWALL_2_MIDDLE,
3798 EL_DC_STEELWALL_2_SINGLE,
3799 EL_STEELWALL_SLIPPERY,
3813 EL_GATE_1_GRAY_ACTIVE,
3814 EL_GATE_2_GRAY_ACTIVE,
3815 EL_GATE_3_GRAY_ACTIVE,
3816 EL_GATE_4_GRAY_ACTIVE,
3825 EL_EM_GATE_1_GRAY_ACTIVE,
3826 EL_EM_GATE_2_GRAY_ACTIVE,
3827 EL_EM_GATE_3_GRAY_ACTIVE,
3828 EL_EM_GATE_4_GRAY_ACTIVE,
3837 EL_EMC_GATE_5_GRAY_ACTIVE,
3838 EL_EMC_GATE_6_GRAY_ACTIVE,
3839 EL_EMC_GATE_7_GRAY_ACTIVE,
3840 EL_EMC_GATE_8_GRAY_ACTIVE,
3842 EL_DC_GATE_WHITE_GRAY,
3843 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3844 EL_DC_GATE_FAKE_GRAY,
3846 EL_SWITCHGATE_OPENING,
3847 EL_SWITCHGATE_CLOSED,
3848 EL_SWITCHGATE_CLOSING,
3849 EL_DC_SWITCHGATE_SWITCH_UP,
3850 EL_DC_SWITCHGATE_SWITCH_DOWN,
3852 EL_TIMEGATE_OPENING,
3854 EL_TIMEGATE_CLOSING,
3855 EL_DC_TIMEGATE_SWITCH,
3856 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3860 EL_TUBE_VERTICAL_LEFT,
3861 EL_TUBE_VERTICAL_RIGHT,
3862 EL_TUBE_HORIZONTAL_UP,
3863 EL_TUBE_HORIZONTAL_DOWN,
3868 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3869 EL_EXPANDABLE_STEELWALL_VERTICAL,
3870 EL_EXPANDABLE_STEELWALL_ANY,
3875 static int ep_classic_enemy[] =
3892 static int ep_belt[] =
3894 EL_CONVEYOR_BELT_1_LEFT,
3895 EL_CONVEYOR_BELT_1_MIDDLE,
3896 EL_CONVEYOR_BELT_1_RIGHT,
3897 EL_CONVEYOR_BELT_2_LEFT,
3898 EL_CONVEYOR_BELT_2_MIDDLE,
3899 EL_CONVEYOR_BELT_2_RIGHT,
3900 EL_CONVEYOR_BELT_3_LEFT,
3901 EL_CONVEYOR_BELT_3_MIDDLE,
3902 EL_CONVEYOR_BELT_3_RIGHT,
3903 EL_CONVEYOR_BELT_4_LEFT,
3904 EL_CONVEYOR_BELT_4_MIDDLE,
3905 EL_CONVEYOR_BELT_4_RIGHT,
3910 static int ep_belt_active[] =
3912 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3913 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3914 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3915 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3916 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3917 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3918 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3919 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3920 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3921 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3922 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3923 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3928 static int ep_belt_switch[] =
3930 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3931 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3932 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3933 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3934 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3935 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3936 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3937 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3938 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3939 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3940 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3941 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3946 static int ep_tube[] =
3953 EL_TUBE_HORIZONTAL_UP,
3954 EL_TUBE_HORIZONTAL_DOWN,
3956 EL_TUBE_VERTICAL_LEFT,
3957 EL_TUBE_VERTICAL_RIGHT,
3963 static int ep_acid_pool[] =
3965 EL_ACID_POOL_TOPLEFT,
3966 EL_ACID_POOL_TOPRIGHT,
3967 EL_ACID_POOL_BOTTOMLEFT,
3968 EL_ACID_POOL_BOTTOM,
3969 EL_ACID_POOL_BOTTOMRIGHT,
3974 static int ep_keygate[] =
3984 EL_GATE_1_GRAY_ACTIVE,
3985 EL_GATE_2_GRAY_ACTIVE,
3986 EL_GATE_3_GRAY_ACTIVE,
3987 EL_GATE_4_GRAY_ACTIVE,
3996 EL_EM_GATE_1_GRAY_ACTIVE,
3997 EL_EM_GATE_2_GRAY_ACTIVE,
3998 EL_EM_GATE_3_GRAY_ACTIVE,
3999 EL_EM_GATE_4_GRAY_ACTIVE,
4008 EL_EMC_GATE_5_GRAY_ACTIVE,
4009 EL_EMC_GATE_6_GRAY_ACTIVE,
4010 EL_EMC_GATE_7_GRAY_ACTIVE,
4011 EL_EMC_GATE_8_GRAY_ACTIVE,
4013 EL_DC_GATE_WHITE_GRAY,
4014 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4019 static int ep_amoeboid[] =
4031 static int ep_amoebalive[] =
4042 static int ep_has_editor_content[] =
4048 EL_SOKOBAN_FIELD_PLAYER,
4065 static int ep_can_turn_each_move[] =
4067 // !!! do something with this one !!!
4071 static int ep_can_grow[] =
4085 static int ep_active_bomb[] =
4088 EL_EM_DYNAMITE_ACTIVE,
4089 EL_DYNABOMB_PLAYER_1_ACTIVE,
4090 EL_DYNABOMB_PLAYER_2_ACTIVE,
4091 EL_DYNABOMB_PLAYER_3_ACTIVE,
4092 EL_DYNABOMB_PLAYER_4_ACTIVE,
4093 EL_SP_DISK_RED_ACTIVE,
4098 static int ep_inactive[] =
4108 EL_QUICKSAND_FAST_EMPTY,
4131 EL_GATE_1_GRAY_ACTIVE,
4132 EL_GATE_2_GRAY_ACTIVE,
4133 EL_GATE_3_GRAY_ACTIVE,
4134 EL_GATE_4_GRAY_ACTIVE,
4143 EL_EM_GATE_1_GRAY_ACTIVE,
4144 EL_EM_GATE_2_GRAY_ACTIVE,
4145 EL_EM_GATE_3_GRAY_ACTIVE,
4146 EL_EM_GATE_4_GRAY_ACTIVE,
4155 EL_EMC_GATE_5_GRAY_ACTIVE,
4156 EL_EMC_GATE_6_GRAY_ACTIVE,
4157 EL_EMC_GATE_7_GRAY_ACTIVE,
4158 EL_EMC_GATE_8_GRAY_ACTIVE,
4160 EL_DC_GATE_WHITE_GRAY,
4161 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4162 EL_DC_GATE_FAKE_GRAY,
4165 EL_INVISIBLE_STEELWALL,
4173 EL_WALL_EMERALD_YELLOW,
4174 EL_DYNABOMB_INCREASE_NUMBER,
4175 EL_DYNABOMB_INCREASE_SIZE,
4176 EL_DYNABOMB_INCREASE_POWER,
4180 EL_SOKOBAN_FIELD_EMPTY,
4181 EL_SOKOBAN_FIELD_FULL,
4182 EL_WALL_EMERALD_RED,
4183 EL_WALL_EMERALD_PURPLE,
4184 EL_ACID_POOL_TOPLEFT,
4185 EL_ACID_POOL_TOPRIGHT,
4186 EL_ACID_POOL_BOTTOMLEFT,
4187 EL_ACID_POOL_BOTTOM,
4188 EL_ACID_POOL_BOTTOMRIGHT,
4192 EL_BD_MAGIC_WALL_DEAD,
4194 EL_DC_MAGIC_WALL_DEAD,
4195 EL_AMOEBA_TO_DIAMOND,
4203 EL_SP_GRAVITY_PORT_RIGHT,
4204 EL_SP_GRAVITY_PORT_DOWN,
4205 EL_SP_GRAVITY_PORT_LEFT,
4206 EL_SP_GRAVITY_PORT_UP,
4207 EL_SP_PORT_HORIZONTAL,
4208 EL_SP_PORT_VERTICAL,
4219 EL_SP_HARDWARE_GRAY,
4220 EL_SP_HARDWARE_GREEN,
4221 EL_SP_HARDWARE_BLUE,
4223 EL_SP_HARDWARE_YELLOW,
4224 EL_SP_HARDWARE_BASE_1,
4225 EL_SP_HARDWARE_BASE_2,
4226 EL_SP_HARDWARE_BASE_3,
4227 EL_SP_HARDWARE_BASE_4,
4228 EL_SP_HARDWARE_BASE_5,
4229 EL_SP_HARDWARE_BASE_6,
4230 EL_SP_GRAVITY_ON_PORT_LEFT,
4231 EL_SP_GRAVITY_ON_PORT_RIGHT,
4232 EL_SP_GRAVITY_ON_PORT_UP,
4233 EL_SP_GRAVITY_ON_PORT_DOWN,
4234 EL_SP_GRAVITY_OFF_PORT_LEFT,
4235 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4236 EL_SP_GRAVITY_OFF_PORT_UP,
4237 EL_SP_GRAVITY_OFF_PORT_DOWN,
4238 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4239 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4240 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4241 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4242 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4243 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4244 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4245 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4246 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4247 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4248 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4249 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4250 EL_SIGN_EXCLAMATION,
4251 EL_SIGN_RADIOACTIVITY,
4258 EL_SIGN_ENTRY_FORBIDDEN,
4259 EL_SIGN_EMERGENCY_EXIT,
4267 EL_DC_STEELWALL_1_LEFT,
4268 EL_DC_STEELWALL_1_RIGHT,
4269 EL_DC_STEELWALL_1_TOP,
4270 EL_DC_STEELWALL_1_BOTTOM,
4271 EL_DC_STEELWALL_1_HORIZONTAL,
4272 EL_DC_STEELWALL_1_VERTICAL,
4273 EL_DC_STEELWALL_1_TOPLEFT,
4274 EL_DC_STEELWALL_1_TOPRIGHT,
4275 EL_DC_STEELWALL_1_BOTTOMLEFT,
4276 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4277 EL_DC_STEELWALL_1_TOPLEFT_2,
4278 EL_DC_STEELWALL_1_TOPRIGHT_2,
4279 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4280 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4281 EL_DC_STEELWALL_2_LEFT,
4282 EL_DC_STEELWALL_2_RIGHT,
4283 EL_DC_STEELWALL_2_TOP,
4284 EL_DC_STEELWALL_2_BOTTOM,
4285 EL_DC_STEELWALL_2_HORIZONTAL,
4286 EL_DC_STEELWALL_2_VERTICAL,
4287 EL_DC_STEELWALL_2_MIDDLE,
4288 EL_DC_STEELWALL_2_SINGLE,
4289 EL_STEELWALL_SLIPPERY,
4294 EL_EMC_WALL_SLIPPERY_1,
4295 EL_EMC_WALL_SLIPPERY_2,
4296 EL_EMC_WALL_SLIPPERY_3,
4297 EL_EMC_WALL_SLIPPERY_4,
4318 static int ep_em_slippery_wall[] =
4323 static int ep_gfx_crumbled[] =
4334 static int ep_editor_cascade_active[] =
4336 EL_INTERNAL_CASCADE_BD_ACTIVE,
4337 EL_INTERNAL_CASCADE_EM_ACTIVE,
4338 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4339 EL_INTERNAL_CASCADE_RND_ACTIVE,
4340 EL_INTERNAL_CASCADE_SB_ACTIVE,
4341 EL_INTERNAL_CASCADE_SP_ACTIVE,
4342 EL_INTERNAL_CASCADE_DC_ACTIVE,
4343 EL_INTERNAL_CASCADE_DX_ACTIVE,
4344 EL_INTERNAL_CASCADE_MM_ACTIVE,
4345 EL_INTERNAL_CASCADE_DF_ACTIVE,
4346 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4347 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4348 EL_INTERNAL_CASCADE_CE_ACTIVE,
4349 EL_INTERNAL_CASCADE_GE_ACTIVE,
4350 EL_INTERNAL_CASCADE_REF_ACTIVE,
4351 EL_INTERNAL_CASCADE_USER_ACTIVE,
4352 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4357 static int ep_editor_cascade_inactive[] =
4359 EL_INTERNAL_CASCADE_BD,
4360 EL_INTERNAL_CASCADE_EM,
4361 EL_INTERNAL_CASCADE_EMC,
4362 EL_INTERNAL_CASCADE_RND,
4363 EL_INTERNAL_CASCADE_SB,
4364 EL_INTERNAL_CASCADE_SP,
4365 EL_INTERNAL_CASCADE_DC,
4366 EL_INTERNAL_CASCADE_DX,
4367 EL_INTERNAL_CASCADE_MM,
4368 EL_INTERNAL_CASCADE_DF,
4369 EL_INTERNAL_CASCADE_CHARS,
4370 EL_INTERNAL_CASCADE_STEEL_CHARS,
4371 EL_INTERNAL_CASCADE_CE,
4372 EL_INTERNAL_CASCADE_GE,
4373 EL_INTERNAL_CASCADE_REF,
4374 EL_INTERNAL_CASCADE_USER,
4375 EL_INTERNAL_CASCADE_DYNAMIC,
4380 static int ep_obsolete[] =
4384 EL_EM_KEY_1_FILE_OBSOLETE,
4385 EL_EM_KEY_2_FILE_OBSOLETE,
4386 EL_EM_KEY_3_FILE_OBSOLETE,
4387 EL_EM_KEY_4_FILE_OBSOLETE,
4388 EL_ENVELOPE_OBSOLETE,
4397 } element_properties[] =
4399 { ep_diggable, EP_DIGGABLE },
4400 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4401 { ep_dont_run_into, EP_DONT_RUN_INTO },
4402 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4403 { ep_dont_touch, EP_DONT_TOUCH },
4404 { ep_indestructible, EP_INDESTRUCTIBLE },
4405 { ep_slippery, EP_SLIPPERY },
4406 { ep_can_change, EP_CAN_CHANGE },
4407 { ep_can_move, EP_CAN_MOVE },
4408 { ep_can_fall, EP_CAN_FALL },
4409 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4410 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4411 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4412 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4413 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4414 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4415 { ep_walkable_over, EP_WALKABLE_OVER },
4416 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4417 { ep_walkable_under, EP_WALKABLE_UNDER },
4418 { ep_passable_over, EP_PASSABLE_OVER },
4419 { ep_passable_inside, EP_PASSABLE_INSIDE },
4420 { ep_passable_under, EP_PASSABLE_UNDER },
4421 { ep_droppable, EP_DROPPABLE },
4422 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4423 { ep_pushable, EP_PUSHABLE },
4424 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4425 { ep_protected, EP_PROTECTED },
4426 { ep_throwable, EP_THROWABLE },
4427 { ep_can_explode, EP_CAN_EXPLODE },
4428 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4430 { ep_player, EP_PLAYER },
4431 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4432 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4433 { ep_switchable, EP_SWITCHABLE },
4434 { ep_bd_element, EP_BD_ELEMENT },
4435 { ep_sp_element, EP_SP_ELEMENT },
4436 { ep_sb_element, EP_SB_ELEMENT },
4438 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4439 { ep_food_penguin, EP_FOOD_PENGUIN },
4440 { ep_food_pig, EP_FOOD_PIG },
4441 { ep_historic_wall, EP_HISTORIC_WALL },
4442 { ep_historic_solid, EP_HISTORIC_SOLID },
4443 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4444 { ep_belt, EP_BELT },
4445 { ep_belt_active, EP_BELT_ACTIVE },
4446 { ep_belt_switch, EP_BELT_SWITCH },
4447 { ep_tube, EP_TUBE },
4448 { ep_acid_pool, EP_ACID_POOL },
4449 { ep_keygate, EP_KEYGATE },
4450 { ep_amoeboid, EP_AMOEBOID },
4451 { ep_amoebalive, EP_AMOEBALIVE },
4452 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4453 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4454 { ep_can_grow, EP_CAN_GROW },
4455 { ep_active_bomb, EP_ACTIVE_BOMB },
4456 { ep_inactive, EP_INACTIVE },
4458 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4460 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4462 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4463 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4465 { ep_obsolete, EP_OBSOLETE },
4472 // always start with reliable default values (element has no properties)
4473 // (but never initialize clipboard elements after the very first time)
4474 // (to be able to use clipboard elements between several levels)
4475 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4476 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4477 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4478 SET_PROPERTY(i, j, FALSE);
4480 // set all base element properties from above array definitions
4481 for (i = 0; element_properties[i].elements != NULL; i++)
4482 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4483 SET_PROPERTY((element_properties[i].elements)[j],
4484 element_properties[i].property, TRUE);
4486 // copy properties to some elements that are only stored in level file
4487 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4488 for (j = 0; copy_properties[j][0] != -1; j++)
4489 if (HAS_PROPERTY(copy_properties[j][0], i))
4490 for (k = 1; k <= 4; k++)
4491 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4493 // set static element properties that are not listed in array definitions
4494 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4495 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4497 clipboard_elements_initialized = TRUE;
4500 void InitElementPropertiesEngine(int engine_version)
4502 static int no_wall_properties[] =
4505 EP_COLLECTIBLE_ONLY,
4507 EP_DONT_COLLIDE_WITH,
4510 EP_CAN_SMASH_PLAYER,
4511 EP_CAN_SMASH_ENEMIES,
4512 EP_CAN_SMASH_EVERYTHING,
4517 EP_FOOD_DARK_YAMYAM,
4533 /* important: after initialization in InitElementPropertiesStatic(), the
4534 elements are not again initialized to a default value; therefore all
4535 changes have to make sure that they leave the element with a defined
4536 property (which means that conditional property changes must be set to
4537 a reliable default value before) */
4539 // resolve group elements
4540 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4541 ResolveGroupElement(EL_GROUP_START + i);
4543 // set all special, combined or engine dependent element properties
4544 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4546 // do not change (already initialized) clipboard elements here
4547 if (IS_CLIPBOARD_ELEMENT(i))
4550 // ---------- INACTIVE ----------------------------------------------------
4551 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4552 i <= EL_CHAR_END) ||
4553 (i >= EL_STEEL_CHAR_START &&
4554 i <= EL_STEEL_CHAR_END)));
4556 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4557 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4558 IS_WALKABLE_INSIDE(i) ||
4559 IS_WALKABLE_UNDER(i)));
4561 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4562 IS_PASSABLE_INSIDE(i) ||
4563 IS_PASSABLE_UNDER(i)));
4565 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4566 IS_PASSABLE_OVER(i)));
4568 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4569 IS_PASSABLE_INSIDE(i)));
4571 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4572 IS_PASSABLE_UNDER(i)));
4574 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4577 // ---------- COLLECTIBLE -------------------------------------------------
4578 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4582 // ---------- SNAPPABLE ---------------------------------------------------
4583 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4584 IS_COLLECTIBLE(i) ||
4588 // ---------- WALL --------------------------------------------------------
4589 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4591 for (j = 0; no_wall_properties[j] != -1; j++)
4592 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4593 i >= EL_FIRST_RUNTIME_UNREAL)
4594 SET_PROPERTY(i, EP_WALL, FALSE);
4596 if (IS_HISTORIC_WALL(i))
4597 SET_PROPERTY(i, EP_WALL, TRUE);
4599 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4600 if (engine_version < VERSION_IDENT(2,2,0,0))
4601 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4603 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4605 !IS_COLLECTIBLE(i)));
4607 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4608 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4609 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4611 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4614 // ---------- EXPLOSION_PROOF ---------------------------------------------
4616 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4617 else if (engine_version < VERSION_IDENT(2,2,0,0))
4618 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4620 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4624 if (IS_CUSTOM_ELEMENT(i))
4626 // these are additional properties which are initially false when set
4628 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4630 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4631 if (DONT_COLLIDE_WITH(i))
4632 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4634 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4635 if (CAN_SMASH_EVERYTHING(i))
4636 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4637 if (CAN_SMASH_ENEMIES(i))
4638 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4641 // ---------- CAN_SMASH ---------------------------------------------------
4642 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4643 CAN_SMASH_ENEMIES(i) ||
4644 CAN_SMASH_EVERYTHING(i)));
4646 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4647 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4648 EXPLODES_BY_FIRE(i)));
4650 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4651 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4652 EXPLODES_SMASHED(i)));
4654 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4655 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4656 EXPLODES_IMPACT(i)));
4658 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4659 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4661 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4662 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4663 i == EL_BLACK_ORB));
4665 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4666 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4668 IS_CUSTOM_ELEMENT(i)));
4670 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4671 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4672 i == EL_SP_ELECTRON));
4674 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4675 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4676 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4677 getMoveIntoAcidProperty(&level, i));
4679 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4680 if (MAYBE_DONT_COLLIDE_WITH(i))
4681 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4682 getDontCollideWithProperty(&level, i));
4684 // ---------- SP_PORT -----------------------------------------------------
4685 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4686 IS_PASSABLE_INSIDE(i)));
4688 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4689 for (j = 0; j < level.num_android_clone_elements; j++)
4690 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4692 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4694 // ---------- CAN_CHANGE --------------------------------------------------
4695 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4696 for (j = 0; j < element_info[i].num_change_pages; j++)
4697 if (element_info[i].change_page[j].can_change)
4698 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4700 // ---------- HAS_ACTION --------------------------------------------------
4701 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4702 for (j = 0; j < element_info[i].num_change_pages; j++)
4703 if (element_info[i].change_page[j].has_action)
4704 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4706 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4707 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4710 // ---------- GFX_CRUMBLED ------------------------------------------------
4711 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4712 element_info[i].crumbled[ACTION_DEFAULT] !=
4713 element_info[i].graphic[ACTION_DEFAULT]);
4715 // ---------- EDITOR_CASCADE ----------------------------------------------
4716 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4717 IS_EDITOR_CASCADE_INACTIVE(i)));
4720 // dynamically adjust element properties according to game engine version
4722 static int ep_em_slippery_wall[] =
4727 EL_EXPANDABLE_WALL_HORIZONTAL,
4728 EL_EXPANDABLE_WALL_VERTICAL,
4729 EL_EXPANDABLE_WALL_ANY,
4730 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4731 EL_EXPANDABLE_STEELWALL_VERTICAL,
4732 EL_EXPANDABLE_STEELWALL_ANY,
4733 EL_EXPANDABLE_STEELWALL_GROWING,
4737 static int ep_em_explodes_by_fire[] =
4740 EL_EM_DYNAMITE_ACTIVE,
4745 // special EM style gems behaviour
4746 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4747 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4748 level.em_slippery_gems);
4750 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4751 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4752 (level.em_slippery_gems &&
4753 engine_version > VERSION_IDENT(2,0,1,0)));
4755 // special EM style explosion behaviour regarding chain reactions
4756 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4757 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4758 level.em_explodes_by_fire);
4761 // this is needed because some graphics depend on element properties
4762 if (game_status == GAME_MODE_PLAYING)
4763 InitElementGraphicInfo();
4766 void InitElementPropertiesGfxElement(void)
4770 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4772 struct ElementInfo *ei = &element_info[i];
4774 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4778 static void InitGlobal(void)
4783 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4785 // check if element_name_info entry defined for each element in "main.h"
4786 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4787 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4789 element_info[i].token_name = element_name_info[i].token_name;
4790 element_info[i].class_name = element_name_info[i].class_name;
4791 element_info[i].editor_description= element_name_info[i].editor_description;
4794 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4796 // check if global_anim_name_info defined for each entry in "main.h"
4797 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4798 global_anim_name_info[i].token_name == NULL)
4799 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4801 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4804 // create hash from image config list
4805 image_config_hash = newSetupFileHash();
4806 for (i = 0; image_config[i].token != NULL; i++)
4807 setHashEntry(image_config_hash,
4808 image_config[i].token,
4809 image_config[i].value);
4811 // create hash from element token list
4812 element_token_hash = newSetupFileHash();
4813 for (i = 0; element_name_info[i].token_name != NULL; i++)
4814 setHashEntry(element_token_hash,
4815 element_name_info[i].token_name,
4818 // create hash from graphic token list
4819 graphic_token_hash = newSetupFileHash();
4820 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4821 if (strSuffix(image_config[i].value, ".png") ||
4822 strSuffix(image_config[i].value, ".pcx") ||
4823 strSuffix(image_config[i].value, ".wav") ||
4824 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4825 setHashEntry(graphic_token_hash,
4826 image_config[i].token,
4827 int2str(graphic++, 0));
4829 // create hash from font token list
4830 font_token_hash = newSetupFileHash();
4831 for (i = 0; font_info[i].token_name != NULL; i++)
4832 setHashEntry(font_token_hash,
4833 font_info[i].token_name,
4836 // set default filenames for all cloned graphics in static configuration
4837 for (i = 0; image_config[i].token != NULL; i++)
4839 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4841 char *token = image_config[i].token;
4842 char *token_clone_from = getStringCat2(token, ".clone_from");
4843 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4845 if (token_cloned != NULL)
4847 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4849 if (value_cloned != NULL)
4851 // set default filename in static configuration
4852 image_config[i].value = value_cloned;
4854 // set default filename in image config hash
4855 setHashEntry(image_config_hash, token, value_cloned);
4859 free(token_clone_from);
4863 // always start with reliable default values (all elements)
4864 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4865 ActiveElement[i] = i;
4867 // now add all entries that have an active state (active elements)
4868 for (i = 0; element_with_active_state[i].element != -1; i++)
4870 int element = element_with_active_state[i].element;
4871 int element_active = element_with_active_state[i].element_active;
4873 ActiveElement[element] = element_active;
4876 // always start with reliable default values (all buttons)
4877 for (i = 0; i < NUM_IMAGE_FILES; i++)
4878 ActiveButton[i] = i;
4880 // now add all entries that have an active state (active buttons)
4881 for (i = 0; button_with_active_state[i].button != -1; i++)
4883 int button = button_with_active_state[i].button;
4884 int button_active = button_with_active_state[i].button_active;
4886 ActiveButton[button] = button_active;
4889 // always start with reliable default values (all fonts)
4890 for (i = 0; i < NUM_FONTS; i++)
4893 // now add all entries that have an active state (active fonts)
4894 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4896 int font = font_with_active_state[i].font_nr;
4897 int font_active = font_with_active_state[i].font_nr_active;
4899 ActiveFont[font] = font_active;
4902 global.autoplay_leveldir = NULL;
4903 global.convert_leveldir = NULL;
4904 global.create_images_dir = NULL;
4906 global.frames_per_second = 0;
4907 global.show_frames_per_second = FALSE;
4909 global.border_status = GAME_MODE_LOADING;
4910 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4912 global.use_envelope_request = FALSE;
4915 static void Execute_Command(char *command)
4919 if (strEqual(command, "print graphicsinfo.conf"))
4921 Print("# You can configure additional/alternative image files here.\n");
4922 Print("# (The entries below are default and therefore commented out.)\n");
4924 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4926 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4929 for (i = 0; image_config[i].token != NULL; i++)
4930 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4931 image_config[i].value));
4935 else if (strEqual(command, "print soundsinfo.conf"))
4937 Print("# You can configure additional/alternative sound files here.\n");
4938 Print("# (The entries below are default and therefore commented out.)\n");
4940 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4942 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4945 for (i = 0; sound_config[i].token != NULL; i++)
4946 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4947 sound_config[i].value));
4951 else if (strEqual(command, "print musicinfo.conf"))
4953 Print("# You can configure additional/alternative music files here.\n");
4954 Print("# (The entries below are default and therefore commented out.)\n");
4956 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4958 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4961 for (i = 0; music_config[i].token != NULL; i++)
4962 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4963 music_config[i].value));
4967 else if (strEqual(command, "print editorsetup.conf"))
4969 Print("# You can configure your personal editor element list here.\n");
4970 Print("# (The entries below are default and therefore commented out.)\n");
4973 // this is needed to be able to check element list for cascade elements
4974 InitElementPropertiesStatic();
4975 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4977 PrintEditorElementList();
4981 else if (strEqual(command, "print helpanim.conf"))
4983 Print("# You can configure different element help animations here.\n");
4984 Print("# (The entries below are default and therefore commented out.)\n");
4987 for (i = 0; helpanim_config[i].token != NULL; i++)
4989 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4990 helpanim_config[i].value));
4992 if (strEqual(helpanim_config[i].token, "end"))
4998 else if (strEqual(command, "print helptext.conf"))
5000 Print("# You can configure different element help text here.\n");
5001 Print("# (The entries below are default and therefore commented out.)\n");
5004 for (i = 0; helptext_config[i].token != NULL; i++)
5005 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5006 helptext_config[i].value));
5010 else if (strPrefix(command, "dump level "))
5012 char *filename = &command[11];
5014 if (!fileExists(filename))
5015 Error(ERR_EXIT, "cannot open file '%s'", filename);
5017 LoadLevelFromFilename(&level, filename);
5022 else if (strPrefix(command, "dump tape "))
5024 char *filename = &command[10];
5026 if (!fileExists(filename))
5027 Error(ERR_EXIT, "cannot open file '%s'", filename);
5029 LoadTapeFromFilename(filename);
5034 else if (strPrefix(command, "autotest ") ||
5035 strPrefix(command, "autoplay ") ||
5036 strPrefix(command, "autoffwd ") ||
5037 strPrefix(command, "autowarp "))
5039 char *str_ptr = getStringCopy(&command[9]); // read command parameters
5041 global.autoplay_mode =
5042 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5043 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5044 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5045 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5046 AUTOPLAY_MODE_NONE);
5048 while (*str_ptr != '\0') // continue parsing string
5050 // cut leading whitespace from string, replace it by string terminator
5051 while (*str_ptr == ' ' || *str_ptr == '\t')
5054 if (*str_ptr == '\0') // end of string reached
5057 if (global.autoplay_leveldir == NULL) // read level set string
5059 global.autoplay_leveldir = str_ptr;
5060 global.autoplay_all = TRUE; // default: play all tapes
5062 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5063 global.autoplay_level[i] = FALSE;
5065 else // read level number string
5067 int level_nr = atoi(str_ptr); // get level_nr value
5069 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5070 global.autoplay_level[level_nr] = TRUE;
5072 global.autoplay_all = FALSE;
5075 // advance string pointer to the next whitespace (or end of string)
5076 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5080 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5081 program.headless = TRUE;
5083 else if (strPrefix(command, "convert "))
5085 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5086 char *str_ptr = strchr(str_copy, ' ');
5088 global.convert_leveldir = str_copy;
5089 global.convert_level_nr = -1;
5091 if (str_ptr != NULL) // level number follows
5093 *str_ptr++ = '\0'; // terminate leveldir string
5094 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5097 program.headless = TRUE;
5099 else if (strPrefix(command, "create images "))
5101 global.create_images_dir = getStringCopy(&command[14]);
5103 if (access(global.create_images_dir, W_OK) != 0)
5104 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5105 global.create_images_dir);
5107 else if (strPrefix(command, "create CE image "))
5109 CreateCustomElementImages(&command[16]);
5115 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5118 // disable networking if any valid command was recognized
5119 options.network = setup.network_mode = FALSE;
5122 static void InitSetup(void)
5124 LoadSetup(); // global setup info
5125 LoadSetup_AutoSetup(); // global auto setup info
5127 // set some options from setup file
5129 if (setup.options.verbose)
5130 options.verbose = TRUE;
5132 if (setup.debug.show_frames_per_second)
5133 global.show_frames_per_second = TRUE;
5136 static void InitGameInfo(void)
5138 game.restart_level = FALSE;
5139 game.restart_game_message = NULL;
5140 game.request_active = FALSE;
5143 static void InitPlayerInfo(void)
5147 // choose default local player
5148 local_player = &stored_player[0];
5150 for (i = 0; i < MAX_PLAYERS; i++)
5152 stored_player[i].connected_locally = FALSE;
5153 stored_player[i].connected_network = FALSE;
5156 local_player->connected_locally = TRUE;
5159 static void InitArtworkInfo(void)
5164 static char *get_string_in_brackets(char *string)
5166 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5168 sprintf(string_in_brackets, "[%s]", string);
5170 return string_in_brackets;
5173 static char *get_level_id_suffix(int id_nr)
5175 char *id_suffix = checked_malloc(1 + 3 + 1);
5177 if (id_nr < 0 || id_nr > 999)
5180 sprintf(id_suffix, ".%03d", id_nr);
5185 static void InitArtworkConfig(void)
5187 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5189 NUM_GLOBAL_ANIM_TOKENS + 1];
5190 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5191 NUM_GLOBAL_ANIM_TOKENS + 1];
5192 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5193 NUM_GLOBAL_ANIM_TOKENS + 1];
5194 static char *action_id_suffix[NUM_ACTIONS + 1];
5195 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5196 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5197 static char *level_id_suffix[MAX_LEVELS + 1];
5198 static char *dummy[1] = { NULL };
5199 static char *ignore_generic_tokens[] =
5204 "program_copyright",
5209 static char **ignore_image_tokens;
5210 static char **ignore_sound_tokens;
5211 static char **ignore_music_tokens;
5212 int num_ignore_generic_tokens;
5213 int num_ignore_image_tokens;
5214 int num_ignore_sound_tokens;
5215 int num_ignore_music_tokens;
5218 // dynamically determine list of generic tokens to be ignored
5219 num_ignore_generic_tokens = 0;
5220 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5221 num_ignore_generic_tokens++;
5223 // dynamically determine list of image tokens to be ignored
5224 num_ignore_image_tokens = num_ignore_generic_tokens;
5225 for (i = 0; image_config_vars[i].token != NULL; i++)
5226 num_ignore_image_tokens++;
5227 ignore_image_tokens =
5228 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5229 for (i = 0; i < num_ignore_generic_tokens; i++)
5230 ignore_image_tokens[i] = ignore_generic_tokens[i];
5231 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5232 ignore_image_tokens[num_ignore_generic_tokens + i] =
5233 image_config_vars[i].token;
5234 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5236 // dynamically determine list of sound tokens to be ignored
5237 num_ignore_sound_tokens = num_ignore_generic_tokens;
5238 ignore_sound_tokens =
5239 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5240 for (i = 0; i < num_ignore_generic_tokens; i++)
5241 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5242 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5244 // dynamically determine list of music tokens to be ignored
5245 num_ignore_music_tokens = num_ignore_generic_tokens;
5246 ignore_music_tokens =
5247 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5248 for (i = 0; i < num_ignore_generic_tokens; i++)
5249 ignore_music_tokens[i] = ignore_generic_tokens[i];
5250 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5252 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5253 image_id_prefix[i] = element_info[i].token_name;
5254 for (i = 0; i < NUM_FONTS; i++)
5255 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5256 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5257 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5258 global_anim_info[i].token_name;
5259 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5261 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5262 sound_id_prefix[i] = element_info[i].token_name;
5263 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5264 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5265 get_string_in_brackets(element_info[i].class_name);
5266 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5267 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5268 global_anim_info[i].token_name;
5269 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5271 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5272 music_id_prefix[i] = music_prefix_info[i].prefix;
5273 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5274 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5275 global_anim_info[i].token_name;
5276 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5278 for (i = 0; i < NUM_ACTIONS; i++)
5279 action_id_suffix[i] = element_action_info[i].suffix;
5280 action_id_suffix[NUM_ACTIONS] = NULL;
5282 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5283 direction_id_suffix[i] = element_direction_info[i].suffix;
5284 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5286 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5287 special_id_suffix[i] = special_suffix_info[i].suffix;
5288 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5290 for (i = 0; i < MAX_LEVELS; i++)
5291 level_id_suffix[i] = get_level_id_suffix(i);
5292 level_id_suffix[MAX_LEVELS] = NULL;
5294 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5295 image_id_prefix, action_id_suffix, direction_id_suffix,
5296 special_id_suffix, ignore_image_tokens);
5297 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5298 sound_id_prefix, action_id_suffix, dummy,
5299 special_id_suffix, ignore_sound_tokens);
5300 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5301 music_id_prefix, action_id_suffix, special_id_suffix,
5302 level_id_suffix, ignore_music_tokens);
5305 static void InitMixer(void)
5312 static void InitVideoOverlay(void)
5314 // if virtual buttons are not loaded from setup file, repeat initializing
5315 // virtual buttons grid with default values now that video is initialized
5316 if (!setup.touch.grid_initialized)
5319 InitTileCursorInfo();
5323 void InitGfxBuffers(void)
5325 static int win_xsize_last = -1;
5326 static int win_ysize_last = -1;
5328 // create additional image buffers for double-buffering and cross-fading
5330 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5332 // used to temporarily store the backbuffer -- only re-create if changed
5333 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5334 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5336 win_xsize_last = WIN_XSIZE;
5337 win_ysize_last = WIN_YSIZE;
5340 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5341 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5342 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5343 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5345 // initialize screen properties
5346 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5347 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5349 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5350 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5351 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5352 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5353 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5354 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5356 // required if door size definitions have changed
5357 InitGraphicCompatibilityInfo_Doors();
5359 InitGfxBuffers_EM();
5360 InitGfxBuffers_SP();
5363 static void InitGfx(void)
5365 struct GraphicInfo *graphic_info_last = graphic_info;
5366 char *filename_font_initial = NULL;
5367 char *filename_anim_initial = NULL;
5368 Bitmap *bitmap_font_initial = NULL;
5371 // determine settings for initial font (for displaying startup messages)
5372 for (i = 0; image_config[i].token != NULL; i++)
5374 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5376 char font_token[128];
5379 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5380 len_font_token = strlen(font_token);
5382 if (strEqual(image_config[i].token, font_token))
5383 filename_font_initial = image_config[i].value;
5384 else if (strlen(image_config[i].token) > len_font_token &&
5385 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5387 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5388 font_initial[j].src_x = atoi(image_config[i].value);
5389 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5390 font_initial[j].src_y = atoi(image_config[i].value);
5391 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5392 font_initial[j].width = atoi(image_config[i].value);
5393 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5394 font_initial[j].height = atoi(image_config[i].value);
5399 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5401 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5402 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5405 if (filename_font_initial == NULL) // should not happen
5406 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5409 InitGfxCustomArtworkInfo();
5410 InitGfxOtherSettings();
5412 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5414 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5415 font_initial[j].bitmap = bitmap_font_initial;
5417 InitFontGraphicInfo();
5421 DrawInitText("Loading graphics", 120, FC_GREEN);
5423 // initialize settings for busy animation with default values
5424 int parameter[NUM_GFX_ARGS];
5425 for (i = 0; i < NUM_GFX_ARGS; i++)
5426 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5427 image_config_suffix[i].token,
5428 image_config_suffix[i].type);
5430 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5431 int len_anim_token = strlen(anim_token);
5433 // read settings for busy animation from default custom artwork config
5434 char *gfx_config_filename = getPath3(options.graphics_directory,
5436 GRAPHICSINFO_FILENAME);
5438 if (fileExists(gfx_config_filename))
5440 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5442 if (setup_file_hash)
5444 char *filename = getHashEntry(setup_file_hash, anim_token);
5448 filename_anim_initial = getStringCopy(filename);
5450 for (j = 0; image_config_suffix[j].token != NULL; j++)
5452 int type = image_config_suffix[j].type;
5453 char *suffix = image_config_suffix[j].token;
5454 char *token = getStringCat2(anim_token, suffix);
5455 char *value = getHashEntry(setup_file_hash, token);
5457 checked_free(token);
5460 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5464 freeSetupFileHash(setup_file_hash);
5468 if (filename_anim_initial == NULL)
5470 // read settings for busy animation from static default artwork config
5471 for (i = 0; image_config[i].token != NULL; i++)
5473 if (strEqual(image_config[i].token, anim_token))
5474 filename_anim_initial = getStringCopy(image_config[i].value);
5475 else if (strlen(image_config[i].token) > len_anim_token &&
5476 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5478 for (j = 0; image_config_suffix[j].token != NULL; j++)
5480 if (strEqual(&image_config[i].token[len_anim_token],
5481 image_config_suffix[j].token))
5483 get_graphic_parameter_value(image_config[i].value,
5484 image_config_suffix[j].token,
5485 image_config_suffix[j].type);
5491 if (filename_anim_initial == NULL) // should not happen
5492 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5494 anim_initial.bitmaps =
5495 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5497 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5498 LoadCustomImage(filename_anim_initial);
5500 checked_free(filename_anim_initial);
5502 graphic_info = &anim_initial; // graphic == 0 => anim_initial
5504 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5506 graphic_info = graphic_info_last;
5508 init.busy.width = anim_initial.width;
5509 init.busy.height = anim_initial.height;
5511 InitMenuDesignSettings_Static();
5513 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5514 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5515 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5516 InitGfxDrawTileCursorFunction(DrawTileCursor);
5518 gfx.fade_border_source_status = global.border_status;
5519 gfx.fade_border_target_status = global.border_status;
5520 gfx.masked_border_bitmap_ptr = backbuffer;
5522 // use copy of busy animation to prevent change while reloading artwork
5526 static void InitGfxBackground(void)
5528 fieldbuffer = bitmap_db_field;
5529 SetDrawtoField(DRAW_TO_BACKBUFFER);
5531 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5533 redraw_mask = REDRAW_ALL;
5536 static void InitLevelInfo(void)
5538 LoadLevelInfo(); // global level info
5539 LoadLevelSetup_LastSeries(); // last played series info
5540 LoadLevelSetup_SeriesInfo(); // last played level info
5542 if (global.autoplay_leveldir &&
5543 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5545 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5546 global.autoplay_leveldir);
5547 if (leveldir_current == NULL)
5548 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5551 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5554 static void InitLevelArtworkInfo(void)
5556 LoadLevelArtworkInfo();
5559 static void InitImages(void)
5561 print_timestamp_init("InitImages");
5564 printf("::: leveldir_current->identifier == '%s'\n",
5565 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5566 printf("::: leveldir_current->graphics_path == '%s'\n",
5567 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5568 printf("::: leveldir_current->graphics_set == '%s'\n",
5569 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5570 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5571 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5574 setLevelArtworkDir(artwork.gfx_first);
5577 printf("::: leveldir_current->identifier == '%s'\n",
5578 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5579 printf("::: leveldir_current->graphics_path == '%s'\n",
5580 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5581 printf("::: leveldir_current->graphics_set == '%s'\n",
5582 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5583 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5584 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5588 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5589 leveldir_current->identifier,
5590 artwork.gfx_current_identifier,
5591 artwork.gfx_current->identifier,
5592 leveldir_current->graphics_set,
5593 leveldir_current->graphics_path);
5596 UPDATE_BUSY_STATE();
5598 ReloadCustomImages();
5599 print_timestamp_time("ReloadCustomImages");
5601 UPDATE_BUSY_STATE();
5603 LoadCustomElementDescriptions();
5604 print_timestamp_time("LoadCustomElementDescriptions");
5606 UPDATE_BUSY_STATE();
5608 LoadMenuDesignSettings();
5609 print_timestamp_time("LoadMenuDesignSettings");
5611 UPDATE_BUSY_STATE();
5613 ReinitializeGraphics();
5614 print_timestamp_time("ReinitializeGraphics");
5616 LoadMenuDesignSettings_AfterGraphics();
5617 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5619 UPDATE_BUSY_STATE();
5621 print_timestamp_done("InitImages");
5624 static void InitSound(char *identifier)
5626 print_timestamp_init("InitSound");
5628 if (identifier == NULL)
5629 identifier = artwork.snd_current->identifier;
5631 // set artwork path to send it to the sound server process
5632 setLevelArtworkDir(artwork.snd_first);
5634 InitReloadCustomSounds(identifier);
5635 print_timestamp_time("InitReloadCustomSounds");
5637 ReinitializeSounds();
5638 print_timestamp_time("ReinitializeSounds");
5640 print_timestamp_done("InitSound");
5643 static void InitMusic(char *identifier)
5645 print_timestamp_init("InitMusic");
5647 if (identifier == NULL)
5648 identifier = artwork.mus_current->identifier;
5650 // set artwork path to send it to the sound server process
5651 setLevelArtworkDir(artwork.mus_first);
5653 InitReloadCustomMusic(identifier);
5654 print_timestamp_time("InitReloadCustomMusic");
5656 ReinitializeMusic();
5657 print_timestamp_time("ReinitializeMusic");
5659 print_timestamp_done("InitMusic");
5662 static void InitArtworkDone(void)
5664 if (program.headless)
5667 InitGlobalAnimations();
5670 static void InitNetworkSettings(void)
5672 boolean network_enabled = (options.network || setup.network_mode);
5673 char *network_server = (options.server_host != NULL ? options.server_host :
5674 setup.network_server_hostname);
5676 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5677 network_server = NULL;
5679 InitNetworkInfo(network_enabled,
5683 options.server_port);
5686 void InitNetworkServer(void)
5688 if (!network.enabled || network.connected)
5691 LimitScreenUpdates(FALSE);
5693 if (game_status == GAME_MODE_LOADING)
5696 if (!ConnectToServer(network.server_host, network.server_port))
5698 network.enabled = FALSE;
5700 setup.network_mode = FALSE;
5704 SendToServer_ProtocolVersion();
5705 SendToServer_PlayerName(setup.player_name);
5706 SendToServer_NrWanted(setup.network_player_nr + 1);
5708 network.connected = TRUE;
5711 // short time to recognize result of network initialization
5712 if (game_status == GAME_MODE_LOADING)
5713 Delay_WithScreenUpdates(1000);
5716 static boolean CheckArtworkConfigForCustomElements(char *filename)
5718 SetupFileHash *setup_file_hash;
5719 boolean redefined_ce_found = FALSE;
5721 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5723 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5725 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5727 char *token = HASH_ITERATION_TOKEN(itr);
5729 if (strPrefix(token, "custom_"))
5731 redefined_ce_found = TRUE;
5736 END_HASH_ITERATION(setup_file_hash, itr)
5738 freeSetupFileHash(setup_file_hash);
5741 return redefined_ce_found;
5744 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5746 char *filename_base, *filename_local;
5747 boolean redefined_ce_found = FALSE;
5749 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5752 printf("::: leveldir_current->identifier == '%s'\n",
5753 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5754 printf("::: leveldir_current->graphics_path == '%s'\n",
5755 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5756 printf("::: leveldir_current->graphics_set == '%s'\n",
5757 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5758 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5759 leveldir_current == NULL ? "[NULL]" :
5760 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5763 // first look for special artwork configured in level series config
5764 filename_base = getCustomArtworkLevelConfigFilename(type);
5767 printf("::: filename_base == '%s'\n", filename_base);
5770 if (fileExists(filename_base))
5771 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5773 filename_local = getCustomArtworkConfigFilename(type);
5776 printf("::: filename_local == '%s'\n", filename_local);
5779 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5780 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5783 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5786 return redefined_ce_found;
5789 static void InitOverrideArtwork(void)
5791 boolean redefined_ce_found = FALSE;
5793 // to check if this level set redefines any CEs, do not use overriding
5794 gfx.override_level_graphics = FALSE;
5795 gfx.override_level_sounds = FALSE;
5796 gfx.override_level_music = FALSE;
5798 // now check if this level set has definitions for custom elements
5799 if (setup.override_level_graphics == AUTO ||
5800 setup.override_level_sounds == AUTO ||
5801 setup.override_level_music == AUTO)
5802 redefined_ce_found =
5803 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5804 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5805 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5808 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5811 if (redefined_ce_found)
5813 // this level set has CE definitions: change "AUTO" to "FALSE"
5814 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5815 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5816 gfx.override_level_music = (setup.override_level_music == TRUE);
5820 // this level set has no CE definitions: change "AUTO" to "TRUE"
5821 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5822 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5823 gfx.override_level_music = (setup.override_level_music != FALSE);
5827 printf("::: => %d, %d, %d\n",
5828 gfx.override_level_graphics,
5829 gfx.override_level_sounds,
5830 gfx.override_level_music);
5834 static char *getNewArtworkIdentifier(int type)
5836 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5837 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5838 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5839 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5840 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5841 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5842 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5843 char *leveldir_identifier = leveldir_current->identifier;
5844 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
5845 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5846 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5847 char *artwork_current_identifier;
5848 char *artwork_new_identifier = NULL; // default: nothing has changed
5850 // leveldir_current may be invalid (level group, parent link)
5851 if (!validLevelSeries(leveldir_current))
5854 /* 1st step: determine artwork set to be activated in descending order:
5855 --------------------------------------------------------------------
5856 1. setup artwork (when configured to override everything else)
5857 2. artwork set configured in "levelinfo.conf" of current level set
5858 (artwork in level directory will have priority when loading later)
5859 3. artwork in level directory (stored in artwork sub-directory)
5860 4. setup artwork (currently configured in setup menu) */
5862 if (setup_override_artwork)
5863 artwork_current_identifier = setup_artwork_set;
5864 else if (leveldir_artwork_set != NULL)
5865 artwork_current_identifier = leveldir_artwork_set;
5866 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5867 artwork_current_identifier = leveldir_identifier;
5869 artwork_current_identifier = setup_artwork_set;
5872 /* 2nd step: check if it is really needed to reload artwork set
5873 ------------------------------------------------------------ */
5875 // ---------- reload if level set and also artwork set has changed ----------
5876 if (leveldir_current_identifier[type] != leveldir_identifier &&
5877 (last_has_level_artwork_set[type] || has_level_artwork_set))
5878 artwork_new_identifier = artwork_current_identifier;
5880 leveldir_current_identifier[type] = leveldir_identifier;
5881 last_has_level_artwork_set[type] = has_level_artwork_set;
5883 // ---------- reload if "override artwork" setting has changed --------------
5884 if (last_override_level_artwork[type] != setup_override_artwork)
5885 artwork_new_identifier = artwork_current_identifier;
5887 last_override_level_artwork[type] = setup_override_artwork;
5889 // ---------- reload if current artwork identifier has changed --------------
5890 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5891 artwork_current_identifier))
5892 artwork_new_identifier = artwork_current_identifier;
5894 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5896 // ---------- do not reload directly after starting -------------------------
5897 if (!initialized[type])
5898 artwork_new_identifier = NULL;
5900 initialized[type] = TRUE;
5902 return artwork_new_identifier;
5905 void ReloadCustomArtwork(int force_reload)
5907 int last_game_status = game_status; // save current game status
5908 char *gfx_new_identifier;
5909 char *snd_new_identifier;
5910 char *mus_new_identifier;
5911 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5912 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5913 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5914 boolean reload_needed;
5916 InitOverrideArtwork();
5918 force_reload_gfx |= AdjustGraphicsForEMC();
5920 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5921 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5922 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5924 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5925 snd_new_identifier != NULL || force_reload_snd ||
5926 mus_new_identifier != NULL || force_reload_mus);
5931 print_timestamp_init("ReloadCustomArtwork");
5933 SetGameStatus(GAME_MODE_LOADING);
5935 FadeOut(REDRAW_ALL);
5937 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5938 print_timestamp_time("ClearRectangle");
5942 if (gfx_new_identifier != NULL || force_reload_gfx)
5945 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5946 artwork.gfx_current_identifier,
5948 artwork.gfx_current->identifier,
5949 leveldir_current->graphics_set);
5953 print_timestamp_time("InitImages");
5956 if (snd_new_identifier != NULL || force_reload_snd)
5958 InitSound(snd_new_identifier);
5959 print_timestamp_time("InitSound");
5962 if (mus_new_identifier != NULL || force_reload_mus)
5964 InitMusic(mus_new_identifier);
5965 print_timestamp_time("InitMusic");
5970 SetGameStatus(last_game_status); // restore current game status
5972 init_last = init; // switch to new busy animation
5974 FadeOut(REDRAW_ALL);
5976 RedrawGlobalBorder();
5978 // force redraw of (open or closed) door graphics
5979 SetDoorState(DOOR_OPEN_ALL);
5980 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5982 FadeSetEnterScreen();
5983 FadeSkipNextFadeOut();
5985 print_timestamp_done("ReloadCustomArtwork");
5987 LimitScreenUpdates(FALSE);
5990 void KeyboardAutoRepeatOffUnlessAutoplay(void)
5992 if (global.autoplay_leveldir == NULL)
5993 KeyboardAutoRepeatOff();
5996 void DisplayExitMessage(char *format, va_list ap)
5998 // also check for initialized video (headless flag may be temporarily unset)
5999 if (program.headless || !video.initialized)
6002 // check if draw buffer and fonts for exit message are already available
6003 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6006 int font_1 = FC_RED;
6007 int font_2 = FC_YELLOW;
6008 int font_3 = FC_BLUE;
6009 int font_width = getFontWidth(font_2);
6010 int font_height = getFontHeight(font_2);
6013 int sxsize = WIN_XSIZE - 2 * sx;
6014 int sysize = WIN_YSIZE - 2 * sy;
6015 int line_length = sxsize / font_width;
6016 int max_lines = sysize / font_height;
6017 int num_lines_printed;
6021 gfx.sxsize = sxsize;
6022 gfx.sysize = sysize;
6026 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6028 DrawTextSCentered(sy, font_1, "Fatal error:");
6029 sy += 3 * font_height;;
6032 DrawTextBufferVA(sx, sy, format, ap, font_2,
6033 line_length, line_length, max_lines,
6034 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6035 sy += (num_lines_printed + 3) * font_height;
6037 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6038 sy += 3 * font_height;
6041 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6042 line_length, line_length, max_lines,
6043 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6045 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6047 redraw_mask = REDRAW_ALL;
6049 // force drawing exit message even if screen updates are currently limited
6050 LimitScreenUpdates(FALSE);
6054 // deactivate toons on error message screen
6055 setup.toons = FALSE;
6057 WaitForEventToContinue();
6061 // ============================================================================
6063 // ============================================================================
6067 print_timestamp_init("OpenAll");
6069 SetGameStatus(GAME_MODE_LOADING);
6073 InitGlobal(); // initialize some global variables
6075 print_timestamp_time("[init global stuff]");
6079 print_timestamp_time("[init setup/config stuff (1)]");
6083 if (options.execute_command)
6084 Execute_Command(options.execute_command);
6086 InitNetworkSettings();
6090 if (network.serveronly)
6092 #if defined(PLATFORM_UNIX)
6093 NetworkServer(network.server_port, TRUE);
6095 Error(ERR_WARN, "networking only supported in Unix version");
6098 exit(0); // never reached, server loops forever
6102 print_timestamp_time("[init setup/config stuff (2)]");
6104 print_timestamp_time("[init setup/config stuff (3)]");
6105 InitArtworkInfo(); // needed before loading gfx, sound & music
6106 print_timestamp_time("[init setup/config stuff (4)]");
6107 InitArtworkConfig(); // needed before forking sound child process
6108 print_timestamp_time("[init setup/config stuff (5)]");
6110 print_timestamp_time("[init setup/config stuff (6)]");
6112 InitRND(NEW_RANDOMIZE);
6113 InitSimpleRandom(NEW_RANDOMIZE);
6117 print_timestamp_time("[init setup/config stuff]");
6119 InitVideoDefaults();
6121 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6124 InitEventFilter(FilterMouseMotionEvents);
6126 print_timestamp_time("[init video stuff]");
6128 InitElementPropertiesStatic();
6129 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6130 InitElementPropertiesGfxElement();
6132 print_timestamp_time("[init element properties stuff]");
6136 print_timestamp_time("InitGfx");
6139 print_timestamp_time("InitLevelInfo");
6141 InitLevelArtworkInfo();
6142 print_timestamp_time("InitLevelArtworkInfo");
6144 InitOverrideArtwork(); // needs to know current level directory
6145 print_timestamp_time("InitOverrideArtwork");
6147 InitImages(); // needs to know current level directory
6148 print_timestamp_time("InitImages");
6150 InitSound(NULL); // needs to know current level directory
6151 print_timestamp_time("InitSound");
6153 InitMusic(NULL); // needs to know current level directory
6154 print_timestamp_time("InitMusic");
6158 InitGfxBackground();
6164 if (global.autoplay_leveldir)
6169 else if (global.convert_leveldir)
6174 else if (global.create_images_dir)
6176 CreateLevelSketchImages();
6180 InitNetworkServer();
6182 SetGameStatus(GAME_MODE_MAIN);
6184 FadeSetEnterScreen();
6185 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6186 FadeSkipNextFadeOut();
6188 print_timestamp_time("[post-artwork]");
6190 print_timestamp_done("OpenAll");
6195 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6197 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6198 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6199 #if defined(PLATFORM_ANDROID)
6200 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6201 SDL_AndroidGetInternalStoragePath());
6202 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6203 SDL_AndroidGetExternalStoragePath());
6204 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6205 (SDL_AndroidGetExternalStorageState() &
6206 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6207 SDL_AndroidGetExternalStorageState() &
6208 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6213 void CloseAllAndExit(int exit_value)
6218 CloseAudio(); // called after freeing sounds (needed for SDL)
6226 // set a flag to tell the network server thread to quit and wait for it
6227 // using SDL_WaitThread()
6229 // Code used with SDL 1.2:
6230 // if (network_server) // terminate network server
6231 // SDL_KillThread(server_thread);
6233 CloseVideoDisplay();
6234 ClosePlatformDependentStuff();
6236 if (exit_value != 0 && !options.execute_command)
6238 // fall back to default level set (current set may have caused an error)
6239 SaveLevelSetup_LastSeries_Deactivate();
6241 // tell user where to find error log file which may contain more details
6242 // (error notification now directly displayed on screen inside R'n'D
6243 // NotifyUserAboutErrorFile(); // currently only works for Windows