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);
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 if (game_status != GAME_MODE_LOADING)
103 if (anim_initial.bitmap == NULL || window == NULL)
106 if (!DelayReached(&action_delay, action_delay_value))
109 if (init_last.busy.x == -1)
110 init_last.busy.x = WIN_XSIZE / 2;
111 if (init_last.busy.y == -1)
112 init_last.busy.y = WIN_YSIZE / 2;
114 x = ALIGNED_TEXT_XPOS(&init_last.busy);
115 y = ALIGNED_TEXT_YPOS(&init_last.busy);
117 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
119 if (sync_frame % anim_initial.anim_delay == 0)
123 int width = graphic_info[graphic].width;
124 int height = graphic_info[graphic].height;
125 int frame = getGraphicAnimationFrame(graphic, sync_frame);
127 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
128 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
131 graphic_info = graphic_info_last;
138 FreeLevelEditorGadgets();
147 static boolean gadgets_initialized = FALSE;
149 if (gadgets_initialized)
152 CreateLevelEditorGadgets();
156 CreateScreenGadgets();
158 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
160 gadgets_initialized = TRUE;
163 inline static void InitElementSmallImagesScaledUp(int graphic)
165 struct GraphicInfo *g = &graphic_info[graphic];
167 // create small and game tile sized bitmaps (and scale up, if needed)
168 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
171 void InitElementSmallImages()
173 print_timestamp_init("InitElementSmallImages");
175 static int special_graphics[] =
189 IMG_EDITOR_ELEMENT_BORDER,
190 IMG_EDITOR_ELEMENT_BORDER_INPUT,
191 IMG_EDITOR_CASCADE_LIST,
192 IMG_EDITOR_CASCADE_LIST_ACTIVE,
195 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
196 int num_property_mappings = getImageListPropertyMappingSize();
199 print_timestamp_time("getImageListPropertyMapping/Size");
201 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
202 /* initialize normal element images from static configuration */
203 for (i = 0; element_to_graphic[i].element > -1; i++)
204 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
205 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
207 /* initialize special element images from static configuration */
208 for (i = 0; element_to_special_graphic[i].element > -1; i++)
209 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
210 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
212 /* initialize element images from dynamic configuration */
213 for (i = 0; i < num_property_mappings; i++)
214 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
215 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
216 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
218 /* initialize special non-element images from above list */
219 for (i = 0; special_graphics[i] > -1; i++)
220 InitElementSmallImagesScaledUp(special_graphics[i]);
221 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
223 print_timestamp_done("InitElementSmallImages");
226 inline static void InitScaledImagesScaledUp(int graphic)
228 struct GraphicInfo *g = &graphic_info[graphic];
230 ScaleImage(graphic, g->scale_up_factor);
233 void InitScaledImages()
235 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
236 int num_property_mappings = getImageListPropertyMappingSize();
239 /* scale normal images from static configuration, if not already scaled */
240 for (i = 0; i < NUM_IMAGE_FILES; i++)
241 InitScaledImagesScaledUp(i);
243 /* scale images from dynamic configuration, if not already scaled */
244 for (i = 0; i < num_property_mappings; i++)
245 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
248 void InitBitmapPointers()
250 int num_images = getImageListSize();
253 // standard size bitmap may have changed -- update default bitmap pointer
254 for (i = 0; i < num_images; i++)
255 if (graphic_info[i].bitmaps)
256 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
259 void InitImageTextures()
263 FreeAllImageTextures();
265 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
266 CreateImageTextures(i);
268 for (i = 0; i < MAX_NUM_TOONS; i++)
269 CreateImageTextures(IMG_TOON_1 + i);
271 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
273 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
275 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
277 int graphic = global_anim_info[i].graphic[j][k];
279 if (graphic == IMG_UNDEFINED)
282 CreateImageTextures(graphic);
289 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
290 void SetBitmaps_EM(Bitmap **em_bitmap)
292 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
293 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
298 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
299 void SetBitmaps_SP(Bitmap **sp_bitmap)
301 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
305 static int getFontBitmapID(int font_nr)
309 /* (special case: do not use special font for GAME_MODE_LOADING) */
310 if (game_status >= GAME_MODE_TITLE_INITIAL &&
311 game_status <= GAME_MODE_PSEUDO_PREVIEW)
312 special = game_status;
313 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
314 special = GFX_SPECIAL_ARG_MAIN;
317 return font_info[font_nr].special_bitmap_id[special];
322 static int getFontFromToken(char *token)
324 char *value = getHashEntry(font_token_hash, token);
329 /* if font not found, use reliable default value */
330 return FONT_INITIAL_1;
333 void InitFontGraphicInfo()
335 static struct FontBitmapInfo *font_bitmap_info = NULL;
336 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
337 int num_property_mappings = getImageListPropertyMappingSize();
338 int num_font_bitmaps = NUM_FONTS;
341 if (graphic_info == NULL) /* still at startup phase */
343 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
344 getFontBitmapID, getFontFromToken);
349 /* ---------- initialize font graphic definitions ---------- */
351 /* always start with reliable default values (normal font graphics) */
352 for (i = 0; i < NUM_FONTS; i++)
353 font_info[i].graphic = IMG_FONT_INITIAL_1;
355 /* initialize normal font/graphic mapping from static configuration */
356 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
358 int font_nr = font_to_graphic[i].font_nr;
359 int special = font_to_graphic[i].special;
360 int graphic = font_to_graphic[i].graphic;
365 font_info[font_nr].graphic = graphic;
368 /* always start with reliable default values (special font graphics) */
369 for (i = 0; i < NUM_FONTS; i++)
371 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
373 font_info[i].special_graphic[j] = font_info[i].graphic;
374 font_info[i].special_bitmap_id[j] = i;
378 /* initialize special font/graphic mapping from static configuration */
379 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
381 int font_nr = font_to_graphic[i].font_nr;
382 int special = font_to_graphic[i].special;
383 int graphic = font_to_graphic[i].graphic;
384 int base_graphic = font2baseimg(font_nr);
386 if (IS_SPECIAL_GFX_ARG(special))
388 boolean base_redefined =
389 getImageListEntryFromImageID(base_graphic)->redefined;
390 boolean special_redefined =
391 getImageListEntryFromImageID(graphic)->redefined;
392 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
394 /* if the base font ("font.title_1", for example) has been redefined,
395 but not the special font ("font.title_1.LEVELS", for example), do not
396 use an existing (in this case considered obsolete) special font
397 anymore, but use the automatically determined default font */
398 /* special case: cloned special fonts must be explicitly redefined,
399 but are not automatically redefined by redefining base font */
400 if (base_redefined && !special_redefined && !special_cloned)
403 font_info[font_nr].special_graphic[special] = graphic;
404 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
409 /* initialize special font/graphic mapping from dynamic configuration */
410 for (i = 0; i < num_property_mappings; i++)
412 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
413 int special = property_mapping[i].ext3_index;
414 int graphic = property_mapping[i].artwork_index;
416 if (font_nr < 0 || font_nr >= NUM_FONTS)
419 if (IS_SPECIAL_GFX_ARG(special))
421 font_info[font_nr].special_graphic[special] = graphic;
422 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
427 /* correct special font/graphic mapping for cloned fonts for downwards
428 compatibility of PREVIEW fonts -- this is only needed for implicit
429 redefinition of special font by redefined base font, and only if other
430 fonts are cloned from this special font (like in the "Zelda" level set) */
431 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
433 int font_nr = font_to_graphic[i].font_nr;
434 int special = font_to_graphic[i].special;
435 int graphic = font_to_graphic[i].graphic;
437 if (IS_SPECIAL_GFX_ARG(special))
439 boolean special_redefined =
440 getImageListEntryFromImageID(graphic)->redefined;
441 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
443 if (special_cloned && !special_redefined)
447 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
449 int font_nr2 = font_to_graphic[j].font_nr;
450 int special2 = font_to_graphic[j].special;
451 int graphic2 = font_to_graphic[j].graphic;
453 if (IS_SPECIAL_GFX_ARG(special2) &&
454 graphic2 == graphic_info[graphic].clone_from)
456 font_info[font_nr].special_graphic[special] =
457 font_info[font_nr2].special_graphic[special2];
458 font_info[font_nr].special_bitmap_id[special] =
459 font_info[font_nr2].special_bitmap_id[special2];
466 /* reset non-redefined ".active" font graphics if normal font is redefined */
467 /* (this different treatment is needed because normal and active fonts are
468 independently defined ("active" is not a property of font definitions!) */
469 for (i = 0; i < NUM_FONTS; i++)
471 int font_nr_base = i;
472 int font_nr_active = FONT_ACTIVE(font_nr_base);
474 /* check only those fonts with exist as normal and ".active" variant */
475 if (font_nr_base != font_nr_active)
477 int base_graphic = font_info[font_nr_base].graphic;
478 int active_graphic = font_info[font_nr_active].graphic;
479 boolean base_redefined =
480 getImageListEntryFromImageID(base_graphic)->redefined;
481 boolean active_redefined =
482 getImageListEntryFromImageID(active_graphic)->redefined;
484 /* if the base font ("font.menu_1", for example) has been redefined,
485 but not the active font ("font.menu_1.active", for example), do not
486 use an existing (in this case considered obsolete) active font
487 anymore, but use the automatically determined default font */
488 if (base_redefined && !active_redefined)
489 font_info[font_nr_active].graphic = base_graphic;
491 /* now also check each "special" font (which may be the same as above) */
492 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
494 int base_graphic = font_info[font_nr_base].special_graphic[j];
495 int active_graphic = font_info[font_nr_active].special_graphic[j];
496 boolean base_redefined =
497 getImageListEntryFromImageID(base_graphic)->redefined;
498 boolean active_redefined =
499 getImageListEntryFromImageID(active_graphic)->redefined;
501 /* same as above, but check special graphic definitions, for example:
502 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
503 if (base_redefined && !active_redefined)
505 font_info[font_nr_active].special_graphic[j] =
506 font_info[font_nr_base].special_graphic[j];
507 font_info[font_nr_active].special_bitmap_id[j] =
508 font_info[font_nr_base].special_bitmap_id[j];
514 /* ---------- initialize font bitmap array ---------- */
516 if (font_bitmap_info != NULL)
517 FreeFontInfo(font_bitmap_info);
520 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
522 /* ---------- initialize font bitmap definitions ---------- */
524 for (i = 0; i < NUM_FONTS; i++)
526 if (i < NUM_INITIAL_FONTS)
528 font_bitmap_info[i] = font_initial[i];
532 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
534 int font_bitmap_id = font_info[i].special_bitmap_id[j];
535 int graphic = font_info[i].special_graphic[j];
537 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
538 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
540 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
541 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
544 /* copy font relevant information from graphics information */
545 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
546 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
547 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
548 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
549 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
551 font_bitmap_info[font_bitmap_id].draw_xoffset =
552 graphic_info[graphic].draw_xoffset;
553 font_bitmap_info[font_bitmap_id].draw_yoffset =
554 graphic_info[graphic].draw_yoffset;
556 font_bitmap_info[font_bitmap_id].num_chars =
557 graphic_info[graphic].anim_frames;
558 font_bitmap_info[font_bitmap_id].num_chars_per_line =
559 graphic_info[graphic].anim_frames_per_line;
563 InitFontInfo(font_bitmap_info, num_font_bitmaps,
564 getFontBitmapID, getFontFromToken);
567 void InitGlobalAnimGraphicInfo()
569 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
570 int num_property_mappings = getImageListPropertyMappingSize();
573 if (graphic_info == NULL) /* still at startup phase */
576 /* always start with reliable default values (no global animations) */
577 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
578 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
579 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
580 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
582 /* initialize global animation definitions from static configuration */
583 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
585 int j = GLOBAL_ANIM_ID_PART_BASE;
586 int k = GFX_SPECIAL_ARG_DEFAULT;
588 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
591 /* initialize global animation definitions from dynamic configuration */
592 for (i = 0; i < num_property_mappings; i++)
594 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
595 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
596 int special = property_mapping[i].ext3_index;
597 int graphic = property_mapping[i].artwork_index;
599 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
602 /* set animation part to base part, if not specified */
603 if (!IS_GLOBAL_ANIM_PART(part_nr))
604 part_nr = GLOBAL_ANIM_ID_PART_BASE;
606 /* set animation screen to default, if not specified */
607 if (!IS_SPECIAL_GFX_ARG(special))
608 special = GFX_SPECIAL_ARG_DEFAULT;
610 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
612 /* fix default value for ".draw_masked" (for backward compatibility) */
613 struct GraphicInfo *g = &graphic_info[graphic];
614 struct FileInfo *image = getImageListEntryFromImageID(graphic);
615 char **parameter_raw = image->parameter;
616 int p = GFX_ARG_DRAW_MASKED;
617 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
618 image_config_suffix[p].token,
619 image_config_suffix[p].type);
621 /* if ".draw_masked" parameter is undefined, use default value "TRUE" */
622 if (draw_masked == ARG_UNDEFINED_VALUE)
623 g->draw_masked = TRUE;
627 printf("::: InitGlobalAnimGraphicInfo\n");
629 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
630 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
631 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
632 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
633 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
634 printf("::: - anim %d, part %d, mode %d => %d\n",
635 i, j, k, global_anim_info[i].graphic[j][k]);
639 void InitGlobalAnimSoundInfo()
641 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
642 int num_property_mappings = getSoundListPropertyMappingSize();
645 /* always start with reliable default values (no global animation sounds) */
646 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
647 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
648 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
649 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
651 /* initialize global animation sound definitions from dynamic configuration */
652 for (i = 0; i < num_property_mappings; i++)
654 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
655 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
656 int special = property_mapping[i].ext3_index;
657 int sound = property_mapping[i].artwork_index;
659 // sound uses control definition; map it to position of graphic (artwork)
660 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
662 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
665 /* set animation part to base part, if not specified */
666 if (!IS_GLOBAL_ANIM_PART(part_nr))
667 part_nr = GLOBAL_ANIM_ID_PART_BASE;
669 /* set animation screen to default, if not specified */
670 if (!IS_SPECIAL_GFX_ARG(special))
671 special = GFX_SPECIAL_ARG_DEFAULT;
673 global_anim_info[anim_nr].sound[part_nr][special] = sound;
677 printf("::: InitGlobalAnimSoundInfo\n");
679 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
680 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
681 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
682 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
683 printf("::: - anim %d, part %d, mode %d => %d\n",
684 i, j, k, global_anim_info[i].sound[j][k]);
688 void InitGlobalAnimMusicInfo()
690 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
691 int num_property_mappings = getMusicListPropertyMappingSize();
694 /* always start with reliable default values (no global animation music) */
695 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
696 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
697 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
698 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
700 /* initialize global animation music definitions from dynamic configuration */
701 for (i = 0; i < num_property_mappings; i++)
703 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
704 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
705 int special = property_mapping[i].ext2_index;
706 int music = property_mapping[i].artwork_index;
708 // music uses control definition; map it to position of graphic (artwork)
709 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
711 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
714 /* set animation part to base part, if not specified */
715 if (!IS_GLOBAL_ANIM_PART(part_nr))
716 part_nr = GLOBAL_ANIM_ID_PART_BASE;
718 /* set animation screen to default, if not specified */
719 if (!IS_SPECIAL_GFX_ARG(special))
720 special = GFX_SPECIAL_ARG_DEFAULT;
722 global_anim_info[anim_nr].music[part_nr][special] = music;
726 printf("::: InitGlobalAnimMusicInfo\n");
728 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
729 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
730 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
731 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
732 printf("::: - anim %d, part %d, mode %d => %d\n",
733 i, j, k, global_anim_info[i].music[j][k]);
737 void InitElementGraphicInfo()
739 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
740 int num_property_mappings = getImageListPropertyMappingSize();
743 if (graphic_info == NULL) /* still at startup phase */
746 /* set values to -1 to identify later as "uninitialized" values */
747 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
749 for (act = 0; act < NUM_ACTIONS; act++)
751 element_info[i].graphic[act] = -1;
752 element_info[i].crumbled[act] = -1;
754 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
756 element_info[i].direction_graphic[act][dir] = -1;
757 element_info[i].direction_crumbled[act][dir] = -1;
764 /* initialize normal element/graphic mapping from static configuration */
765 for (i = 0; element_to_graphic[i].element > -1; i++)
767 int element = element_to_graphic[i].element;
768 int action = element_to_graphic[i].action;
769 int direction = element_to_graphic[i].direction;
770 boolean crumbled = element_to_graphic[i].crumbled;
771 int graphic = element_to_graphic[i].graphic;
772 int base_graphic = el2baseimg(element);
774 if (graphic_info[graphic].bitmap == NULL)
777 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
780 boolean base_redefined =
781 getImageListEntryFromImageID(base_graphic)->redefined;
782 boolean act_dir_redefined =
783 getImageListEntryFromImageID(graphic)->redefined;
785 /* if the base graphic ("emerald", for example) has been redefined,
786 but not the action graphic ("emerald.falling", for example), do not
787 use an existing (in this case considered obsolete) action graphic
788 anymore, but use the automatically determined default graphic */
789 if (base_redefined && !act_dir_redefined)
794 action = ACTION_DEFAULT;
799 element_info[element].direction_crumbled[action][direction] = graphic;
801 element_info[element].crumbled[action] = graphic;
806 element_info[element].direction_graphic[action][direction] = graphic;
808 element_info[element].graphic[action] = graphic;
812 /* initialize normal element/graphic mapping from dynamic configuration */
813 for (i = 0; i < num_property_mappings; i++)
815 int element = property_mapping[i].base_index;
816 int action = property_mapping[i].ext1_index;
817 int direction = property_mapping[i].ext2_index;
818 int special = property_mapping[i].ext3_index;
819 int graphic = property_mapping[i].artwork_index;
820 boolean crumbled = FALSE;
822 if (special == GFX_SPECIAL_ARG_CRUMBLED)
828 if (graphic_info[graphic].bitmap == NULL)
831 if (element >= MAX_NUM_ELEMENTS || special != -1)
835 action = ACTION_DEFAULT;
840 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
841 element_info[element].direction_crumbled[action][dir] = -1;
844 element_info[element].direction_crumbled[action][direction] = graphic;
846 element_info[element].crumbled[action] = graphic;
851 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
852 element_info[element].direction_graphic[action][dir] = -1;
855 element_info[element].direction_graphic[action][direction] = graphic;
857 element_info[element].graphic[action] = graphic;
861 /* now copy all graphics that are defined to be cloned from other graphics */
862 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
864 int graphic = element_info[i].graphic[ACTION_DEFAULT];
865 int crumbled_like, diggable_like;
870 crumbled_like = graphic_info[graphic].crumbled_like;
871 diggable_like = graphic_info[graphic].diggable_like;
873 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
875 for (act = 0; act < NUM_ACTIONS; act++)
876 element_info[i].crumbled[act] =
877 element_info[crumbled_like].crumbled[act];
878 for (act = 0; act < NUM_ACTIONS; act++)
879 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
880 element_info[i].direction_crumbled[act][dir] =
881 element_info[crumbled_like].direction_crumbled[act][dir];
884 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
886 element_info[i].graphic[ACTION_DIGGING] =
887 element_info[diggable_like].graphic[ACTION_DIGGING];
888 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
889 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
890 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
894 /* set hardcoded definitions for some runtime elements without graphic */
895 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
897 /* set hardcoded definitions for some internal elements without graphic */
898 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
900 if (IS_EDITOR_CASCADE_INACTIVE(i))
901 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
902 else if (IS_EDITOR_CASCADE_ACTIVE(i))
903 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
906 /* now set all undefined/invalid graphics to -1 to set to default after it */
907 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
909 for (act = 0; act < NUM_ACTIONS; act++)
913 graphic = element_info[i].graphic[act];
914 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
915 element_info[i].graphic[act] = -1;
917 graphic = element_info[i].crumbled[act];
918 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
919 element_info[i].crumbled[act] = -1;
921 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
923 graphic = element_info[i].direction_graphic[act][dir];
924 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
925 element_info[i].direction_graphic[act][dir] = -1;
927 graphic = element_info[i].direction_crumbled[act][dir];
928 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
929 element_info[i].direction_crumbled[act][dir] = -1;
936 /* adjust graphics with 2nd tile for movement according to direction
937 (do this before correcting '-1' values to minimize calculations) */
938 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
940 for (act = 0; act < NUM_ACTIONS; act++)
942 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
944 int graphic = element_info[i].direction_graphic[act][dir];
945 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
947 if (act == ACTION_FALLING) /* special case */
948 graphic = element_info[i].graphic[act];
951 graphic_info[graphic].double_movement &&
952 graphic_info[graphic].swap_double_tiles != 0)
954 struct GraphicInfo *g = &graphic_info[graphic];
955 int src_x_front = g->src_x;
956 int src_y_front = g->src_y;
957 int src_x_back = g->src_x + g->offset2_x;
958 int src_y_back = g->src_y + g->offset2_y;
959 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
961 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
962 src_y_front < src_y_back);
963 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
964 boolean swap_movement_tiles_autodetected =
965 (!frames_are_ordered_diagonally &&
966 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
967 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
968 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
969 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
971 /* swap frontside and backside graphic tile coordinates, if needed */
972 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
974 /* get current (wrong) backside tile coordinates */
975 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
977 /* set frontside tile coordinates to backside tile coordinates */
978 g->src_x = src_x_back;
979 g->src_y = src_y_back;
981 /* invert tile offset to point to new backside tile coordinates */
985 /* do not swap front and backside tiles again after correction */
986 g->swap_double_tiles = 0;
995 /* now set all '-1' values to element specific default values */
996 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
998 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
999 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1000 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1001 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1003 if (default_graphic == -1)
1004 default_graphic = IMG_UNKNOWN;
1006 if (default_crumbled == -1)
1007 default_crumbled = default_graphic;
1009 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1011 default_direction_graphic[dir] =
1012 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1013 default_direction_crumbled[dir] =
1014 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1016 if (default_direction_graphic[dir] == -1)
1017 default_direction_graphic[dir] = default_graphic;
1019 if (default_direction_crumbled[dir] == -1)
1020 default_direction_crumbled[dir] = default_direction_graphic[dir];
1023 for (act = 0; act < NUM_ACTIONS; act++)
1025 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1026 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1027 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1028 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1029 act == ACTION_TURNING_FROM_RIGHT ||
1030 act == ACTION_TURNING_FROM_UP ||
1031 act == ACTION_TURNING_FROM_DOWN);
1033 /* generic default action graphic (defined by "[default]" directive) */
1034 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1035 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1036 int default_remove_graphic = IMG_EMPTY;
1038 if (act_remove && default_action_graphic != -1)
1039 default_remove_graphic = default_action_graphic;
1041 /* look for special default action graphic (classic game specific) */
1042 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1043 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1044 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1045 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1046 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1047 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1049 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1050 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1051 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1052 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1053 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1054 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1056 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1057 /* !!! make this better !!! */
1058 if (i == EL_EMPTY_SPACE)
1060 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1061 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1064 if (default_action_graphic == -1)
1065 default_action_graphic = default_graphic;
1067 if (default_action_crumbled == -1)
1068 default_action_crumbled = default_action_graphic;
1070 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1072 /* use action graphic as the default direction graphic, if undefined */
1073 int default_action_direction_graphic = element_info[i].graphic[act];
1074 int default_action_direction_crumbled = element_info[i].crumbled[act];
1076 /* no graphic for current action -- use default direction graphic */
1077 if (default_action_direction_graphic == -1)
1078 default_action_direction_graphic =
1079 (act_remove ? default_remove_graphic :
1081 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1082 default_action_graphic != default_graphic ?
1083 default_action_graphic :
1084 default_direction_graphic[dir]);
1086 if (element_info[i].direction_graphic[act][dir] == -1)
1087 element_info[i].direction_graphic[act][dir] =
1088 default_action_direction_graphic;
1090 if (default_action_direction_crumbled == -1)
1091 default_action_direction_crumbled =
1092 element_info[i].direction_graphic[act][dir];
1094 if (element_info[i].direction_crumbled[act][dir] == -1)
1095 element_info[i].direction_crumbled[act][dir] =
1096 default_action_direction_crumbled;
1099 /* no graphic for this specific action -- use default action graphic */
1100 if (element_info[i].graphic[act] == -1)
1101 element_info[i].graphic[act] =
1102 (act_remove ? default_remove_graphic :
1103 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1104 default_action_graphic);
1106 if (element_info[i].crumbled[act] == -1)
1107 element_info[i].crumbled[act] = element_info[i].graphic[act];
1111 UPDATE_BUSY_STATE();
1114 void InitElementSpecialGraphicInfo()
1116 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1117 int num_property_mappings = getImageListPropertyMappingSize();
1120 /* always start with reliable default values */
1121 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1122 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1123 element_info[i].special_graphic[j] =
1124 element_info[i].graphic[ACTION_DEFAULT];
1126 /* initialize special element/graphic mapping from static configuration */
1127 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1129 int element = element_to_special_graphic[i].element;
1130 int special = element_to_special_graphic[i].special;
1131 int graphic = element_to_special_graphic[i].graphic;
1132 int base_graphic = el2baseimg(element);
1133 boolean base_redefined =
1134 getImageListEntryFromImageID(base_graphic)->redefined;
1135 boolean special_redefined =
1136 getImageListEntryFromImageID(graphic)->redefined;
1138 /* if the base graphic ("emerald", for example) has been redefined,
1139 but not the special graphic ("emerald.EDITOR", for example), do not
1140 use an existing (in this case considered obsolete) special graphic
1141 anymore, but use the automatically created (down-scaled) graphic */
1142 if (base_redefined && !special_redefined)
1145 element_info[element].special_graphic[special] = graphic;
1148 /* initialize special element/graphic mapping from dynamic configuration */
1149 for (i = 0; i < num_property_mappings; i++)
1151 int element = property_mapping[i].base_index;
1152 int action = property_mapping[i].ext1_index;
1153 int direction = property_mapping[i].ext2_index;
1154 int special = property_mapping[i].ext3_index;
1155 int graphic = property_mapping[i].artwork_index;
1157 /* for action ".active", replace element with active element, if exists */
1158 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1160 element = ELEMENT_ACTIVE(element);
1164 if (element >= MAX_NUM_ELEMENTS)
1167 /* do not change special graphic if action or direction was specified */
1168 if (action != -1 || direction != -1)
1171 if (IS_SPECIAL_GFX_ARG(special))
1172 element_info[element].special_graphic[special] = graphic;
1175 /* now set all undefined/invalid graphics to default */
1176 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1177 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1178 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1179 element_info[i].special_graphic[j] =
1180 element_info[i].graphic[ACTION_DEFAULT];
1183 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1185 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1186 return get_parameter_value(value_raw, suffix, type);
1188 if (strEqual(value_raw, ARG_UNDEFINED))
1189 return ARG_UNDEFINED_VALUE;
1191 if (type == TYPE_ELEMENT)
1193 char *value = getHashEntry(element_token_hash, value_raw);
1197 Error(ERR_INFO_LINE, "-");
1198 Error(ERR_INFO, "warning: error found in config file:");
1199 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1200 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1201 Error(ERR_INFO, "custom graphic rejected for this element/action");
1202 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1203 Error(ERR_INFO_LINE, "-");
1206 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1208 else if (type == TYPE_GRAPHIC)
1210 char *value = getHashEntry(graphic_token_hash, value_raw);
1211 int fallback_graphic = IMG_CHAR_EXCLAM;
1215 Error(ERR_INFO_LINE, "-");
1216 Error(ERR_INFO, "warning: error found in config file:");
1217 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1218 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1219 Error(ERR_INFO, "custom graphic rejected for this element/action");
1220 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1221 Error(ERR_INFO_LINE, "-");
1224 return (value != NULL ? atoi(value) : fallback_graphic);
1230 static int get_scaled_graphic_width(int graphic)
1232 int original_width = getOriginalImageWidthFromImageID(graphic);
1233 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1235 return original_width * scale_up_factor;
1238 static int get_scaled_graphic_height(int graphic)
1240 int original_height = getOriginalImageHeightFromImageID(graphic);
1241 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1243 return original_height * scale_up_factor;
1246 static void set_graphic_parameters_ext(int graphic, int *parameter,
1247 Bitmap **src_bitmaps)
1249 struct GraphicInfo *g = &graphic_info[graphic];
1250 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1251 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1252 int anim_frames_per_line = 1;
1254 /* always start with reliable default values */
1255 g->src_image_width = 0;
1256 g->src_image_height = 0;
1259 g->width = TILEX; /* default for element graphics */
1260 g->height = TILEY; /* default for element graphics */
1261 g->offset_x = 0; /* one or both of these values ... */
1262 g->offset_y = 0; /* ... will be corrected later */
1263 g->offset2_x = 0; /* one or both of these values ... */
1264 g->offset2_y = 0; /* ... will be corrected later */
1265 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1266 g->crumbled_like = -1; /* do not use clone element */
1267 g->diggable_like = -1; /* do not use clone element */
1268 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1269 g->scale_up_factor = 1; /* default: no scaling up */
1270 g->tile_size = TILESIZE; /* default: standard tile size */
1271 g->clone_from = -1; /* do not use clone graphic */
1272 g->init_delay_fixed = 0;
1273 g->init_delay_random = 0;
1274 g->anim_delay_fixed = 0;
1275 g->anim_delay_random = 0;
1276 g->post_delay_fixed = 0;
1277 g->post_delay_random = 0;
1278 g->init_event = ANIM_EVENT_DEFAULT;
1279 g->anim_event = ANIM_EVENT_DEFAULT;
1280 g->draw_masked = FALSE;
1282 g->fade_mode = FADE_MODE_DEFAULT;
1286 g->align = ALIGN_CENTER; /* default for title screens */
1287 g->valign = VALIGN_MIDDLE; /* default for title screens */
1288 g->sort_priority = 0; /* default for title screens */
1290 g->style = STYLE_DEFAULT;
1292 g->bitmaps = src_bitmaps;
1293 g->bitmap = src_bitmap;
1295 /* optional zoom factor for scaling up the image to a larger size */
1296 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1297 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1298 if (g->scale_up_factor < 1)
1299 g->scale_up_factor = 1; /* no scaling */
1301 /* optional tile size for using non-standard image size */
1302 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1304 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1307 // CHECK: should tile sizes less than standard tile size be allowed?
1308 if (g->tile_size < TILESIZE)
1309 g->tile_size = TILESIZE; /* standard tile size */
1312 // when setting tile size, also set width and height accordingly
1313 g->width = g->tile_size;
1314 g->height = g->tile_size;
1317 if (g->use_image_size)
1319 /* set new default bitmap size (with scaling, but without small images) */
1320 g->width = get_scaled_graphic_width(graphic);
1321 g->height = get_scaled_graphic_height(graphic);
1324 /* optional width and height of each animation frame */
1325 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1326 g->width = parameter[GFX_ARG_WIDTH];
1327 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1328 g->height = parameter[GFX_ARG_HEIGHT];
1330 /* optional x and y tile position of animation frame sequence */
1331 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1332 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1333 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1334 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1336 /* optional x and y pixel position of animation frame sequence */
1337 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1338 g->src_x = parameter[GFX_ARG_X];
1339 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1340 g->src_y = parameter[GFX_ARG_Y];
1346 Error(ERR_INFO_LINE, "-");
1347 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1348 g->width, getTokenFromImageID(graphic), TILEX);
1349 Error(ERR_INFO_LINE, "-");
1351 g->width = TILEX; /* will be checked to be inside bitmap later */
1356 Error(ERR_INFO_LINE, "-");
1357 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1358 g->height, getTokenFromImageID(graphic), TILEY);
1359 Error(ERR_INFO_LINE, "-");
1361 g->height = TILEY; /* will be checked to be inside bitmap later */
1367 /* get final bitmap size (with scaling, but without small images) */
1368 int src_image_width = get_scaled_graphic_width(graphic);
1369 int src_image_height = get_scaled_graphic_height(graphic);
1371 if (src_image_width == 0 || src_image_height == 0)
1373 /* only happens when loaded outside artwork system (like "global.busy") */
1374 src_image_width = src_bitmap->width;
1375 src_image_height = src_bitmap->height;
1378 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1380 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1381 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1385 anim_frames_per_row = MAX(1, src_image_width / g->width);
1386 anim_frames_per_col = MAX(1, src_image_height / g->height);
1389 g->src_image_width = src_image_width;
1390 g->src_image_height = src_image_height;
1393 /* correct x or y offset dependent of vertical or horizontal frame order */
1394 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1396 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1397 parameter[GFX_ARG_OFFSET] : g->height);
1398 anim_frames_per_line = anim_frames_per_col;
1400 else /* frames are ordered horizontally */
1402 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1403 parameter[GFX_ARG_OFFSET] : g->width);
1404 anim_frames_per_line = anim_frames_per_row;
1407 /* optionally, the x and y offset of frames can be specified directly */
1408 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1409 g->offset_x = parameter[GFX_ARG_XOFFSET];
1410 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1411 g->offset_y = parameter[GFX_ARG_YOFFSET];
1413 /* optionally, moving animations may have separate start and end graphics */
1414 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1416 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1417 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1419 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1420 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1421 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1422 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1423 else /* frames are ordered horizontally */
1424 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1425 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1427 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1428 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1429 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1430 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1431 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1433 /* optionally, the second movement tile can be specified as start tile */
1434 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1435 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1437 /* automatically determine correct number of frames, if not defined */
1438 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1439 g->anim_frames = parameter[GFX_ARG_FRAMES];
1440 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1441 g->anim_frames = anim_frames_per_row;
1442 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1443 g->anim_frames = anim_frames_per_col;
1447 if (g->anim_frames == 0) /* frames must be at least 1 */
1450 g->anim_frames_per_line =
1451 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1452 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1454 g->anim_delay = parameter[GFX_ARG_DELAY];
1455 if (g->anim_delay == 0) /* delay must be at least 1 */
1458 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1460 /* automatically determine correct start frame, if not defined */
1461 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1462 g->anim_start_frame = 0;
1463 else if (g->anim_mode & ANIM_REVERSE)
1464 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1466 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1468 /* animation synchronized with global frame counter, not move position */
1469 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1471 /* optional element for cloning crumble graphics */
1472 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1473 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1475 /* optional element for cloning digging graphics */
1476 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1477 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1479 /* optional border size for "crumbling" diggable graphics */
1480 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1481 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1483 /* used for global animations and player "boring" and "sleeping" actions */
1484 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1485 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1486 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1487 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1488 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1489 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1490 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1491 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1492 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1493 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1494 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1495 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1497 /* used for global animations */
1498 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1499 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1500 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1501 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1503 /* used for toon animations and global animations */
1504 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1505 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1506 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1507 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1508 g->direction = parameter[GFX_ARG_DIRECTION];
1509 g->position = parameter[GFX_ARG_POSITION];
1510 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1511 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1513 /* this is only used for drawing font characters */
1514 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1515 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1517 /* use a different default value for global animations and toons */
1518 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1519 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1520 g->draw_masked = TRUE;
1522 /* this is used for drawing envelopes, global animations and toons */
1523 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1524 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1526 /* used for toon animations and global animations */
1527 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1528 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1530 /* optional graphic for cloning all graphics settings */
1531 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1532 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1534 /* optional settings for drawing title screens and title messages */
1535 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1536 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1537 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1538 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1539 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1540 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1541 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1542 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1543 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1544 g->align = parameter[GFX_ARG_ALIGN];
1545 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1546 g->valign = parameter[GFX_ARG_VALIGN];
1547 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1548 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1550 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1551 g->class = parameter[GFX_ARG_CLASS];
1552 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1553 g->style = parameter[GFX_ARG_STYLE];
1555 /* this is only used for drawing menu buttons and text */
1556 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1557 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1558 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1559 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1562 static void set_graphic_parameters(int graphic)
1564 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1565 char **parameter_raw = image->parameter;
1566 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1567 int parameter[NUM_GFX_ARGS];
1570 /* if fallback to default artwork is done, also use the default parameters */
1571 if (image->fallback_to_default)
1572 parameter_raw = image->default_parameter;
1574 /* get integer values from string parameters */
1575 for (i = 0; i < NUM_GFX_ARGS; i++)
1576 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1577 image_config_suffix[i].token,
1578 image_config_suffix[i].type);
1580 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1582 UPDATE_BUSY_STATE();
1585 static void set_cloned_graphic_parameters(int graphic)
1587 int fallback_graphic = IMG_CHAR_EXCLAM;
1588 int max_num_images = getImageListSize();
1589 int clone_graphic = graphic_info[graphic].clone_from;
1590 int num_references_followed = 1;
1592 while (graphic_info[clone_graphic].clone_from != -1 &&
1593 num_references_followed < max_num_images)
1595 clone_graphic = graphic_info[clone_graphic].clone_from;
1597 num_references_followed++;
1600 if (num_references_followed >= max_num_images)
1602 Error(ERR_INFO_LINE, "-");
1603 Error(ERR_INFO, "warning: error found in config file:");
1604 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1605 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1606 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1607 Error(ERR_INFO, "custom graphic rejected for this element/action");
1609 if (graphic == fallback_graphic)
1610 Error(ERR_EXIT, "no fallback graphic available");
1612 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1613 Error(ERR_INFO_LINE, "-");
1615 graphic_info[graphic] = graphic_info[fallback_graphic];
1619 graphic_info[graphic] = graphic_info[clone_graphic];
1620 graphic_info[graphic].clone_from = clone_graphic;
1624 static void InitGraphicInfo()
1626 int fallback_graphic = IMG_CHAR_EXCLAM;
1627 int num_images = getImageListSize();
1630 /* use image size as default values for width and height for these images */
1631 static int full_size_graphics[] =
1634 IMG_GLOBAL_BORDER_MAIN,
1635 IMG_GLOBAL_BORDER_SCORES,
1636 IMG_GLOBAL_BORDER_EDITOR,
1637 IMG_GLOBAL_BORDER_PLAYING,
1640 IMG_BACKGROUND_ENVELOPE_1,
1641 IMG_BACKGROUND_ENVELOPE_2,
1642 IMG_BACKGROUND_ENVELOPE_3,
1643 IMG_BACKGROUND_ENVELOPE_4,
1644 IMG_BACKGROUND_REQUEST,
1647 IMG_BACKGROUND_TITLE_INITIAL,
1648 IMG_BACKGROUND_TITLE,
1649 IMG_BACKGROUND_MAIN,
1650 IMG_BACKGROUND_LEVELS,
1651 IMG_BACKGROUND_LEVELNR,
1652 IMG_BACKGROUND_SCORES,
1653 IMG_BACKGROUND_EDITOR,
1654 IMG_BACKGROUND_INFO,
1655 IMG_BACKGROUND_INFO_ELEMENTS,
1656 IMG_BACKGROUND_INFO_MUSIC,
1657 IMG_BACKGROUND_INFO_CREDITS,
1658 IMG_BACKGROUND_INFO_PROGRAM,
1659 IMG_BACKGROUND_INFO_VERSION,
1660 IMG_BACKGROUND_INFO_LEVELSET,
1661 IMG_BACKGROUND_SETUP,
1662 IMG_BACKGROUND_PLAYING,
1663 IMG_BACKGROUND_DOOR,
1664 IMG_BACKGROUND_TAPE,
1665 IMG_BACKGROUND_PANEL,
1666 IMG_BACKGROUND_PALETTE,
1667 IMG_BACKGROUND_TOOLBOX,
1669 IMG_TITLESCREEN_INITIAL_1,
1670 IMG_TITLESCREEN_INITIAL_2,
1671 IMG_TITLESCREEN_INITIAL_3,
1672 IMG_TITLESCREEN_INITIAL_4,
1673 IMG_TITLESCREEN_INITIAL_5,
1680 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1681 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1682 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1683 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1684 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1685 IMG_BACKGROUND_TITLEMESSAGE_1,
1686 IMG_BACKGROUND_TITLEMESSAGE_2,
1687 IMG_BACKGROUND_TITLEMESSAGE_3,
1688 IMG_BACKGROUND_TITLEMESSAGE_4,
1689 IMG_BACKGROUND_TITLEMESSAGE_5,
1694 checked_free(graphic_info);
1696 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1698 /* initialize "use_image_size" flag with default value */
1699 for (i = 0; i < num_images; i++)
1700 graphic_info[i].use_image_size = FALSE;
1702 /* initialize "use_image_size" flag from static configuration above */
1703 for (i = 0; full_size_graphics[i] != -1; i++)
1704 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1706 /* first set all graphic paramaters ... */
1707 for (i = 0; i < num_images; i++)
1708 set_graphic_parameters(i);
1710 /* ... then copy these parameters for cloned graphics */
1711 for (i = 0; i < num_images; i++)
1712 if (graphic_info[i].clone_from != -1)
1713 set_cloned_graphic_parameters(i);
1715 for (i = 0; i < num_images; i++)
1720 int first_frame, last_frame;
1721 int src_bitmap_width, src_bitmap_height;
1723 /* now check if no animation frames are outside of the loaded image */
1725 if (graphic_info[i].bitmap == NULL)
1726 continue; /* skip check for optional images that are undefined */
1728 /* get image size (this can differ from the standard element tile size!) */
1729 width = graphic_info[i].width;
1730 height = graphic_info[i].height;
1732 /* get final bitmap size (with scaling, but without small images) */
1733 src_bitmap_width = graphic_info[i].src_image_width;
1734 src_bitmap_height = graphic_info[i].src_image_height;
1736 /* check if first animation frame is inside specified bitmap */
1739 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1741 /* this avoids calculating wrong start position for out-of-bounds frame */
1742 src_x = graphic_info[i].src_x;
1743 src_y = graphic_info[i].src_y;
1745 if (program.headless)
1748 if (src_x < 0 || src_y < 0 ||
1749 src_x + width > src_bitmap_width ||
1750 src_y + height > src_bitmap_height)
1752 Error(ERR_INFO_LINE, "-");
1753 Error(ERR_INFO, "warning: error found in config file:");
1754 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1755 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1756 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1757 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1759 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1760 src_x, src_y, src_bitmap_width, src_bitmap_height);
1761 Error(ERR_INFO, "custom graphic rejected for this element/action");
1763 if (i == fallback_graphic)
1764 Error(ERR_EXIT, "no fallback graphic available");
1766 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1767 Error(ERR_INFO_LINE, "-");
1769 graphic_info[i] = graphic_info[fallback_graphic];
1772 /* check if last animation frame is inside specified bitmap */
1774 last_frame = graphic_info[i].anim_frames - 1;
1775 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1777 if (src_x < 0 || src_y < 0 ||
1778 src_x + width > src_bitmap_width ||
1779 src_y + height > src_bitmap_height)
1781 Error(ERR_INFO_LINE, "-");
1782 Error(ERR_INFO, "warning: error found in config file:");
1783 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1784 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1785 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1786 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1788 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1789 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1790 Error(ERR_INFO, "custom graphic rejected for this element/action");
1792 if (i == fallback_graphic)
1793 Error(ERR_EXIT, "no fallback graphic available");
1795 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1796 Error(ERR_INFO_LINE, "-");
1798 graphic_info[i] = graphic_info[fallback_graphic];
1803 static void InitGraphicCompatibilityInfo()
1805 struct FileInfo *fi_global_door =
1806 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1807 int num_images = getImageListSize();
1810 /* the following compatibility handling is needed for the following case:
1811 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1812 graphics mainly used for door and panel graphics, like editor, tape and
1813 in-game buttons with hard-coded bitmap positions and button sizes; as
1814 these graphics now have individual definitions, redefining "global.door"
1815 to change all these graphics at once like before does not work anymore
1816 (because all those individual definitions still have their default values);
1817 to solve this, remap all those individual definitions that are not
1818 redefined to the new bitmap of "global.door" if it was redefined */
1820 /* special compatibility handling if image "global.door" was redefined */
1821 if (fi_global_door->redefined)
1823 for (i = 0; i < num_images; i++)
1825 struct FileInfo *fi = getImageListEntryFromImageID(i);
1827 /* process only those images that still use the default settings */
1830 /* process all images which default to same image as "global.door" */
1831 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1833 // printf("::: special treatment needed for token '%s'\n", fi->token);
1835 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1836 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1842 InitGraphicCompatibilityInfo_Doors();
1845 static void InitElementSoundInfo()
1847 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1848 int num_property_mappings = getSoundListPropertyMappingSize();
1851 /* set values to -1 to identify later as "uninitialized" values */
1852 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1853 for (act = 0; act < NUM_ACTIONS; act++)
1854 element_info[i].sound[act] = -1;
1856 /* initialize element/sound mapping from static configuration */
1857 for (i = 0; element_to_sound[i].element > -1; i++)
1859 int element = element_to_sound[i].element;
1860 int action = element_to_sound[i].action;
1861 int sound = element_to_sound[i].sound;
1862 boolean is_class = element_to_sound[i].is_class;
1865 action = ACTION_DEFAULT;
1868 element_info[element].sound[action] = sound;
1870 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1871 if (strEqual(element_info[j].class_name,
1872 element_info[element].class_name))
1873 element_info[j].sound[action] = sound;
1876 /* initialize element class/sound mapping from dynamic configuration */
1877 for (i = 0; i < num_property_mappings; i++)
1879 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1880 int action = property_mapping[i].ext1_index;
1881 int sound = property_mapping[i].artwork_index;
1883 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1887 action = ACTION_DEFAULT;
1889 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1890 if (strEqual(element_info[j].class_name,
1891 element_info[element_class].class_name))
1892 element_info[j].sound[action] = sound;
1895 /* initialize element/sound mapping from dynamic configuration */
1896 for (i = 0; i < num_property_mappings; i++)
1898 int element = property_mapping[i].base_index;
1899 int action = property_mapping[i].ext1_index;
1900 int sound = property_mapping[i].artwork_index;
1902 if (element >= MAX_NUM_ELEMENTS)
1906 action = ACTION_DEFAULT;
1908 element_info[element].sound[action] = sound;
1911 /* now set all '-1' values to element specific default values */
1912 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1914 for (act = 0; act < NUM_ACTIONS; act++)
1916 /* generic default action sound (defined by "[default]" directive) */
1917 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1919 /* look for special default action sound (classic game specific) */
1920 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1921 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1922 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1923 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1924 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1925 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1927 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1928 /* !!! make this better !!! */
1929 if (i == EL_EMPTY_SPACE)
1930 default_action_sound = element_info[EL_DEFAULT].sound[act];
1932 /* no sound for this specific action -- use default action sound */
1933 if (element_info[i].sound[act] == -1)
1934 element_info[i].sound[act] = default_action_sound;
1938 /* copy sound settings to some elements that are only stored in level file
1939 in native R'n'D levels, but are used by game engine in native EM levels */
1940 for (i = 0; copy_properties[i][0] != -1; i++)
1941 for (j = 1; j <= 4; j++)
1942 for (act = 0; act < NUM_ACTIONS; act++)
1943 element_info[copy_properties[i][j]].sound[act] =
1944 element_info[copy_properties[i][0]].sound[act];
1947 static void InitGameModeSoundInfo()
1951 /* set values to -1 to identify later as "uninitialized" values */
1952 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1955 /* initialize gamemode/sound mapping from static configuration */
1956 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1958 int gamemode = gamemode_to_sound[i].gamemode;
1959 int sound = gamemode_to_sound[i].sound;
1962 gamemode = GAME_MODE_DEFAULT;
1964 menu.sound[gamemode] = sound;
1967 /* now set all '-1' values to levelset specific default values */
1968 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1969 if (menu.sound[i] == -1)
1970 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1973 static void set_sound_parameters(int sound, char **parameter_raw)
1975 int parameter[NUM_SND_ARGS];
1978 /* get integer values from string parameters */
1979 for (i = 0; i < NUM_SND_ARGS; i++)
1981 get_parameter_value(parameter_raw[i],
1982 sound_config_suffix[i].token,
1983 sound_config_suffix[i].type);
1985 /* explicit loop mode setting in configuration overrides default value */
1986 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1987 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1989 /* sound volume to change the original volume when loading the sound file */
1990 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1992 /* sound priority to give certain sounds a higher or lower priority */
1993 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1996 static void InitSoundInfo()
1998 int *sound_effect_properties;
1999 int num_sounds = getSoundListSize();
2002 checked_free(sound_info);
2004 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2005 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2007 /* initialize sound effect for all elements to "no sound" */
2008 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2009 for (j = 0; j < NUM_ACTIONS; j++)
2010 element_info[i].sound[j] = SND_UNDEFINED;
2012 for (i = 0; i < num_sounds; i++)
2014 struct FileInfo *sound = getSoundListEntry(i);
2015 int len_effect_text = strlen(sound->token);
2017 sound_effect_properties[i] = ACTION_OTHER;
2018 sound_info[i].loop = FALSE; /* default: play sound only once */
2020 /* determine all loop sounds and identify certain sound classes */
2022 for (j = 0; element_action_info[j].suffix; j++)
2024 int len_action_text = strlen(element_action_info[j].suffix);
2026 if (len_action_text < len_effect_text &&
2027 strEqual(&sound->token[len_effect_text - len_action_text],
2028 element_action_info[j].suffix))
2030 sound_effect_properties[i] = element_action_info[j].value;
2031 sound_info[i].loop = element_action_info[j].is_loop_sound;
2037 /* associate elements and some selected sound actions */
2039 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2041 if (element_info[j].class_name)
2043 int len_class_text = strlen(element_info[j].class_name);
2045 if (len_class_text + 1 < len_effect_text &&
2046 strncmp(sound->token,
2047 element_info[j].class_name, len_class_text) == 0 &&
2048 sound->token[len_class_text] == '.')
2050 int sound_action_value = sound_effect_properties[i];
2052 element_info[j].sound[sound_action_value] = i;
2057 set_sound_parameters(i, sound->parameter);
2060 free(sound_effect_properties);
2063 static void InitGameModeMusicInfo()
2065 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2066 int num_property_mappings = getMusicListPropertyMappingSize();
2067 int default_levelset_music = -1;
2070 /* set values to -1 to identify later as "uninitialized" values */
2071 for (i = 0; i < MAX_LEVELS; i++)
2072 levelset.music[i] = -1;
2073 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2076 /* initialize gamemode/music mapping from static configuration */
2077 for (i = 0; gamemode_to_music[i].music > -1; i++)
2079 int gamemode = gamemode_to_music[i].gamemode;
2080 int music = gamemode_to_music[i].music;
2083 gamemode = GAME_MODE_DEFAULT;
2085 menu.music[gamemode] = music;
2088 /* initialize gamemode/music mapping from dynamic configuration */
2089 for (i = 0; i < num_property_mappings; i++)
2091 int prefix = property_mapping[i].base_index;
2092 int gamemode = property_mapping[i].ext2_index;
2093 int level = property_mapping[i].ext3_index;
2094 int music = property_mapping[i].artwork_index;
2096 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2100 gamemode = GAME_MODE_DEFAULT;
2102 /* level specific music only allowed for in-game music */
2103 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2104 gamemode = GAME_MODE_PLAYING;
2109 default_levelset_music = music;
2112 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2113 levelset.music[level] = music;
2114 if (gamemode != GAME_MODE_PLAYING)
2115 menu.music[gamemode] = music;
2118 /* now set all '-1' values to menu specific default values */
2119 /* (undefined values of "levelset.music[]" might stay at "-1" to
2120 allow dynamic selection of music files from music directory!) */
2121 for (i = 0; i < MAX_LEVELS; i++)
2122 if (levelset.music[i] == -1)
2123 levelset.music[i] = default_levelset_music;
2124 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2125 if (menu.music[i] == -1)
2126 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2129 static void set_music_parameters(int music, char **parameter_raw)
2131 int parameter[NUM_MUS_ARGS];
2134 /* get integer values from string parameters */
2135 for (i = 0; i < NUM_MUS_ARGS; i++)
2137 get_parameter_value(parameter_raw[i],
2138 music_config_suffix[i].token,
2139 music_config_suffix[i].type);
2141 /* explicit loop mode setting in configuration overrides default value */
2142 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2143 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2146 static void InitMusicInfo()
2148 int num_music = getMusicListSize();
2151 checked_free(music_info);
2153 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2155 for (i = 0; i < num_music; i++)
2157 struct FileInfo *music = getMusicListEntry(i);
2158 int len_music_text = strlen(music->token);
2160 music_info[i].loop = TRUE; /* default: play music in loop mode */
2162 /* determine all loop music */
2164 for (j = 0; music_prefix_info[j].prefix; j++)
2166 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2168 if (len_prefix_text < len_music_text &&
2169 strncmp(music->token,
2170 music_prefix_info[j].prefix, len_prefix_text) == 0)
2172 music_info[i].loop = music_prefix_info[j].is_loop_music;
2178 set_music_parameters(i, music->parameter);
2182 static void ReinitializeGraphics()
2184 print_timestamp_init("ReinitializeGraphics");
2186 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2188 InitGraphicInfo(); /* graphic properties mapping */
2189 print_timestamp_time("InitGraphicInfo");
2190 InitElementGraphicInfo(); /* element game graphic mapping */
2191 print_timestamp_time("InitElementGraphicInfo");
2192 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2193 print_timestamp_time("InitElementSpecialGraphicInfo");
2195 InitElementSmallImages(); /* scale elements to all needed sizes */
2196 print_timestamp_time("InitElementSmallImages");
2197 InitScaledImages(); /* scale all other images, if needed */
2198 print_timestamp_time("InitScaledImages");
2199 InitBitmapPointers(); /* set standard size bitmap pointers */
2200 print_timestamp_time("InitBitmapPointers");
2201 InitFontGraphicInfo(); /* initialize text drawing functions */
2202 print_timestamp_time("InitFontGraphicInfo");
2203 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2204 print_timestamp_time("InitGlobalAnimGraphicInfo");
2206 InitImageTextures(); /* create textures for certain images */
2207 print_timestamp_time("InitImageTextures");
2209 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2210 print_timestamp_time("InitGraphicInfo_EM");
2212 InitGraphicCompatibilityInfo();
2213 print_timestamp_time("InitGraphicCompatibilityInfo");
2215 SetMainBackgroundImage(IMG_BACKGROUND);
2216 print_timestamp_time("SetMainBackgroundImage");
2217 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2218 print_timestamp_time("SetDoorBackgroundImage");
2221 print_timestamp_time("InitGadgets");
2223 print_timestamp_time("InitDoors");
2225 print_timestamp_done("ReinitializeGraphics");
2228 static void ReinitializeSounds()
2230 InitSoundInfo(); /* sound properties mapping */
2231 InitElementSoundInfo(); /* element game sound mapping */
2232 InitGameModeSoundInfo(); /* game mode sound mapping */
2233 InitGlobalAnimSoundInfo(); /* global animation sound settings */
2235 InitPlayLevelSound(); /* internal game sound settings */
2238 static void ReinitializeMusic()
2240 InitMusicInfo(); /* music properties mapping */
2241 InitGameModeMusicInfo(); /* game mode music mapping */
2242 InitGlobalAnimMusicInfo(); /* global animation music settings */
2245 static int get_special_property_bit(int element, int property_bit_nr)
2247 struct PropertyBitInfo
2253 static struct PropertyBitInfo pb_can_move_into_acid[] =
2255 /* the player may be able fall into acid when gravity is activated */
2260 { EL_SP_MURPHY, 0 },
2261 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2263 /* all elements that can move may be able to also move into acid */
2266 { EL_BUG_RIGHT, 1 },
2269 { EL_SPACESHIP, 2 },
2270 { EL_SPACESHIP_LEFT, 2 },
2271 { EL_SPACESHIP_RIGHT, 2 },
2272 { EL_SPACESHIP_UP, 2 },
2273 { EL_SPACESHIP_DOWN, 2 },
2274 { EL_BD_BUTTERFLY, 3 },
2275 { EL_BD_BUTTERFLY_LEFT, 3 },
2276 { EL_BD_BUTTERFLY_RIGHT, 3 },
2277 { EL_BD_BUTTERFLY_UP, 3 },
2278 { EL_BD_BUTTERFLY_DOWN, 3 },
2279 { EL_BD_FIREFLY, 4 },
2280 { EL_BD_FIREFLY_LEFT, 4 },
2281 { EL_BD_FIREFLY_RIGHT, 4 },
2282 { EL_BD_FIREFLY_UP, 4 },
2283 { EL_BD_FIREFLY_DOWN, 4 },
2285 { EL_YAMYAM_LEFT, 5 },
2286 { EL_YAMYAM_RIGHT, 5 },
2287 { EL_YAMYAM_UP, 5 },
2288 { EL_YAMYAM_DOWN, 5 },
2289 { EL_DARK_YAMYAM, 6 },
2292 { EL_PACMAN_LEFT, 8 },
2293 { EL_PACMAN_RIGHT, 8 },
2294 { EL_PACMAN_UP, 8 },
2295 { EL_PACMAN_DOWN, 8 },
2297 { EL_MOLE_LEFT, 9 },
2298 { EL_MOLE_RIGHT, 9 },
2300 { EL_MOLE_DOWN, 9 },
2304 { EL_SATELLITE, 13 },
2305 { EL_SP_SNIKSNAK, 14 },
2306 { EL_SP_ELECTRON, 15 },
2309 { EL_EMC_ANDROID, 18 },
2314 static struct PropertyBitInfo pb_dont_collide_with[] =
2316 { EL_SP_SNIKSNAK, 0 },
2317 { EL_SP_ELECTRON, 1 },
2325 struct PropertyBitInfo *pb_info;
2328 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2329 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2334 struct PropertyBitInfo *pb_info = NULL;
2337 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2338 if (pb_definition[i].bit_nr == property_bit_nr)
2339 pb_info = pb_definition[i].pb_info;
2341 if (pb_info == NULL)
2344 for (i = 0; pb_info[i].element != -1; i++)
2345 if (pb_info[i].element == element)
2346 return pb_info[i].bit_nr;
2351 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2352 boolean property_value)
2354 int bit_nr = get_special_property_bit(element, property_bit_nr);
2359 *bitfield |= (1 << bit_nr);
2361 *bitfield &= ~(1 << bit_nr);
2365 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2367 int bit_nr = get_special_property_bit(element, property_bit_nr);
2370 return ((*bitfield & (1 << bit_nr)) != 0);
2375 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2377 static int group_nr;
2378 static struct ElementGroupInfo *group;
2379 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2382 if (actual_group == NULL) /* not yet initialized */
2385 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2387 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2388 group_element - EL_GROUP_START + 1);
2390 /* replace element which caused too deep recursion by question mark */
2391 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2396 if (recursion_depth == 0) /* initialization */
2398 group = actual_group;
2399 group_nr = GROUP_NR(group_element);
2401 group->num_elements_resolved = 0;
2402 group->choice_pos = 0;
2404 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2405 element_info[i].in_group[group_nr] = FALSE;
2408 for (i = 0; i < actual_group->num_elements; i++)
2410 int element = actual_group->element[i];
2412 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2415 if (IS_GROUP_ELEMENT(element))
2416 ResolveGroupElementExt(element, recursion_depth + 1);
2419 group->element_resolved[group->num_elements_resolved++] = element;
2420 element_info[element].in_group[group_nr] = TRUE;
2425 void ResolveGroupElement(int group_element)
2427 ResolveGroupElementExt(group_element, 0);
2430 void InitElementPropertiesStatic()
2432 static boolean clipboard_elements_initialized = FALSE;
2434 static int ep_diggable[] =
2439 EL_SP_BUGGY_BASE_ACTIVATING,
2442 EL_INVISIBLE_SAND_ACTIVE,
2445 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2446 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2451 EL_SP_BUGGY_BASE_ACTIVE,
2458 static int ep_collectible_only[] =
2480 EL_DYNABOMB_INCREASE_NUMBER,
2481 EL_DYNABOMB_INCREASE_SIZE,
2482 EL_DYNABOMB_INCREASE_POWER,
2500 /* !!! handle separately !!! */
2501 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2507 static int ep_dont_run_into[] =
2509 /* same elements as in 'ep_dont_touch' */
2515 /* same elements as in 'ep_dont_collide_with' */
2527 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2532 EL_SP_BUGGY_BASE_ACTIVE,
2539 static int ep_dont_collide_with[] =
2541 /* same elements as in 'ep_dont_touch' */
2558 static int ep_dont_touch[] =
2568 static int ep_indestructible[] =
2572 EL_ACID_POOL_TOPLEFT,
2573 EL_ACID_POOL_TOPRIGHT,
2574 EL_ACID_POOL_BOTTOMLEFT,
2575 EL_ACID_POOL_BOTTOM,
2576 EL_ACID_POOL_BOTTOMRIGHT,
2577 EL_SP_HARDWARE_GRAY,
2578 EL_SP_HARDWARE_GREEN,
2579 EL_SP_HARDWARE_BLUE,
2581 EL_SP_HARDWARE_YELLOW,
2582 EL_SP_HARDWARE_BASE_1,
2583 EL_SP_HARDWARE_BASE_2,
2584 EL_SP_HARDWARE_BASE_3,
2585 EL_SP_HARDWARE_BASE_4,
2586 EL_SP_HARDWARE_BASE_5,
2587 EL_SP_HARDWARE_BASE_6,
2588 EL_INVISIBLE_STEELWALL,
2589 EL_INVISIBLE_STEELWALL_ACTIVE,
2590 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2591 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2592 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2593 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2594 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2595 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2596 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2597 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2598 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2599 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2600 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2601 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2603 EL_LIGHT_SWITCH_ACTIVE,
2604 EL_SIGN_EXCLAMATION,
2605 EL_SIGN_RADIOACTIVITY,
2612 EL_SIGN_ENTRY_FORBIDDEN,
2613 EL_SIGN_EMERGENCY_EXIT,
2621 EL_STEEL_EXIT_CLOSED,
2623 EL_STEEL_EXIT_OPENING,
2624 EL_STEEL_EXIT_CLOSING,
2625 EL_EM_STEEL_EXIT_CLOSED,
2626 EL_EM_STEEL_EXIT_OPEN,
2627 EL_EM_STEEL_EXIT_OPENING,
2628 EL_EM_STEEL_EXIT_CLOSING,
2629 EL_DC_STEELWALL_1_LEFT,
2630 EL_DC_STEELWALL_1_RIGHT,
2631 EL_DC_STEELWALL_1_TOP,
2632 EL_DC_STEELWALL_1_BOTTOM,
2633 EL_DC_STEELWALL_1_HORIZONTAL,
2634 EL_DC_STEELWALL_1_VERTICAL,
2635 EL_DC_STEELWALL_1_TOPLEFT,
2636 EL_DC_STEELWALL_1_TOPRIGHT,
2637 EL_DC_STEELWALL_1_BOTTOMLEFT,
2638 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2639 EL_DC_STEELWALL_1_TOPLEFT_2,
2640 EL_DC_STEELWALL_1_TOPRIGHT_2,
2641 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2642 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2643 EL_DC_STEELWALL_2_LEFT,
2644 EL_DC_STEELWALL_2_RIGHT,
2645 EL_DC_STEELWALL_2_TOP,
2646 EL_DC_STEELWALL_2_BOTTOM,
2647 EL_DC_STEELWALL_2_HORIZONTAL,
2648 EL_DC_STEELWALL_2_VERTICAL,
2649 EL_DC_STEELWALL_2_MIDDLE,
2650 EL_DC_STEELWALL_2_SINGLE,
2651 EL_STEELWALL_SLIPPERY,
2665 EL_GATE_1_GRAY_ACTIVE,
2666 EL_GATE_2_GRAY_ACTIVE,
2667 EL_GATE_3_GRAY_ACTIVE,
2668 EL_GATE_4_GRAY_ACTIVE,
2677 EL_EM_GATE_1_GRAY_ACTIVE,
2678 EL_EM_GATE_2_GRAY_ACTIVE,
2679 EL_EM_GATE_3_GRAY_ACTIVE,
2680 EL_EM_GATE_4_GRAY_ACTIVE,
2689 EL_EMC_GATE_5_GRAY_ACTIVE,
2690 EL_EMC_GATE_6_GRAY_ACTIVE,
2691 EL_EMC_GATE_7_GRAY_ACTIVE,
2692 EL_EMC_GATE_8_GRAY_ACTIVE,
2694 EL_DC_GATE_WHITE_GRAY,
2695 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2696 EL_DC_GATE_FAKE_GRAY,
2698 EL_SWITCHGATE_OPENING,
2699 EL_SWITCHGATE_CLOSED,
2700 EL_SWITCHGATE_CLOSING,
2701 EL_DC_SWITCHGATE_SWITCH_UP,
2702 EL_DC_SWITCHGATE_SWITCH_DOWN,
2704 EL_TIMEGATE_OPENING,
2706 EL_TIMEGATE_CLOSING,
2707 EL_DC_TIMEGATE_SWITCH,
2708 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2712 EL_TUBE_VERTICAL_LEFT,
2713 EL_TUBE_VERTICAL_RIGHT,
2714 EL_TUBE_HORIZONTAL_UP,
2715 EL_TUBE_HORIZONTAL_DOWN,
2720 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2721 EL_EXPANDABLE_STEELWALL_VERTICAL,
2722 EL_EXPANDABLE_STEELWALL_ANY,
2727 static int ep_slippery[] =
2741 EL_ROBOT_WHEEL_ACTIVE,
2747 EL_ACID_POOL_TOPLEFT,
2748 EL_ACID_POOL_TOPRIGHT,
2758 EL_STEELWALL_SLIPPERY,
2761 EL_EMC_WALL_SLIPPERY_1,
2762 EL_EMC_WALL_SLIPPERY_2,
2763 EL_EMC_WALL_SLIPPERY_3,
2764 EL_EMC_WALL_SLIPPERY_4,
2766 EL_EMC_MAGIC_BALL_ACTIVE,
2771 static int ep_can_change[] =
2776 static int ep_can_move[] =
2778 /* same elements as in 'pb_can_move_into_acid' */
2801 static int ep_can_fall[] =
2815 EL_QUICKSAND_FAST_FULL,
2817 EL_BD_MAGIC_WALL_FULL,
2818 EL_DC_MAGIC_WALL_FULL,
2832 static int ep_can_smash_player[] =
2858 static int ep_can_smash_enemies[] =
2867 static int ep_can_smash_everything[] =
2876 static int ep_explodes_by_fire[] =
2878 /* same elements as in 'ep_explodes_impact' */
2883 /* same elements as in 'ep_explodes_smashed' */
2893 EL_EM_DYNAMITE_ACTIVE,
2894 EL_DYNABOMB_PLAYER_1_ACTIVE,
2895 EL_DYNABOMB_PLAYER_2_ACTIVE,
2896 EL_DYNABOMB_PLAYER_3_ACTIVE,
2897 EL_DYNABOMB_PLAYER_4_ACTIVE,
2898 EL_DYNABOMB_INCREASE_NUMBER,
2899 EL_DYNABOMB_INCREASE_SIZE,
2900 EL_DYNABOMB_INCREASE_POWER,
2901 EL_SP_DISK_RED_ACTIVE,
2915 static int ep_explodes_smashed[] =
2917 /* same elements as in 'ep_explodes_impact' */
2931 static int ep_explodes_impact[] =
2940 static int ep_walkable_over[] =
2944 EL_SOKOBAN_FIELD_EMPTY,
2951 EL_EM_STEEL_EXIT_OPEN,
2952 EL_EM_STEEL_EXIT_OPENING,
2961 EL_GATE_1_GRAY_ACTIVE,
2962 EL_GATE_2_GRAY_ACTIVE,
2963 EL_GATE_3_GRAY_ACTIVE,
2964 EL_GATE_4_GRAY_ACTIVE,
2972 static int ep_walkable_inside[] =
2977 EL_TUBE_VERTICAL_LEFT,
2978 EL_TUBE_VERTICAL_RIGHT,
2979 EL_TUBE_HORIZONTAL_UP,
2980 EL_TUBE_HORIZONTAL_DOWN,
2989 static int ep_walkable_under[] =
2994 static int ep_passable_over[] =
3004 EL_EM_GATE_1_GRAY_ACTIVE,
3005 EL_EM_GATE_2_GRAY_ACTIVE,
3006 EL_EM_GATE_3_GRAY_ACTIVE,
3007 EL_EM_GATE_4_GRAY_ACTIVE,
3016 EL_EMC_GATE_5_GRAY_ACTIVE,
3017 EL_EMC_GATE_6_GRAY_ACTIVE,
3018 EL_EMC_GATE_7_GRAY_ACTIVE,
3019 EL_EMC_GATE_8_GRAY_ACTIVE,
3021 EL_DC_GATE_WHITE_GRAY,
3022 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3029 static int ep_passable_inside[] =
3035 EL_SP_PORT_HORIZONTAL,
3036 EL_SP_PORT_VERTICAL,
3038 EL_SP_GRAVITY_PORT_LEFT,
3039 EL_SP_GRAVITY_PORT_RIGHT,
3040 EL_SP_GRAVITY_PORT_UP,
3041 EL_SP_GRAVITY_PORT_DOWN,
3042 EL_SP_GRAVITY_ON_PORT_LEFT,
3043 EL_SP_GRAVITY_ON_PORT_RIGHT,
3044 EL_SP_GRAVITY_ON_PORT_UP,
3045 EL_SP_GRAVITY_ON_PORT_DOWN,
3046 EL_SP_GRAVITY_OFF_PORT_LEFT,
3047 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3048 EL_SP_GRAVITY_OFF_PORT_UP,
3049 EL_SP_GRAVITY_OFF_PORT_DOWN,
3054 static int ep_passable_under[] =
3059 static int ep_droppable[] =
3064 static int ep_explodes_1x1_old[] =
3069 static int ep_pushable[] =
3081 EL_SOKOBAN_FIELD_FULL,
3090 static int ep_explodes_cross_old[] =
3095 static int ep_protected[] =
3097 /* same elements as in 'ep_walkable_inside' */
3101 EL_TUBE_VERTICAL_LEFT,
3102 EL_TUBE_VERTICAL_RIGHT,
3103 EL_TUBE_HORIZONTAL_UP,
3104 EL_TUBE_HORIZONTAL_DOWN,
3110 /* same elements as in 'ep_passable_over' */
3119 EL_EM_GATE_1_GRAY_ACTIVE,
3120 EL_EM_GATE_2_GRAY_ACTIVE,
3121 EL_EM_GATE_3_GRAY_ACTIVE,
3122 EL_EM_GATE_4_GRAY_ACTIVE,
3131 EL_EMC_GATE_5_GRAY_ACTIVE,
3132 EL_EMC_GATE_6_GRAY_ACTIVE,
3133 EL_EMC_GATE_7_GRAY_ACTIVE,
3134 EL_EMC_GATE_8_GRAY_ACTIVE,
3136 EL_DC_GATE_WHITE_GRAY,
3137 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3141 /* same elements as in 'ep_passable_inside' */
3146 EL_SP_PORT_HORIZONTAL,
3147 EL_SP_PORT_VERTICAL,
3149 EL_SP_GRAVITY_PORT_LEFT,
3150 EL_SP_GRAVITY_PORT_RIGHT,
3151 EL_SP_GRAVITY_PORT_UP,
3152 EL_SP_GRAVITY_PORT_DOWN,
3153 EL_SP_GRAVITY_ON_PORT_LEFT,
3154 EL_SP_GRAVITY_ON_PORT_RIGHT,
3155 EL_SP_GRAVITY_ON_PORT_UP,
3156 EL_SP_GRAVITY_ON_PORT_DOWN,
3157 EL_SP_GRAVITY_OFF_PORT_LEFT,
3158 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3159 EL_SP_GRAVITY_OFF_PORT_UP,
3160 EL_SP_GRAVITY_OFF_PORT_DOWN,
3165 static int ep_throwable[] =
3170 static int ep_can_explode[] =
3172 /* same elements as in 'ep_explodes_impact' */
3177 /* same elements as in 'ep_explodes_smashed' */
3183 /* elements that can explode by explosion or by dragonfire */
3187 EL_EM_DYNAMITE_ACTIVE,
3188 EL_DYNABOMB_PLAYER_1_ACTIVE,
3189 EL_DYNABOMB_PLAYER_2_ACTIVE,
3190 EL_DYNABOMB_PLAYER_3_ACTIVE,
3191 EL_DYNABOMB_PLAYER_4_ACTIVE,
3192 EL_DYNABOMB_INCREASE_NUMBER,
3193 EL_DYNABOMB_INCREASE_SIZE,
3194 EL_DYNABOMB_INCREASE_POWER,
3195 EL_SP_DISK_RED_ACTIVE,
3203 /* elements that can explode only by explosion */
3209 static int ep_gravity_reachable[] =
3215 EL_INVISIBLE_SAND_ACTIVE,
3220 EL_SP_PORT_HORIZONTAL,
3221 EL_SP_PORT_VERTICAL,
3223 EL_SP_GRAVITY_PORT_LEFT,
3224 EL_SP_GRAVITY_PORT_RIGHT,
3225 EL_SP_GRAVITY_PORT_UP,
3226 EL_SP_GRAVITY_PORT_DOWN,
3227 EL_SP_GRAVITY_ON_PORT_LEFT,
3228 EL_SP_GRAVITY_ON_PORT_RIGHT,
3229 EL_SP_GRAVITY_ON_PORT_UP,
3230 EL_SP_GRAVITY_ON_PORT_DOWN,
3231 EL_SP_GRAVITY_OFF_PORT_LEFT,
3232 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3233 EL_SP_GRAVITY_OFF_PORT_UP,
3234 EL_SP_GRAVITY_OFF_PORT_DOWN,
3240 static int ep_player[] =
3247 EL_SOKOBAN_FIELD_PLAYER,
3253 static int ep_can_pass_magic_wall[] =
3267 static int ep_can_pass_dc_magic_wall[] =
3283 static int ep_switchable[] =
3287 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3288 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3289 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3290 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3291 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3292 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3293 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3294 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3295 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3296 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3297 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3298 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3299 EL_SWITCHGATE_SWITCH_UP,
3300 EL_SWITCHGATE_SWITCH_DOWN,
3301 EL_DC_SWITCHGATE_SWITCH_UP,
3302 EL_DC_SWITCHGATE_SWITCH_DOWN,
3304 EL_LIGHT_SWITCH_ACTIVE,
3306 EL_DC_TIMEGATE_SWITCH,
3307 EL_BALLOON_SWITCH_LEFT,
3308 EL_BALLOON_SWITCH_RIGHT,
3309 EL_BALLOON_SWITCH_UP,
3310 EL_BALLOON_SWITCH_DOWN,
3311 EL_BALLOON_SWITCH_ANY,
3312 EL_BALLOON_SWITCH_NONE,
3315 EL_EMC_MAGIC_BALL_SWITCH,
3316 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3321 static int ep_bd_element[] =
3355 static int ep_sp_element[] =
3357 /* should always be valid */
3360 /* standard classic Supaplex elements */
3367 EL_SP_HARDWARE_GRAY,
3375 EL_SP_GRAVITY_PORT_RIGHT,
3376 EL_SP_GRAVITY_PORT_DOWN,
3377 EL_SP_GRAVITY_PORT_LEFT,
3378 EL_SP_GRAVITY_PORT_UP,
3383 EL_SP_PORT_VERTICAL,
3384 EL_SP_PORT_HORIZONTAL,
3390 EL_SP_HARDWARE_BASE_1,
3391 EL_SP_HARDWARE_GREEN,
3392 EL_SP_HARDWARE_BLUE,
3394 EL_SP_HARDWARE_YELLOW,
3395 EL_SP_HARDWARE_BASE_2,
3396 EL_SP_HARDWARE_BASE_3,
3397 EL_SP_HARDWARE_BASE_4,
3398 EL_SP_HARDWARE_BASE_5,
3399 EL_SP_HARDWARE_BASE_6,
3403 /* additional elements that appeared in newer Supaplex levels */
3406 /* additional gravity port elements (not switching, but setting gravity) */
3407 EL_SP_GRAVITY_ON_PORT_LEFT,
3408 EL_SP_GRAVITY_ON_PORT_RIGHT,
3409 EL_SP_GRAVITY_ON_PORT_UP,
3410 EL_SP_GRAVITY_ON_PORT_DOWN,
3411 EL_SP_GRAVITY_OFF_PORT_LEFT,
3412 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3413 EL_SP_GRAVITY_OFF_PORT_UP,
3414 EL_SP_GRAVITY_OFF_PORT_DOWN,
3416 /* more than one Murphy in a level results in an inactive clone */
3419 /* runtime Supaplex elements */
3420 EL_SP_DISK_RED_ACTIVE,
3421 EL_SP_TERMINAL_ACTIVE,
3422 EL_SP_BUGGY_BASE_ACTIVATING,
3423 EL_SP_BUGGY_BASE_ACTIVE,
3430 static int ep_sb_element[] =
3435 EL_SOKOBAN_FIELD_EMPTY,
3436 EL_SOKOBAN_FIELD_FULL,
3437 EL_SOKOBAN_FIELD_PLAYER,
3442 EL_INVISIBLE_STEELWALL,
3447 static int ep_gem[] =
3459 static int ep_food_dark_yamyam[] =
3487 static int ep_food_penguin[] =
3501 static int ep_food_pig[] =
3513 static int ep_historic_wall[] =
3524 EL_GATE_1_GRAY_ACTIVE,
3525 EL_GATE_2_GRAY_ACTIVE,
3526 EL_GATE_3_GRAY_ACTIVE,
3527 EL_GATE_4_GRAY_ACTIVE,
3536 EL_EM_GATE_1_GRAY_ACTIVE,
3537 EL_EM_GATE_2_GRAY_ACTIVE,
3538 EL_EM_GATE_3_GRAY_ACTIVE,
3539 EL_EM_GATE_4_GRAY_ACTIVE,
3546 EL_EXPANDABLE_WALL_HORIZONTAL,
3547 EL_EXPANDABLE_WALL_VERTICAL,
3548 EL_EXPANDABLE_WALL_ANY,
3549 EL_EXPANDABLE_WALL_GROWING,
3550 EL_BD_EXPANDABLE_WALL,
3557 EL_SP_HARDWARE_GRAY,
3558 EL_SP_HARDWARE_GREEN,
3559 EL_SP_HARDWARE_BLUE,
3561 EL_SP_HARDWARE_YELLOW,
3562 EL_SP_HARDWARE_BASE_1,
3563 EL_SP_HARDWARE_BASE_2,
3564 EL_SP_HARDWARE_BASE_3,
3565 EL_SP_HARDWARE_BASE_4,
3566 EL_SP_HARDWARE_BASE_5,
3567 EL_SP_HARDWARE_BASE_6,
3569 EL_SP_TERMINAL_ACTIVE,
3572 EL_INVISIBLE_STEELWALL,
3573 EL_INVISIBLE_STEELWALL_ACTIVE,
3575 EL_INVISIBLE_WALL_ACTIVE,
3576 EL_STEELWALL_SLIPPERY,
3593 static int ep_historic_solid[] =
3597 EL_EXPANDABLE_WALL_HORIZONTAL,
3598 EL_EXPANDABLE_WALL_VERTICAL,
3599 EL_EXPANDABLE_WALL_ANY,
3600 EL_BD_EXPANDABLE_WALL,
3613 EL_QUICKSAND_FILLING,
3614 EL_QUICKSAND_EMPTYING,
3616 EL_MAGIC_WALL_ACTIVE,
3617 EL_MAGIC_WALL_EMPTYING,
3618 EL_MAGIC_WALL_FILLING,
3622 EL_BD_MAGIC_WALL_ACTIVE,
3623 EL_BD_MAGIC_WALL_EMPTYING,
3624 EL_BD_MAGIC_WALL_FULL,
3625 EL_BD_MAGIC_WALL_FILLING,
3626 EL_BD_MAGIC_WALL_DEAD,
3635 EL_SP_TERMINAL_ACTIVE,
3639 EL_INVISIBLE_WALL_ACTIVE,
3640 EL_SWITCHGATE_SWITCH_UP,
3641 EL_SWITCHGATE_SWITCH_DOWN,
3642 EL_DC_SWITCHGATE_SWITCH_UP,
3643 EL_DC_SWITCHGATE_SWITCH_DOWN,
3645 EL_TIMEGATE_SWITCH_ACTIVE,
3646 EL_DC_TIMEGATE_SWITCH,
3647 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3659 /* the following elements are a direct copy of "indestructible" elements,
3660 except "EL_ACID", which is "indestructible", but not "solid"! */
3665 EL_ACID_POOL_TOPLEFT,
3666 EL_ACID_POOL_TOPRIGHT,
3667 EL_ACID_POOL_BOTTOMLEFT,
3668 EL_ACID_POOL_BOTTOM,
3669 EL_ACID_POOL_BOTTOMRIGHT,
3670 EL_SP_HARDWARE_GRAY,
3671 EL_SP_HARDWARE_GREEN,
3672 EL_SP_HARDWARE_BLUE,
3674 EL_SP_HARDWARE_YELLOW,
3675 EL_SP_HARDWARE_BASE_1,
3676 EL_SP_HARDWARE_BASE_2,
3677 EL_SP_HARDWARE_BASE_3,
3678 EL_SP_HARDWARE_BASE_4,
3679 EL_SP_HARDWARE_BASE_5,
3680 EL_SP_HARDWARE_BASE_6,
3681 EL_INVISIBLE_STEELWALL,
3682 EL_INVISIBLE_STEELWALL_ACTIVE,
3683 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3684 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3685 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3686 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3687 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3688 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3689 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3690 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3691 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3692 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3693 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3694 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3696 EL_LIGHT_SWITCH_ACTIVE,
3697 EL_SIGN_EXCLAMATION,
3698 EL_SIGN_RADIOACTIVITY,
3705 EL_SIGN_ENTRY_FORBIDDEN,
3706 EL_SIGN_EMERGENCY_EXIT,
3714 EL_STEEL_EXIT_CLOSED,
3716 EL_DC_STEELWALL_1_LEFT,
3717 EL_DC_STEELWALL_1_RIGHT,
3718 EL_DC_STEELWALL_1_TOP,
3719 EL_DC_STEELWALL_1_BOTTOM,
3720 EL_DC_STEELWALL_1_HORIZONTAL,
3721 EL_DC_STEELWALL_1_VERTICAL,
3722 EL_DC_STEELWALL_1_TOPLEFT,
3723 EL_DC_STEELWALL_1_TOPRIGHT,
3724 EL_DC_STEELWALL_1_BOTTOMLEFT,
3725 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3726 EL_DC_STEELWALL_1_TOPLEFT_2,
3727 EL_DC_STEELWALL_1_TOPRIGHT_2,
3728 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3729 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3730 EL_DC_STEELWALL_2_LEFT,
3731 EL_DC_STEELWALL_2_RIGHT,
3732 EL_DC_STEELWALL_2_TOP,
3733 EL_DC_STEELWALL_2_BOTTOM,
3734 EL_DC_STEELWALL_2_HORIZONTAL,
3735 EL_DC_STEELWALL_2_VERTICAL,
3736 EL_DC_STEELWALL_2_MIDDLE,
3737 EL_DC_STEELWALL_2_SINGLE,
3738 EL_STEELWALL_SLIPPERY,
3752 EL_GATE_1_GRAY_ACTIVE,
3753 EL_GATE_2_GRAY_ACTIVE,
3754 EL_GATE_3_GRAY_ACTIVE,
3755 EL_GATE_4_GRAY_ACTIVE,
3764 EL_EM_GATE_1_GRAY_ACTIVE,
3765 EL_EM_GATE_2_GRAY_ACTIVE,
3766 EL_EM_GATE_3_GRAY_ACTIVE,
3767 EL_EM_GATE_4_GRAY_ACTIVE,
3769 EL_SWITCHGATE_OPENING,
3770 EL_SWITCHGATE_CLOSED,
3771 EL_SWITCHGATE_CLOSING,
3773 EL_TIMEGATE_OPENING,
3775 EL_TIMEGATE_CLOSING,
3779 EL_TUBE_VERTICAL_LEFT,
3780 EL_TUBE_VERTICAL_RIGHT,
3781 EL_TUBE_HORIZONTAL_UP,
3782 EL_TUBE_HORIZONTAL_DOWN,
3791 static int ep_classic_enemy[] =
3808 static int ep_belt[] =
3810 EL_CONVEYOR_BELT_1_LEFT,
3811 EL_CONVEYOR_BELT_1_MIDDLE,
3812 EL_CONVEYOR_BELT_1_RIGHT,
3813 EL_CONVEYOR_BELT_2_LEFT,
3814 EL_CONVEYOR_BELT_2_MIDDLE,
3815 EL_CONVEYOR_BELT_2_RIGHT,
3816 EL_CONVEYOR_BELT_3_LEFT,
3817 EL_CONVEYOR_BELT_3_MIDDLE,
3818 EL_CONVEYOR_BELT_3_RIGHT,
3819 EL_CONVEYOR_BELT_4_LEFT,
3820 EL_CONVEYOR_BELT_4_MIDDLE,
3821 EL_CONVEYOR_BELT_4_RIGHT,
3826 static int ep_belt_active[] =
3828 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3829 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3830 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3831 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3832 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3833 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3834 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3835 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3836 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3837 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3838 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3839 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3844 static int ep_belt_switch[] =
3846 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3847 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3848 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3849 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3850 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3851 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3852 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3853 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3854 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3855 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3856 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3857 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3862 static int ep_tube[] =
3869 EL_TUBE_HORIZONTAL_UP,
3870 EL_TUBE_HORIZONTAL_DOWN,
3872 EL_TUBE_VERTICAL_LEFT,
3873 EL_TUBE_VERTICAL_RIGHT,
3879 static int ep_acid_pool[] =
3881 EL_ACID_POOL_TOPLEFT,
3882 EL_ACID_POOL_TOPRIGHT,
3883 EL_ACID_POOL_BOTTOMLEFT,
3884 EL_ACID_POOL_BOTTOM,
3885 EL_ACID_POOL_BOTTOMRIGHT,
3890 static int ep_keygate[] =
3900 EL_GATE_1_GRAY_ACTIVE,
3901 EL_GATE_2_GRAY_ACTIVE,
3902 EL_GATE_3_GRAY_ACTIVE,
3903 EL_GATE_4_GRAY_ACTIVE,
3912 EL_EM_GATE_1_GRAY_ACTIVE,
3913 EL_EM_GATE_2_GRAY_ACTIVE,
3914 EL_EM_GATE_3_GRAY_ACTIVE,
3915 EL_EM_GATE_4_GRAY_ACTIVE,
3924 EL_EMC_GATE_5_GRAY_ACTIVE,
3925 EL_EMC_GATE_6_GRAY_ACTIVE,
3926 EL_EMC_GATE_7_GRAY_ACTIVE,
3927 EL_EMC_GATE_8_GRAY_ACTIVE,
3929 EL_DC_GATE_WHITE_GRAY,
3930 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3935 static int ep_amoeboid[] =
3947 static int ep_amoebalive[] =
3958 static int ep_has_editor_content[] =
3964 EL_SOKOBAN_FIELD_PLAYER,
3981 static int ep_can_turn_each_move[] =
3983 /* !!! do something with this one !!! */
3987 static int ep_can_grow[] =
4001 static int ep_active_bomb[] =
4004 EL_EM_DYNAMITE_ACTIVE,
4005 EL_DYNABOMB_PLAYER_1_ACTIVE,
4006 EL_DYNABOMB_PLAYER_2_ACTIVE,
4007 EL_DYNABOMB_PLAYER_3_ACTIVE,
4008 EL_DYNABOMB_PLAYER_4_ACTIVE,
4009 EL_SP_DISK_RED_ACTIVE,
4014 static int ep_inactive[] =
4024 EL_QUICKSAND_FAST_EMPTY,
4047 EL_GATE_1_GRAY_ACTIVE,
4048 EL_GATE_2_GRAY_ACTIVE,
4049 EL_GATE_3_GRAY_ACTIVE,
4050 EL_GATE_4_GRAY_ACTIVE,
4059 EL_EM_GATE_1_GRAY_ACTIVE,
4060 EL_EM_GATE_2_GRAY_ACTIVE,
4061 EL_EM_GATE_3_GRAY_ACTIVE,
4062 EL_EM_GATE_4_GRAY_ACTIVE,
4071 EL_EMC_GATE_5_GRAY_ACTIVE,
4072 EL_EMC_GATE_6_GRAY_ACTIVE,
4073 EL_EMC_GATE_7_GRAY_ACTIVE,
4074 EL_EMC_GATE_8_GRAY_ACTIVE,
4076 EL_DC_GATE_WHITE_GRAY,
4077 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4078 EL_DC_GATE_FAKE_GRAY,
4081 EL_INVISIBLE_STEELWALL,
4089 EL_WALL_EMERALD_YELLOW,
4090 EL_DYNABOMB_INCREASE_NUMBER,
4091 EL_DYNABOMB_INCREASE_SIZE,
4092 EL_DYNABOMB_INCREASE_POWER,
4096 EL_SOKOBAN_FIELD_EMPTY,
4097 EL_SOKOBAN_FIELD_FULL,
4098 EL_WALL_EMERALD_RED,
4099 EL_WALL_EMERALD_PURPLE,
4100 EL_ACID_POOL_TOPLEFT,
4101 EL_ACID_POOL_TOPRIGHT,
4102 EL_ACID_POOL_BOTTOMLEFT,
4103 EL_ACID_POOL_BOTTOM,
4104 EL_ACID_POOL_BOTTOMRIGHT,
4108 EL_BD_MAGIC_WALL_DEAD,
4110 EL_DC_MAGIC_WALL_DEAD,
4111 EL_AMOEBA_TO_DIAMOND,
4119 EL_SP_GRAVITY_PORT_RIGHT,
4120 EL_SP_GRAVITY_PORT_DOWN,
4121 EL_SP_GRAVITY_PORT_LEFT,
4122 EL_SP_GRAVITY_PORT_UP,
4123 EL_SP_PORT_HORIZONTAL,
4124 EL_SP_PORT_VERTICAL,
4135 EL_SP_HARDWARE_GRAY,
4136 EL_SP_HARDWARE_GREEN,
4137 EL_SP_HARDWARE_BLUE,
4139 EL_SP_HARDWARE_YELLOW,
4140 EL_SP_HARDWARE_BASE_1,
4141 EL_SP_HARDWARE_BASE_2,
4142 EL_SP_HARDWARE_BASE_3,
4143 EL_SP_HARDWARE_BASE_4,
4144 EL_SP_HARDWARE_BASE_5,
4145 EL_SP_HARDWARE_BASE_6,
4146 EL_SP_GRAVITY_ON_PORT_LEFT,
4147 EL_SP_GRAVITY_ON_PORT_RIGHT,
4148 EL_SP_GRAVITY_ON_PORT_UP,
4149 EL_SP_GRAVITY_ON_PORT_DOWN,
4150 EL_SP_GRAVITY_OFF_PORT_LEFT,
4151 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4152 EL_SP_GRAVITY_OFF_PORT_UP,
4153 EL_SP_GRAVITY_OFF_PORT_DOWN,
4154 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4155 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4156 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4157 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4158 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4159 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4160 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4161 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4162 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4163 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4164 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4165 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4166 EL_SIGN_EXCLAMATION,
4167 EL_SIGN_RADIOACTIVITY,
4174 EL_SIGN_ENTRY_FORBIDDEN,
4175 EL_SIGN_EMERGENCY_EXIT,
4183 EL_DC_STEELWALL_1_LEFT,
4184 EL_DC_STEELWALL_1_RIGHT,
4185 EL_DC_STEELWALL_1_TOP,
4186 EL_DC_STEELWALL_1_BOTTOM,
4187 EL_DC_STEELWALL_1_HORIZONTAL,
4188 EL_DC_STEELWALL_1_VERTICAL,
4189 EL_DC_STEELWALL_1_TOPLEFT,
4190 EL_DC_STEELWALL_1_TOPRIGHT,
4191 EL_DC_STEELWALL_1_BOTTOMLEFT,
4192 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4193 EL_DC_STEELWALL_1_TOPLEFT_2,
4194 EL_DC_STEELWALL_1_TOPRIGHT_2,
4195 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4196 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4197 EL_DC_STEELWALL_2_LEFT,
4198 EL_DC_STEELWALL_2_RIGHT,
4199 EL_DC_STEELWALL_2_TOP,
4200 EL_DC_STEELWALL_2_BOTTOM,
4201 EL_DC_STEELWALL_2_HORIZONTAL,
4202 EL_DC_STEELWALL_2_VERTICAL,
4203 EL_DC_STEELWALL_2_MIDDLE,
4204 EL_DC_STEELWALL_2_SINGLE,
4205 EL_STEELWALL_SLIPPERY,
4210 EL_EMC_WALL_SLIPPERY_1,
4211 EL_EMC_WALL_SLIPPERY_2,
4212 EL_EMC_WALL_SLIPPERY_3,
4213 EL_EMC_WALL_SLIPPERY_4,
4234 static int ep_em_slippery_wall[] =
4239 static int ep_gfx_crumbled[] =
4250 static int ep_editor_cascade_active[] =
4252 EL_INTERNAL_CASCADE_BD_ACTIVE,
4253 EL_INTERNAL_CASCADE_EM_ACTIVE,
4254 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4255 EL_INTERNAL_CASCADE_RND_ACTIVE,
4256 EL_INTERNAL_CASCADE_SB_ACTIVE,
4257 EL_INTERNAL_CASCADE_SP_ACTIVE,
4258 EL_INTERNAL_CASCADE_DC_ACTIVE,
4259 EL_INTERNAL_CASCADE_DX_ACTIVE,
4260 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4261 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4262 EL_INTERNAL_CASCADE_CE_ACTIVE,
4263 EL_INTERNAL_CASCADE_GE_ACTIVE,
4264 EL_INTERNAL_CASCADE_REF_ACTIVE,
4265 EL_INTERNAL_CASCADE_USER_ACTIVE,
4266 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4271 static int ep_editor_cascade_inactive[] =
4273 EL_INTERNAL_CASCADE_BD,
4274 EL_INTERNAL_CASCADE_EM,
4275 EL_INTERNAL_CASCADE_EMC,
4276 EL_INTERNAL_CASCADE_RND,
4277 EL_INTERNAL_CASCADE_SB,
4278 EL_INTERNAL_CASCADE_SP,
4279 EL_INTERNAL_CASCADE_DC,
4280 EL_INTERNAL_CASCADE_DX,
4281 EL_INTERNAL_CASCADE_CHARS,
4282 EL_INTERNAL_CASCADE_STEEL_CHARS,
4283 EL_INTERNAL_CASCADE_CE,
4284 EL_INTERNAL_CASCADE_GE,
4285 EL_INTERNAL_CASCADE_REF,
4286 EL_INTERNAL_CASCADE_USER,
4287 EL_INTERNAL_CASCADE_DYNAMIC,
4292 static int ep_obsolete[] =
4296 EL_EM_KEY_1_FILE_OBSOLETE,
4297 EL_EM_KEY_2_FILE_OBSOLETE,
4298 EL_EM_KEY_3_FILE_OBSOLETE,
4299 EL_EM_KEY_4_FILE_OBSOLETE,
4300 EL_ENVELOPE_OBSOLETE,
4309 } element_properties[] =
4311 { ep_diggable, EP_DIGGABLE },
4312 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4313 { ep_dont_run_into, EP_DONT_RUN_INTO },
4314 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4315 { ep_dont_touch, EP_DONT_TOUCH },
4316 { ep_indestructible, EP_INDESTRUCTIBLE },
4317 { ep_slippery, EP_SLIPPERY },
4318 { ep_can_change, EP_CAN_CHANGE },
4319 { ep_can_move, EP_CAN_MOVE },
4320 { ep_can_fall, EP_CAN_FALL },
4321 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4322 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4323 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4324 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4325 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4326 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4327 { ep_walkable_over, EP_WALKABLE_OVER },
4328 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4329 { ep_walkable_under, EP_WALKABLE_UNDER },
4330 { ep_passable_over, EP_PASSABLE_OVER },
4331 { ep_passable_inside, EP_PASSABLE_INSIDE },
4332 { ep_passable_under, EP_PASSABLE_UNDER },
4333 { ep_droppable, EP_DROPPABLE },
4334 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4335 { ep_pushable, EP_PUSHABLE },
4336 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4337 { ep_protected, EP_PROTECTED },
4338 { ep_throwable, EP_THROWABLE },
4339 { ep_can_explode, EP_CAN_EXPLODE },
4340 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4342 { ep_player, EP_PLAYER },
4343 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4344 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4345 { ep_switchable, EP_SWITCHABLE },
4346 { ep_bd_element, EP_BD_ELEMENT },
4347 { ep_sp_element, EP_SP_ELEMENT },
4348 { ep_sb_element, EP_SB_ELEMENT },
4350 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4351 { ep_food_penguin, EP_FOOD_PENGUIN },
4352 { ep_food_pig, EP_FOOD_PIG },
4353 { ep_historic_wall, EP_HISTORIC_WALL },
4354 { ep_historic_solid, EP_HISTORIC_SOLID },
4355 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4356 { ep_belt, EP_BELT },
4357 { ep_belt_active, EP_BELT_ACTIVE },
4358 { ep_belt_switch, EP_BELT_SWITCH },
4359 { ep_tube, EP_TUBE },
4360 { ep_acid_pool, EP_ACID_POOL },
4361 { ep_keygate, EP_KEYGATE },
4362 { ep_amoeboid, EP_AMOEBOID },
4363 { ep_amoebalive, EP_AMOEBALIVE },
4364 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4365 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4366 { ep_can_grow, EP_CAN_GROW },
4367 { ep_active_bomb, EP_ACTIVE_BOMB },
4368 { ep_inactive, EP_INACTIVE },
4370 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4372 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4374 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4375 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4377 { ep_obsolete, EP_OBSOLETE },
4384 /* always start with reliable default values (element has no properties) */
4385 /* (but never initialize clipboard elements after the very first time) */
4386 /* (to be able to use clipboard elements between several levels) */
4387 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4388 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4389 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4390 SET_PROPERTY(i, j, FALSE);
4392 /* set all base element properties from above array definitions */
4393 for (i = 0; element_properties[i].elements != NULL; i++)
4394 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4395 SET_PROPERTY((element_properties[i].elements)[j],
4396 element_properties[i].property, TRUE);
4398 /* copy properties to some elements that are only stored in level file */
4399 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4400 for (j = 0; copy_properties[j][0] != -1; j++)
4401 if (HAS_PROPERTY(copy_properties[j][0], i))
4402 for (k = 1; k <= 4; k++)
4403 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4405 /* set static element properties that are not listed in array definitions */
4406 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4407 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4409 clipboard_elements_initialized = TRUE;
4412 void InitElementPropertiesEngine(int engine_version)
4414 static int no_wall_properties[] =
4417 EP_COLLECTIBLE_ONLY,
4419 EP_DONT_COLLIDE_WITH,
4422 EP_CAN_SMASH_PLAYER,
4423 EP_CAN_SMASH_ENEMIES,
4424 EP_CAN_SMASH_EVERYTHING,
4429 EP_FOOD_DARK_YAMYAM,
4445 /* important: after initialization in InitElementPropertiesStatic(), the
4446 elements are not again initialized to a default value; therefore all
4447 changes have to make sure that they leave the element with a defined
4448 property (which means that conditional property changes must be set to
4449 a reliable default value before) */
4451 /* resolve group elements */
4452 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4453 ResolveGroupElement(EL_GROUP_START + i);
4455 /* set all special, combined or engine dependent element properties */
4456 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4458 /* do not change (already initialized) clipboard elements here */
4459 if (IS_CLIPBOARD_ELEMENT(i))
4462 /* ---------- INACTIVE ------------------------------------------------- */
4463 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4464 i <= EL_CHAR_END) ||
4465 (i >= EL_STEEL_CHAR_START &&
4466 i <= EL_STEEL_CHAR_END)));
4468 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4469 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4470 IS_WALKABLE_INSIDE(i) ||
4471 IS_WALKABLE_UNDER(i)));
4473 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4474 IS_PASSABLE_INSIDE(i) ||
4475 IS_PASSABLE_UNDER(i)));
4477 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4478 IS_PASSABLE_OVER(i)));
4480 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4481 IS_PASSABLE_INSIDE(i)));
4483 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4484 IS_PASSABLE_UNDER(i)));
4486 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4489 /* ---------- COLLECTIBLE ---------------------------------------------- */
4490 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4494 /* ---------- SNAPPABLE ------------------------------------------------ */
4495 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4496 IS_COLLECTIBLE(i) ||
4500 /* ---------- WALL ----------------------------------------------------- */
4501 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4503 for (j = 0; no_wall_properties[j] != -1; j++)
4504 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4505 i >= EL_FIRST_RUNTIME_UNREAL)
4506 SET_PROPERTY(i, EP_WALL, FALSE);
4508 if (IS_HISTORIC_WALL(i))
4509 SET_PROPERTY(i, EP_WALL, TRUE);
4511 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4512 if (engine_version < VERSION_IDENT(2,2,0,0))
4513 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4515 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4517 !IS_COLLECTIBLE(i)));
4519 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4520 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4521 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4523 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4524 IS_INDESTRUCTIBLE(i)));
4526 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4528 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4529 else if (engine_version < VERSION_IDENT(2,2,0,0))
4530 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4532 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4536 if (IS_CUSTOM_ELEMENT(i))
4538 /* these are additional properties which are initially false when set */
4540 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4542 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4543 if (DONT_COLLIDE_WITH(i))
4544 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4546 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4547 if (CAN_SMASH_EVERYTHING(i))
4548 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4549 if (CAN_SMASH_ENEMIES(i))
4550 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4553 /* ---------- CAN_SMASH ------------------------------------------------ */
4554 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4555 CAN_SMASH_ENEMIES(i) ||
4556 CAN_SMASH_EVERYTHING(i)));
4558 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4559 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4560 EXPLODES_BY_FIRE(i)));
4562 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4563 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4564 EXPLODES_SMASHED(i)));
4566 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4567 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4568 EXPLODES_IMPACT(i)));
4570 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4571 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4573 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4574 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4575 i == EL_BLACK_ORB));
4577 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4578 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4580 IS_CUSTOM_ELEMENT(i)));
4582 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4583 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4584 i == EL_SP_ELECTRON));
4586 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4587 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4588 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4589 getMoveIntoAcidProperty(&level, i));
4591 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4592 if (MAYBE_DONT_COLLIDE_WITH(i))
4593 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4594 getDontCollideWithProperty(&level, i));
4596 /* ---------- SP_PORT -------------------------------------------------- */
4597 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4598 IS_PASSABLE_INSIDE(i)));
4600 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4601 for (j = 0; j < level.num_android_clone_elements; j++)
4602 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4604 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4606 /* ---------- CAN_CHANGE ----------------------------------------------- */
4607 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4608 for (j = 0; j < element_info[i].num_change_pages; j++)
4609 if (element_info[i].change_page[j].can_change)
4610 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4612 /* ---------- HAS_ACTION ----------------------------------------------- */
4613 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4614 for (j = 0; j < element_info[i].num_change_pages; j++)
4615 if (element_info[i].change_page[j].has_action)
4616 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4618 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4619 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4622 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4623 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4624 element_info[i].crumbled[ACTION_DEFAULT] !=
4625 element_info[i].graphic[ACTION_DEFAULT]);
4627 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4628 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4629 IS_EDITOR_CASCADE_INACTIVE(i)));
4632 /* dynamically adjust element properties according to game engine version */
4634 static int ep_em_slippery_wall[] =
4639 EL_EXPANDABLE_WALL_HORIZONTAL,
4640 EL_EXPANDABLE_WALL_VERTICAL,
4641 EL_EXPANDABLE_WALL_ANY,
4642 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4643 EL_EXPANDABLE_STEELWALL_VERTICAL,
4644 EL_EXPANDABLE_STEELWALL_ANY,
4645 EL_EXPANDABLE_STEELWALL_GROWING,
4649 static int ep_em_explodes_by_fire[] =
4652 EL_EM_DYNAMITE_ACTIVE,
4657 /* special EM style gems behaviour */
4658 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4659 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4660 level.em_slippery_gems);
4662 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4663 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4664 (level.em_slippery_gems &&
4665 engine_version > VERSION_IDENT(2,0,1,0)));
4667 /* special EM style explosion behaviour regarding chain reactions */
4668 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4669 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4670 level.em_explodes_by_fire);
4673 /* this is needed because some graphics depend on element properties */
4674 if (game_status == GAME_MODE_PLAYING)
4675 InitElementGraphicInfo();
4678 void InitElementPropertiesAfterLoading(int engine_version)
4682 /* set some other uninitialized values of custom elements in older levels */
4683 if (engine_version < VERSION_IDENT(3,1,0,0))
4685 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4687 int element = EL_CUSTOM_START + i;
4689 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4691 element_info[element].explosion_delay = 17;
4692 element_info[element].ignition_delay = 8;
4697 void InitElementPropertiesGfxElement()
4701 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4703 struct ElementInfo *ei = &element_info[i];
4705 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4709 static void InitGlobal()
4714 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4716 /* check if element_name_info entry defined for each element in "main.h" */
4717 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4718 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4720 element_info[i].token_name = element_name_info[i].token_name;
4721 element_info[i].class_name = element_name_info[i].class_name;
4722 element_info[i].editor_description= element_name_info[i].editor_description;
4725 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4727 /* check if global_anim_name_info defined for each entry in "main.h" */
4728 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4729 global_anim_name_info[i].token_name == NULL)
4730 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4732 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4735 /* create hash from image config list */
4736 image_config_hash = newSetupFileHash();
4737 for (i = 0; image_config[i].token != NULL; i++)
4738 setHashEntry(image_config_hash,
4739 image_config[i].token,
4740 image_config[i].value);
4742 /* create hash from element token list */
4743 element_token_hash = newSetupFileHash();
4744 for (i = 0; element_name_info[i].token_name != NULL; i++)
4745 setHashEntry(element_token_hash,
4746 element_name_info[i].token_name,
4749 /* create hash from graphic token list */
4750 graphic_token_hash = newSetupFileHash();
4751 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4752 if (strSuffix(image_config[i].value, ".png") ||
4753 strSuffix(image_config[i].value, ".pcx") ||
4754 strSuffix(image_config[i].value, ".wav") ||
4755 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4756 setHashEntry(graphic_token_hash,
4757 image_config[i].token,
4758 int2str(graphic++, 0));
4760 /* create hash from font token list */
4761 font_token_hash = newSetupFileHash();
4762 for (i = 0; font_info[i].token_name != NULL; i++)
4763 setHashEntry(font_token_hash,
4764 font_info[i].token_name,
4767 /* set default filenames for all cloned graphics in static configuration */
4768 for (i = 0; image_config[i].token != NULL; i++)
4770 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4772 char *token = image_config[i].token;
4773 char *token_clone_from = getStringCat2(token, ".clone_from");
4774 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4776 if (token_cloned != NULL)
4778 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4780 if (value_cloned != NULL)
4782 /* set default filename in static configuration */
4783 image_config[i].value = value_cloned;
4785 /* set default filename in image config hash */
4786 setHashEntry(image_config_hash, token, value_cloned);
4790 free(token_clone_from);
4794 /* always start with reliable default values (all elements) */
4795 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4796 ActiveElement[i] = i;
4798 /* now add all entries that have an active state (active elements) */
4799 for (i = 0; element_with_active_state[i].element != -1; i++)
4801 int element = element_with_active_state[i].element;
4802 int element_active = element_with_active_state[i].element_active;
4804 ActiveElement[element] = element_active;
4807 /* always start with reliable default values (all buttons) */
4808 for (i = 0; i < NUM_IMAGE_FILES; i++)
4809 ActiveButton[i] = i;
4811 /* now add all entries that have an active state (active buttons) */
4812 for (i = 0; button_with_active_state[i].button != -1; i++)
4814 int button = button_with_active_state[i].button;
4815 int button_active = button_with_active_state[i].button_active;
4817 ActiveButton[button] = button_active;
4820 /* always start with reliable default values (all fonts) */
4821 for (i = 0; i < NUM_FONTS; i++)
4824 /* now add all entries that have an active state (active fonts) */
4825 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4827 int font = font_with_active_state[i].font_nr;
4828 int font_active = font_with_active_state[i].font_nr_active;
4830 ActiveFont[font] = font_active;
4833 global.autoplay_leveldir = NULL;
4834 global.convert_leveldir = NULL;
4835 global.create_images_dir = NULL;
4837 global.frames_per_second = 0;
4838 global.show_frames_per_second = FALSE;
4840 global.border_status = GAME_MODE_LOADING;
4841 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4843 global.use_envelope_request = FALSE;
4846 void Execute_Command(char *command)
4850 if (strEqual(command, "print graphicsinfo.conf"))
4852 Print("# You can configure additional/alternative image files here.\n");
4853 Print("# (The entries below are default and therefore commented out.)\n");
4855 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4857 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4860 for (i = 0; image_config[i].token != NULL; i++)
4861 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4862 image_config[i].value));
4866 else if (strEqual(command, "print soundsinfo.conf"))
4868 Print("# You can configure additional/alternative sound files here.\n");
4869 Print("# (The entries below are default and therefore commented out.)\n");
4871 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4873 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4876 for (i = 0; sound_config[i].token != NULL; i++)
4877 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4878 sound_config[i].value));
4882 else if (strEqual(command, "print musicinfo.conf"))
4884 Print("# You can configure additional/alternative music files here.\n");
4885 Print("# (The entries below are default and therefore commented out.)\n");
4887 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4889 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4892 for (i = 0; music_config[i].token != NULL; i++)
4893 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4894 music_config[i].value));
4898 else if (strEqual(command, "print editorsetup.conf"))
4900 Print("# You can configure your personal editor element list here.\n");
4901 Print("# (The entries below are default and therefore commented out.)\n");
4904 /* this is needed to be able to check element list for cascade elements */
4905 InitElementPropertiesStatic();
4906 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4908 PrintEditorElementList();
4912 else if (strEqual(command, "print helpanim.conf"))
4914 Print("# You can configure different element help animations here.\n");
4915 Print("# (The entries below are default and therefore commented out.)\n");
4918 for (i = 0; helpanim_config[i].token != NULL; i++)
4920 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4921 helpanim_config[i].value));
4923 if (strEqual(helpanim_config[i].token, "end"))
4929 else if (strEqual(command, "print helptext.conf"))
4931 Print("# You can configure different element help text here.\n");
4932 Print("# (The entries below are default and therefore commented out.)\n");
4935 for (i = 0; helptext_config[i].token != NULL; i++)
4936 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4937 helptext_config[i].value));
4941 else if (strPrefix(command, "dump level "))
4943 char *filename = &command[11];
4945 if (!fileExists(filename))
4946 Error(ERR_EXIT, "cannot open file '%s'", filename);
4948 LoadLevelFromFilename(&level, filename);
4953 else if (strPrefix(command, "dump tape "))
4955 char *filename = &command[10];
4957 if (!fileExists(filename))
4958 Error(ERR_EXIT, "cannot open file '%s'", filename);
4960 LoadTapeFromFilename(filename);
4965 else if (strPrefix(command, "autotest ") ||
4966 strPrefix(command, "autoplay ") ||
4967 strPrefix(command, "autoffwd ") ||
4968 strPrefix(command, "autowarp "))
4970 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4972 global.autoplay_mode =
4973 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
4974 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
4975 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
4976 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
4977 AUTOPLAY_MODE_NONE);
4979 while (*str_ptr != '\0') /* continue parsing string */
4981 /* cut leading whitespace from string, replace it by string terminator */
4982 while (*str_ptr == ' ' || *str_ptr == '\t')
4985 if (*str_ptr == '\0') /* end of string reached */
4988 if (global.autoplay_leveldir == NULL) /* read level set string */
4990 global.autoplay_leveldir = str_ptr;
4991 global.autoplay_all = TRUE; /* default: play all tapes */
4993 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4994 global.autoplay_level[i] = FALSE;
4996 else /* read level number string */
4998 int level_nr = atoi(str_ptr); /* get level_nr value */
5000 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5001 global.autoplay_level[level_nr] = TRUE;
5003 global.autoplay_all = FALSE;
5006 /* advance string pointer to the next whitespace (or end of string) */
5007 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5011 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5012 program.headless = TRUE;
5014 else if (strPrefix(command, "convert "))
5016 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5017 char *str_ptr = strchr(str_copy, ' ');
5019 global.convert_leveldir = str_copy;
5020 global.convert_level_nr = -1;
5022 if (str_ptr != NULL) /* level number follows */
5024 *str_ptr++ = '\0'; /* terminate leveldir string */
5025 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5028 program.headless = TRUE;
5030 else if (strPrefix(command, "create images "))
5032 global.create_images_dir = getStringCopy(&command[14]);
5034 if (access(global.create_images_dir, W_OK) != 0)
5035 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5036 global.create_images_dir);
5038 else if (strPrefix(command, "create CE image "))
5040 CreateCustomElementImages(&command[16]);
5046 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5050 static void InitSetup()
5052 LoadSetup(); /* global setup info */
5054 /* set some options from setup file */
5056 if (setup.options.verbose)
5057 options.verbose = TRUE;
5059 if (setup.debug.show_frames_per_second)
5060 global.show_frames_per_second = TRUE;
5063 static void InitGameInfo()
5065 game.restart_level = FALSE;
5068 static void InitPlayerInfo()
5072 /* choose default local player */
5073 local_player = &stored_player[0];
5075 for (i = 0; i < MAX_PLAYERS; i++)
5076 stored_player[i].connected = FALSE;
5078 local_player->connected = TRUE;
5081 static void InitArtworkInfo()
5086 static char *get_string_in_brackets(char *string)
5088 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5090 sprintf(string_in_brackets, "[%s]", string);
5092 return string_in_brackets;
5095 static char *get_level_id_suffix(int id_nr)
5097 char *id_suffix = checked_malloc(1 + 3 + 1);
5099 if (id_nr < 0 || id_nr > 999)
5102 sprintf(id_suffix, ".%03d", id_nr);
5107 static void InitArtworkConfig()
5109 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5111 NUM_GLOBAL_ANIM_TOKENS + 1];
5112 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5113 NUM_GLOBAL_ANIM_TOKENS + 1];
5114 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5115 NUM_GLOBAL_ANIM_TOKENS + 1];
5116 static char *action_id_suffix[NUM_ACTIONS + 1];
5117 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5118 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5119 static char *level_id_suffix[MAX_LEVELS + 1];
5120 static char *dummy[1] = { NULL };
5121 static char *ignore_generic_tokens[] =
5127 static char **ignore_image_tokens;
5128 static char **ignore_sound_tokens;
5129 static char **ignore_music_tokens;
5130 int num_ignore_generic_tokens;
5131 int num_ignore_image_tokens;
5132 int num_ignore_sound_tokens;
5133 int num_ignore_music_tokens;
5136 /* dynamically determine list of generic tokens to be ignored */
5137 num_ignore_generic_tokens = 0;
5138 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5139 num_ignore_generic_tokens++;
5141 /* dynamically determine list of image tokens to be ignored */
5142 num_ignore_image_tokens = num_ignore_generic_tokens;
5143 for (i = 0; image_config_vars[i].token != NULL; i++)
5144 num_ignore_image_tokens++;
5145 ignore_image_tokens =
5146 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5147 for (i = 0; i < num_ignore_generic_tokens; i++)
5148 ignore_image_tokens[i] = ignore_generic_tokens[i];
5149 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5150 ignore_image_tokens[num_ignore_generic_tokens + i] =
5151 image_config_vars[i].token;
5152 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5154 /* dynamically determine list of sound tokens to be ignored */
5155 num_ignore_sound_tokens = num_ignore_generic_tokens;
5156 ignore_sound_tokens =
5157 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5158 for (i = 0; i < num_ignore_generic_tokens; i++)
5159 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5160 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5162 /* dynamically determine list of music tokens to be ignored */
5163 num_ignore_music_tokens = num_ignore_generic_tokens;
5164 ignore_music_tokens =
5165 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5166 for (i = 0; i < num_ignore_generic_tokens; i++)
5167 ignore_music_tokens[i] = ignore_generic_tokens[i];
5168 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5170 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5171 image_id_prefix[i] = element_info[i].token_name;
5172 for (i = 0; i < NUM_FONTS; i++)
5173 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5174 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5175 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5176 global_anim_info[i].token_name;
5177 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5179 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5180 sound_id_prefix[i] = element_info[i].token_name;
5181 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5182 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5183 get_string_in_brackets(element_info[i].class_name);
5184 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5185 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5186 global_anim_info[i].token_name;
5187 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5189 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5190 music_id_prefix[i] = music_prefix_info[i].prefix;
5191 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5192 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5193 global_anim_info[i].token_name;
5194 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5196 for (i = 0; i < NUM_ACTIONS; i++)
5197 action_id_suffix[i] = element_action_info[i].suffix;
5198 action_id_suffix[NUM_ACTIONS] = NULL;
5200 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5201 direction_id_suffix[i] = element_direction_info[i].suffix;
5202 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5204 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5205 special_id_suffix[i] = special_suffix_info[i].suffix;
5206 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5208 for (i = 0; i < MAX_LEVELS; i++)
5209 level_id_suffix[i] = get_level_id_suffix(i);
5210 level_id_suffix[MAX_LEVELS] = NULL;
5212 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5213 image_id_prefix, action_id_suffix, direction_id_suffix,
5214 special_id_suffix, ignore_image_tokens);
5215 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5216 sound_id_prefix, action_id_suffix, dummy,
5217 special_id_suffix, ignore_sound_tokens);
5218 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5219 music_id_prefix, action_id_suffix, special_id_suffix,
5220 level_id_suffix, ignore_music_tokens);
5223 static void InitMixer()
5230 void InitGfxBuffers()
5232 static int win_xsize_last = -1;
5233 static int win_ysize_last = -1;
5235 /* create additional image buffers for double-buffering and cross-fading */
5237 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5239 /* used to temporarily store the backbuffer -- only re-create if changed */
5240 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5241 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5243 win_xsize_last = WIN_XSIZE;
5244 win_ysize_last = WIN_YSIZE;
5247 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5248 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5249 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5250 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5252 /* initialize screen properties */
5253 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5254 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5256 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5257 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5258 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5259 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5260 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5261 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5263 /* required if door size definitions have changed */
5264 InitGraphicCompatibilityInfo_Doors();
5266 InitGfxBuffers_EM();
5267 InitGfxBuffers_SP();
5272 struct GraphicInfo *graphic_info_last = graphic_info;
5273 char *filename_font_initial = NULL;
5274 char *filename_anim_initial = NULL;
5275 Bitmap *bitmap_font_initial = NULL;
5279 /* determine settings for initial font (for displaying startup messages) */
5280 for (i = 0; image_config[i].token != NULL; i++)
5282 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5284 char font_token[128];
5287 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5288 len_font_token = strlen(font_token);
5290 if (strEqual(image_config[i].token, font_token))
5291 filename_font_initial = image_config[i].value;
5292 else if (strlen(image_config[i].token) > len_font_token &&
5293 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5295 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5296 font_initial[j].src_x = atoi(image_config[i].value);
5297 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5298 font_initial[j].src_y = atoi(image_config[i].value);
5299 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5300 font_initial[j].width = atoi(image_config[i].value);
5301 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5302 font_initial[j].height = atoi(image_config[i].value);
5307 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5309 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5310 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5313 if (filename_font_initial == NULL) /* should not happen */
5314 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5317 InitGfxCustomArtworkInfo();
5318 InitGfxOtherSettings();
5320 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5322 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5323 font_initial[j].bitmap = bitmap_font_initial;
5325 InitFontGraphicInfo();
5327 font_height = getFontHeight(FC_RED);
5329 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5330 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5331 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5334 DrawInitText("Loading graphics", 120, FC_GREEN);
5336 /* initialize settings for busy animation with default values */
5337 int parameter[NUM_GFX_ARGS];
5338 for (i = 0; i < NUM_GFX_ARGS; i++)
5339 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5340 image_config_suffix[i].token,
5341 image_config_suffix[i].type);
5343 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5344 int len_anim_token = strlen(anim_token);
5346 /* read settings for busy animation from default custom artwork config */
5347 char *gfx_config_filename = getPath3(options.graphics_directory,
5349 GRAPHICSINFO_FILENAME);
5351 if (fileExists(gfx_config_filename))
5353 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5355 if (setup_file_hash)
5357 char *filename = getHashEntry(setup_file_hash, anim_token);
5361 filename_anim_initial = getStringCopy(filename);
5363 for (j = 0; image_config_suffix[j].token != NULL; j++)
5365 int type = image_config_suffix[j].type;
5366 char *suffix = image_config_suffix[j].token;
5367 char *token = getStringCat2(anim_token, suffix);
5368 char *value = getHashEntry(setup_file_hash, token);
5370 checked_free(token);
5373 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5377 freeSetupFileHash(setup_file_hash);
5381 if (filename_anim_initial == NULL)
5383 /* read settings for busy animation from static default artwork config */
5384 for (i = 0; image_config[i].token != NULL; i++)
5386 if (strEqual(image_config[i].token, anim_token))
5387 filename_anim_initial = getStringCopy(image_config[i].value);
5388 else if (strlen(image_config[i].token) > len_anim_token &&
5389 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5391 for (j = 0; image_config_suffix[j].token != NULL; j++)
5393 if (strEqual(&image_config[i].token[len_anim_token],
5394 image_config_suffix[j].token))
5396 get_graphic_parameter_value(image_config[i].value,
5397 image_config_suffix[j].token,
5398 image_config_suffix[j].type);
5404 if (filename_anim_initial == NULL) /* should not happen */
5405 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5407 anim_initial.bitmaps =
5408 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5410 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5411 LoadCustomImage(filename_anim_initial);
5413 checked_free(filename_anim_initial);
5415 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5417 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5419 graphic_info = graphic_info_last;
5421 init.busy.width = anim_initial.width;
5422 init.busy.height = anim_initial.height;
5424 InitMenuDesignSettings_Static();
5426 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5427 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5428 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5430 gfx.fade_border_source_status = global.border_status;
5431 gfx.fade_border_target_status = global.border_status;
5432 gfx.masked_border_bitmap_ptr = backbuffer;
5434 /* use copy of busy animation to prevent change while reloading artwork */
5438 void InitGfxBackground()
5440 fieldbuffer = bitmap_db_field;
5441 SetDrawtoField(DRAW_TO_BACKBUFFER);
5443 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5445 redraw_mask = REDRAW_ALL;
5448 static void InitLevelInfo()
5450 LoadLevelInfo(); /* global level info */
5451 LoadLevelSetup_LastSeries(); /* last played series info */
5452 LoadLevelSetup_SeriesInfo(); /* last played level info */
5454 if (global.autoplay_leveldir &&
5455 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5457 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5458 global.autoplay_leveldir);
5459 if (leveldir_current == NULL)
5460 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5464 static void InitLevelArtworkInfo()
5466 LoadLevelArtworkInfo();
5469 static void InitImages()
5471 print_timestamp_init("InitImages");
5474 printf("::: leveldir_current->identifier == '%s'\n",
5475 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5476 printf("::: leveldir_current->graphics_path == '%s'\n",
5477 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5478 printf("::: leveldir_current->graphics_set == '%s'\n",
5479 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5480 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5481 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5484 setLevelArtworkDir(artwork.gfx_first);
5487 printf("::: leveldir_current->identifier == '%s'\n",
5488 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5489 printf("::: leveldir_current->graphics_path == '%s'\n",
5490 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5491 printf("::: leveldir_current->graphics_set == '%s'\n",
5492 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5493 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5494 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5498 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5499 leveldir_current->identifier,
5500 artwork.gfx_current_identifier,
5501 artwork.gfx_current->identifier,
5502 leveldir_current->graphics_set,
5503 leveldir_current->graphics_path);
5506 UPDATE_BUSY_STATE();
5508 ReloadCustomImages();
5509 print_timestamp_time("ReloadCustomImages");
5511 UPDATE_BUSY_STATE();
5513 LoadCustomElementDescriptions();
5514 print_timestamp_time("LoadCustomElementDescriptions");
5516 UPDATE_BUSY_STATE();
5518 LoadMenuDesignSettings();
5519 print_timestamp_time("LoadMenuDesignSettings");
5521 UPDATE_BUSY_STATE();
5523 ReinitializeGraphics();
5524 print_timestamp_time("ReinitializeGraphics");
5526 LoadMenuDesignSettings_AfterGraphics();
5527 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5529 UPDATE_BUSY_STATE();
5531 print_timestamp_done("InitImages");
5534 static void InitSound(char *identifier)
5536 print_timestamp_init("InitSound");
5538 if (identifier == NULL)
5539 identifier = artwork.snd_current->identifier;
5541 /* set artwork path to send it to the sound server process */
5542 setLevelArtworkDir(artwork.snd_first);
5544 InitReloadCustomSounds(identifier);
5545 print_timestamp_time("InitReloadCustomSounds");
5547 ReinitializeSounds();
5548 print_timestamp_time("ReinitializeSounds");
5550 print_timestamp_done("InitSound");
5553 static void InitMusic(char *identifier)
5555 print_timestamp_init("InitMusic");
5557 if (identifier == NULL)
5558 identifier = artwork.mus_current->identifier;
5560 /* set artwork path to send it to the sound server process */
5561 setLevelArtworkDir(artwork.mus_first);
5563 InitReloadCustomMusic(identifier);
5564 print_timestamp_time("InitReloadCustomMusic");
5566 ReinitializeMusic();
5567 print_timestamp_time("ReinitializeMusic");
5569 print_timestamp_done("InitMusic");
5572 static void InitArtworkDone()
5574 if (program.headless)
5577 InitGlobalAnimations();
5580 void InitNetworkServer()
5582 #if defined(NETWORK_AVALIABLE)
5586 if (!options.network)
5589 #if defined(NETWORK_AVALIABLE)
5590 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5592 if (!ConnectToServer(options.server_host, options.server_port))
5593 Error(ERR_EXIT, "cannot connect to network game server");
5595 SendToServer_PlayerName(setup.player_name);
5596 SendToServer_ProtocolVersion();
5599 SendToServer_NrWanted(nr_wanted);
5603 static boolean CheckArtworkConfigForCustomElements(char *filename)
5605 SetupFileHash *setup_file_hash;
5606 boolean redefined_ce_found = FALSE;
5608 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5610 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5612 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5614 char *token = HASH_ITERATION_TOKEN(itr);
5616 if (strPrefix(token, "custom_"))
5618 redefined_ce_found = TRUE;
5623 END_HASH_ITERATION(setup_file_hash, itr)
5625 freeSetupFileHash(setup_file_hash);
5628 return redefined_ce_found;
5631 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5633 char *filename_base, *filename_local;
5634 boolean redefined_ce_found = FALSE;
5636 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5639 printf("::: leveldir_current->identifier == '%s'\n",
5640 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5641 printf("::: leveldir_current->graphics_path == '%s'\n",
5642 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5643 printf("::: leveldir_current->graphics_set == '%s'\n",
5644 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5645 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5646 leveldir_current == NULL ? "[NULL]" :
5647 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5650 /* first look for special artwork configured in level series config */
5651 filename_base = getCustomArtworkLevelConfigFilename(type);
5654 printf("::: filename_base == '%s'\n", filename_base);
5657 if (fileExists(filename_base))
5658 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5660 filename_local = getCustomArtworkConfigFilename(type);
5663 printf("::: filename_local == '%s'\n", filename_local);
5666 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5667 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5670 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5673 return redefined_ce_found;
5676 static void InitOverrideArtwork()
5678 boolean redefined_ce_found = FALSE;
5680 /* to check if this level set redefines any CEs, do not use overriding */
5681 gfx.override_level_graphics = FALSE;
5682 gfx.override_level_sounds = FALSE;
5683 gfx.override_level_music = FALSE;
5685 /* now check if this level set has definitions for custom elements */
5686 if (setup.override_level_graphics == AUTO ||
5687 setup.override_level_sounds == AUTO ||
5688 setup.override_level_music == AUTO)
5689 redefined_ce_found =
5690 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5691 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5692 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5695 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5698 if (redefined_ce_found)
5700 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5701 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5702 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5703 gfx.override_level_music = (setup.override_level_music == TRUE);
5707 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5708 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5709 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5710 gfx.override_level_music = (setup.override_level_music != FALSE);
5714 printf("::: => %d, %d, %d\n",
5715 gfx.override_level_graphics,
5716 gfx.override_level_sounds,
5717 gfx.override_level_music);
5721 static char *getNewArtworkIdentifier(int type)
5723 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5724 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5725 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5726 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5727 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5728 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5729 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5730 char *leveldir_identifier = leveldir_current->identifier;
5731 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5732 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5733 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5734 char *artwork_current_identifier;
5735 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5737 /* leveldir_current may be invalid (level group, parent link) */
5738 if (!validLevelSeries(leveldir_current))
5741 /* 1st step: determine artwork set to be activated in descending order:
5742 --------------------------------------------------------------------
5743 1. setup artwork (when configured to override everything else)
5744 2. artwork set configured in "levelinfo.conf" of current level set
5745 (artwork in level directory will have priority when loading later)
5746 3. artwork in level directory (stored in artwork sub-directory)
5747 4. setup artwork (currently configured in setup menu) */
5749 if (setup_override_artwork)
5750 artwork_current_identifier = setup_artwork_set;
5751 else if (leveldir_artwork_set != NULL)
5752 artwork_current_identifier = leveldir_artwork_set;
5753 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5754 artwork_current_identifier = leveldir_identifier;
5756 artwork_current_identifier = setup_artwork_set;
5759 /* 2nd step: check if it is really needed to reload artwork set
5760 ------------------------------------------------------------ */
5762 /* ---------- reload if level set and also artwork set has changed ------- */
5763 if (leveldir_current_identifier[type] != leveldir_identifier &&
5764 (last_has_level_artwork_set[type] || has_level_artwork_set))
5765 artwork_new_identifier = artwork_current_identifier;
5767 leveldir_current_identifier[type] = leveldir_identifier;
5768 last_has_level_artwork_set[type] = has_level_artwork_set;
5770 /* ---------- reload if "override artwork" setting has changed ----------- */
5771 if (last_override_level_artwork[type] != setup_override_artwork)
5772 artwork_new_identifier = artwork_current_identifier;
5774 last_override_level_artwork[type] = setup_override_artwork;
5776 /* ---------- reload if current artwork identifier has changed ----------- */
5777 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5778 artwork_current_identifier))
5779 artwork_new_identifier = artwork_current_identifier;
5781 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5783 /* ---------- do not reload directly after starting ---------------------- */
5784 if (!initialized[type])
5785 artwork_new_identifier = NULL;
5787 initialized[type] = TRUE;
5789 return artwork_new_identifier;
5792 void ReloadCustomArtwork(int force_reload)
5794 int last_game_status = game_status; /* save current game status */
5795 char *gfx_new_identifier;
5796 char *snd_new_identifier;
5797 char *mus_new_identifier;
5798 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5799 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5800 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5801 boolean reload_needed;
5803 InitOverrideArtwork();
5805 force_reload_gfx |= AdjustGraphicsForEMC();
5807 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5808 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5809 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5811 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5812 snd_new_identifier != NULL || force_reload_snd ||
5813 mus_new_identifier != NULL || force_reload_mus);
5818 print_timestamp_init("ReloadCustomArtwork");
5820 SetGameStatus(GAME_MODE_LOADING);
5822 FadeOut(REDRAW_ALL);
5824 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5825 print_timestamp_time("ClearRectangle");
5829 if (gfx_new_identifier != NULL || force_reload_gfx)
5832 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5833 artwork.gfx_current_identifier,
5835 artwork.gfx_current->identifier,
5836 leveldir_current->graphics_set);
5840 print_timestamp_time("InitImages");
5843 if (snd_new_identifier != NULL || force_reload_snd)
5845 InitSound(snd_new_identifier);
5846 print_timestamp_time("InitSound");
5849 if (mus_new_identifier != NULL || force_reload_mus)
5851 InitMusic(mus_new_identifier);
5852 print_timestamp_time("InitMusic");
5857 SetGameStatus(last_game_status); /* restore current game status */
5859 init_last = init; /* switch to new busy animation */
5861 FadeOut(REDRAW_ALL);
5863 RedrawGlobalBorder();
5865 /* force redraw of (open or closed) door graphics */
5866 SetDoorState(DOOR_OPEN_ALL);
5867 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5869 FadeSetEnterScreen();
5870 FadeSkipNextFadeOut();
5872 print_timestamp_done("ReloadCustomArtwork");
5874 LimitScreenUpdates(FALSE);
5877 void KeyboardAutoRepeatOffUnlessAutoplay()
5879 if (global.autoplay_leveldir == NULL)
5880 KeyboardAutoRepeatOff();
5883 void DisplayExitMessage(char *format, va_list ap)
5885 // check if draw buffer and fonts for exit message are already available
5886 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5889 int font_1 = FC_RED;
5890 int font_2 = FC_YELLOW;
5891 int font_3 = FC_BLUE;
5892 int font_width = getFontWidth(font_2);
5893 int font_height = getFontHeight(font_2);
5896 int sxsize = WIN_XSIZE - 2 * sx;
5897 int sysize = WIN_YSIZE - 2 * sy;
5898 int line_length = sxsize / font_width;
5899 int max_lines = sysize / font_height;
5900 int num_lines_printed;
5904 gfx.sxsize = sxsize;
5905 gfx.sysize = sysize;
5909 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5911 DrawTextSCentered(sy, font_1, "Fatal error:");
5912 sy += 3 * font_height;;
5915 DrawTextBufferVA(sx, sy, format, ap, font_2,
5916 line_length, line_length, max_lines,
5917 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5918 sy += (num_lines_printed + 3) * font_height;
5920 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5921 sy += 3 * font_height;
5924 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5925 line_length, line_length, max_lines,
5926 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5928 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5930 redraw_mask = REDRAW_ALL;
5932 /* force drawing exit message even if screen updates are currently limited */
5933 LimitScreenUpdates(FALSE);
5937 /* deactivate toons on error message screen */
5938 setup.toons = FALSE;
5940 WaitForEventToContinue();
5944 /* ========================================================================= */
5946 /* ========================================================================= */
5950 print_timestamp_init("OpenAll");
5952 SetGameStatus(GAME_MODE_LOADING);
5956 InitGlobal(); /* initialize some global variables */
5958 print_timestamp_time("[init global stuff]");
5962 print_timestamp_time("[init setup/config stuff (1)]");
5966 if (options.execute_command)
5967 Execute_Command(options.execute_command);
5969 if (options.serveronly)
5971 #if defined(PLATFORM_UNIX)
5972 NetworkServer(options.server_port, options.serveronly);
5974 Error(ERR_WARN, "networking only supported in Unix version");
5977 exit(0); /* never reached, server loops forever */
5981 print_timestamp_time("[init setup/config stuff (2)]");
5983 print_timestamp_time("[init setup/config stuff (3)]");
5984 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5985 print_timestamp_time("[init setup/config stuff (4)]");
5986 InitArtworkConfig(); /* needed before forking sound child process */
5987 print_timestamp_time("[init setup/config stuff (5)]");
5989 print_timestamp_time("[init setup/config stuff (6)]");
5991 InitRND(NEW_RANDOMIZE);
5992 InitSimpleRandom(NEW_RANDOMIZE);
5996 print_timestamp_time("[init setup/config stuff]");
5999 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6003 print_timestamp_time("[init video stuff]");
6005 InitElementPropertiesStatic();
6006 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6007 InitElementPropertiesGfxElement();
6009 print_timestamp_time("[init element properties stuff]");
6013 print_timestamp_time("InitGfx");
6016 print_timestamp_time("InitLevelInfo");
6018 InitLevelArtworkInfo();
6019 print_timestamp_time("InitLevelArtworkInfo");
6021 InitOverrideArtwork(); /* needs to know current level directory */
6022 print_timestamp_time("InitOverrideArtwork");
6024 InitImages(); /* needs to know current level directory */
6025 print_timestamp_time("InitImages");
6027 InitSound(NULL); /* needs to know current level directory */
6028 print_timestamp_time("InitSound");
6030 InitMusic(NULL); /* needs to know current level directory */
6031 print_timestamp_time("InitMusic");
6035 InitGfxBackground();
6040 if (global.autoplay_leveldir)
6045 else if (global.convert_leveldir)
6050 else if (global.create_images_dir)
6052 CreateLevelSketchImages();
6056 SetGameStatus(GAME_MODE_MAIN);
6058 FadeSetEnterScreen();
6059 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6060 FadeSkipNextFadeOut();
6062 print_timestamp_time("[post-artwork]");
6064 print_timestamp_done("OpenAll");
6068 InitNetworkServer();
6071 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6073 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6074 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6075 #if defined(PLATFORM_ANDROID)
6076 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6077 SDL_AndroidGetInternalStoragePath());
6078 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6079 SDL_AndroidGetExternalStoragePath());
6080 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6081 (SDL_AndroidGetExternalStorageState() &
6082 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6083 SDL_AndroidGetExternalStorageState() &
6084 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6089 void CloseAllAndExit(int exit_value)
6094 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6101 #if defined(TARGET_SDL)
6102 #if defined(TARGET_SDL2)
6104 // set a flag to tell the network server thread to quit and wait for it
6105 // using SDL_WaitThread()
6107 if (network_server) /* terminate network server */
6108 SDL_KillThread(server_thread);
6112 CloseVideoDisplay();
6113 ClosePlatformDependentStuff();
6115 if (exit_value != 0)
6117 /* fall back to default level set (current set may have caused an error) */
6118 SaveLevelSetup_LastSeries_Deactivate();
6120 /* tell user where to find error log file which may contain more details */
6121 // (error notification now directly displayed on screen inside R'n'D
6122 // NotifyUserAboutErrorFile(); /* currently only works for Windows */