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
89 struct GraphicInfo *graphic_info_last = graphic_info;
91 static unsigned int action_delay = 0;
92 unsigned int action_delay_value = GameFrameDelay;
93 int sync_frame = FrameCounter;
96 if (game_status != GAME_MODE_LOADING)
99 if (anim_initial.bitmap == NULL || window == NULL)
102 if (!DelayReached(&action_delay, action_delay_value))
105 if (init_last.busy.x == -1)
106 init_last.busy.x = WIN_XSIZE / 2;
107 if (init_last.busy.y == -1)
108 init_last.busy.y = WIN_YSIZE / 2;
110 x = ALIGNED_TEXT_XPOS(&init_last.busy);
111 y = ALIGNED_TEXT_YPOS(&init_last.busy);
113 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
115 if (sync_frame % anim_initial.anim_delay == 0)
119 int width = graphic_info[graphic].width;
120 int height = graphic_info[graphic].height;
121 int frame = getGraphicAnimationFrame(graphic, sync_frame);
123 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
124 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
127 graphic_info = graphic_info_last;
134 FreeLevelEditorGadgets();
143 static boolean gadgets_initialized = FALSE;
145 if (gadgets_initialized)
148 CreateLevelEditorGadgets();
152 CreateScreenGadgets();
154 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
156 gadgets_initialized = TRUE;
159 inline static void InitElementSmallImagesScaledUp(int graphic)
161 struct GraphicInfo *g = &graphic_info[graphic];
163 // create small and game tile sized bitmaps (and scale up, if needed)
164 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
167 void InitElementSmallImages()
169 print_timestamp_init("InitElementSmallImages");
171 static int special_graphics[] =
185 IMG_EDITOR_ELEMENT_BORDER,
186 IMG_EDITOR_ELEMENT_BORDER_INPUT,
187 IMG_EDITOR_CASCADE_LIST,
188 IMG_EDITOR_CASCADE_LIST_ACTIVE,
191 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
192 int num_property_mappings = getImageListPropertyMappingSize();
195 print_timestamp_time("getImageListPropertyMapping/Size");
197 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
198 /* initialize normal element images from static configuration */
199 for (i = 0; element_to_graphic[i].element > -1; i++)
200 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
201 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
203 /* initialize special element images from static configuration */
204 for (i = 0; element_to_special_graphic[i].element > -1; i++)
205 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
206 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
208 /* initialize element images from dynamic configuration */
209 for (i = 0; i < num_property_mappings; i++)
210 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
211 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
212 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
214 /* initialize special non-element images from above list */
215 for (i = 0; special_graphics[i] > -1; i++)
216 InitElementSmallImagesScaledUp(special_graphics[i]);
217 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
219 print_timestamp_done("InitElementSmallImages");
222 void InitScaledImages()
226 /* scale normal images from static configuration, if not already scaled */
227 for (i = 0; i < NUM_IMAGE_FILES; i++)
228 ScaleImage(i, graphic_info[i].scale_up_factor);
231 void InitBitmapPointers()
233 int num_images = getImageListSize();
236 // standard size bitmap may have changed -- update default bitmap pointer
237 for (i = 0; i < num_images; i++)
238 if (graphic_info[i].bitmaps)
239 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
242 void InitImageTextures()
246 FreeAllImageTextures();
248 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
249 CreateImageTextures(i);
251 for (i = 0; i < MAX_NUM_TOONS; i++)
252 CreateImageTextures(IMG_TOON_1 + i);
254 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
256 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
258 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
260 int graphic = global_anim_info[i].graphic[j][k];
262 if (graphic == IMG_UNDEFINED)
265 CreateImageTextures(graphic);
272 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
273 void SetBitmaps_EM(Bitmap **em_bitmap)
275 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
276 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
281 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
282 void SetBitmaps_SP(Bitmap **sp_bitmap)
284 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
288 static int getFontBitmapID(int font_nr)
292 /* (special case: do not use special font for GAME_MODE_LOADING) */
293 if (game_status >= GAME_MODE_TITLE_INITIAL &&
294 game_status <= GAME_MODE_PSEUDO_PREVIEW)
295 special = game_status;
296 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
297 special = GFX_SPECIAL_ARG_MAIN;
300 return font_info[font_nr].special_bitmap_id[special];
305 static int getFontFromToken(char *token)
307 char *value = getHashEntry(font_token_hash, token);
312 /* if font not found, use reliable default value */
313 return FONT_INITIAL_1;
316 void InitFontGraphicInfo()
318 static struct FontBitmapInfo *font_bitmap_info = NULL;
319 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
320 int num_property_mappings = getImageListPropertyMappingSize();
321 int num_font_bitmaps = NUM_FONTS;
324 if (graphic_info == NULL) /* still at startup phase */
326 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
327 getFontBitmapID, getFontFromToken);
332 /* ---------- initialize font graphic definitions ---------- */
334 /* always start with reliable default values (normal font graphics) */
335 for (i = 0; i < NUM_FONTS; i++)
336 font_info[i].graphic = IMG_FONT_INITIAL_1;
338 /* initialize normal font/graphic mapping from static configuration */
339 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
341 int font_nr = font_to_graphic[i].font_nr;
342 int special = font_to_graphic[i].special;
343 int graphic = font_to_graphic[i].graphic;
348 font_info[font_nr].graphic = graphic;
351 /* always start with reliable default values (special font graphics) */
352 for (i = 0; i < NUM_FONTS; i++)
354 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
356 font_info[i].special_graphic[j] = font_info[i].graphic;
357 font_info[i].special_bitmap_id[j] = i;
361 /* initialize special font/graphic mapping from static configuration */
362 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
364 int font_nr = font_to_graphic[i].font_nr;
365 int special = font_to_graphic[i].special;
366 int graphic = font_to_graphic[i].graphic;
367 int base_graphic = font2baseimg(font_nr);
369 if (IS_SPECIAL_GFX_ARG(special))
371 boolean base_redefined =
372 getImageListEntryFromImageID(base_graphic)->redefined;
373 boolean special_redefined =
374 getImageListEntryFromImageID(graphic)->redefined;
375 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
377 /* if the base font ("font.title_1", for example) has been redefined,
378 but not the special font ("font.title_1.LEVELS", for example), do not
379 use an existing (in this case considered obsolete) special font
380 anymore, but use the automatically determined default font */
381 /* special case: cloned special fonts must be explicitly redefined,
382 but are not automatically redefined by redefining base font */
383 if (base_redefined && !special_redefined && !special_cloned)
386 font_info[font_nr].special_graphic[special] = graphic;
387 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
392 /* initialize special font/graphic mapping from dynamic configuration */
393 for (i = 0; i < num_property_mappings; i++)
395 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
396 int special = property_mapping[i].ext3_index;
397 int graphic = property_mapping[i].artwork_index;
402 if (IS_SPECIAL_GFX_ARG(special))
404 font_info[font_nr].special_graphic[special] = graphic;
405 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
410 /* correct special font/graphic mapping for cloned fonts for downwards
411 compatibility of PREVIEW fonts -- this is only needed for implicit
412 redefinition of special font by redefined base font, and only if other
413 fonts are cloned from this special font (like in the "Zelda" level set) */
414 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
416 int font_nr = font_to_graphic[i].font_nr;
417 int special = font_to_graphic[i].special;
418 int graphic = font_to_graphic[i].graphic;
420 if (IS_SPECIAL_GFX_ARG(special))
422 boolean special_redefined =
423 getImageListEntryFromImageID(graphic)->redefined;
424 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
426 if (special_cloned && !special_redefined)
430 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
432 int font_nr2 = font_to_graphic[j].font_nr;
433 int special2 = font_to_graphic[j].special;
434 int graphic2 = font_to_graphic[j].graphic;
436 if (IS_SPECIAL_GFX_ARG(special2) &&
437 graphic2 == graphic_info[graphic].clone_from)
439 font_info[font_nr].special_graphic[special] =
440 font_info[font_nr2].special_graphic[special2];
441 font_info[font_nr].special_bitmap_id[special] =
442 font_info[font_nr2].special_bitmap_id[special2];
449 /* reset non-redefined ".active" font graphics if normal font is redefined */
450 /* (this different treatment is needed because normal and active fonts are
451 independently defined ("active" is not a property of font definitions!) */
452 for (i = 0; i < NUM_FONTS; i++)
454 int font_nr_base = i;
455 int font_nr_active = FONT_ACTIVE(font_nr_base);
457 /* check only those fonts with exist as normal and ".active" variant */
458 if (font_nr_base != font_nr_active)
460 int base_graphic = font_info[font_nr_base].graphic;
461 int active_graphic = font_info[font_nr_active].graphic;
462 boolean base_redefined =
463 getImageListEntryFromImageID(base_graphic)->redefined;
464 boolean active_redefined =
465 getImageListEntryFromImageID(active_graphic)->redefined;
467 /* if the base font ("font.menu_1", for example) has been redefined,
468 but not the active font ("font.menu_1.active", for example), do not
469 use an existing (in this case considered obsolete) active font
470 anymore, but use the automatically determined default font */
471 if (base_redefined && !active_redefined)
472 font_info[font_nr_active].graphic = base_graphic;
474 /* now also check each "special" font (which may be the same as above) */
475 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
477 int base_graphic = font_info[font_nr_base].special_graphic[j];
478 int active_graphic = font_info[font_nr_active].special_graphic[j];
479 boolean base_redefined =
480 getImageListEntryFromImageID(base_graphic)->redefined;
481 boolean active_redefined =
482 getImageListEntryFromImageID(active_graphic)->redefined;
484 /* same as above, but check special graphic definitions, for example:
485 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
486 if (base_redefined && !active_redefined)
488 font_info[font_nr_active].special_graphic[j] =
489 font_info[font_nr_base].special_graphic[j];
490 font_info[font_nr_active].special_bitmap_id[j] =
491 font_info[font_nr_base].special_bitmap_id[j];
497 /* ---------- initialize font bitmap array ---------- */
499 if (font_bitmap_info != NULL)
500 FreeFontInfo(font_bitmap_info);
503 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
505 /* ---------- initialize font bitmap definitions ---------- */
507 for (i = 0; i < NUM_FONTS; i++)
509 if (i < NUM_INITIAL_FONTS)
511 font_bitmap_info[i] = font_initial[i];
515 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
517 int font_bitmap_id = font_info[i].special_bitmap_id[j];
518 int graphic = font_info[i].special_graphic[j];
520 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
521 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
523 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
524 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
527 /* copy font relevant information from graphics information */
528 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
529 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
530 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
531 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
532 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
534 font_bitmap_info[font_bitmap_id].draw_xoffset =
535 graphic_info[graphic].draw_xoffset;
536 font_bitmap_info[font_bitmap_id].draw_yoffset =
537 graphic_info[graphic].draw_yoffset;
539 font_bitmap_info[font_bitmap_id].num_chars =
540 graphic_info[graphic].anim_frames;
541 font_bitmap_info[font_bitmap_id].num_chars_per_line =
542 graphic_info[graphic].anim_frames_per_line;
546 InitFontInfo(font_bitmap_info, num_font_bitmaps,
547 getFontBitmapID, getFontFromToken);
550 void InitGlobalAnimGraphicInfo()
552 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
553 int num_property_mappings = getImageListPropertyMappingSize();
556 if (graphic_info == NULL) /* still at startup phase */
559 /* always start with reliable default values (no global animations) */
560 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
561 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
562 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
563 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
565 /* initialize global animation definitions from static configuration */
566 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
568 int j = GLOBAL_ANIM_ID_PART_BASE;
569 int k = GFX_SPECIAL_ARG_DEFAULT;
571 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
574 /* initialize global animation definitions from dynamic configuration */
575 for (i = 0; i < num_property_mappings; i++)
577 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
578 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
579 int special = property_mapping[i].ext3_index;
580 int graphic = property_mapping[i].artwork_index;
582 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
585 /* set animation part to base part, if not specified */
586 if (!IS_GLOBAL_ANIM_PART(part_nr))
587 part_nr = GLOBAL_ANIM_ID_PART_BASE;
589 /* set animation screen to default, if not specified */
590 if (!IS_SPECIAL_GFX_ARG(special))
591 special = GFX_SPECIAL_ARG_DEFAULT;
593 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
597 printf("::: InitGlobalAnimGraphicInfo\n");
599 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
600 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
601 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
602 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
603 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
604 printf("::: - anim %d, part %d, mode %d => %d\n",
605 i, j, k, global_anim_info[i].graphic[j][k]);
609 void InitGlobalAnimSoundInfo()
611 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
612 int num_property_mappings = getSoundListPropertyMappingSize();
615 /* always start with reliable default values (no global animation sounds) */
616 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
617 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
618 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
619 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
621 /* initialize global animation sound definitions from dynamic configuration */
622 for (i = 0; i < num_property_mappings; i++)
624 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
625 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
626 int special = property_mapping[i].ext3_index;
627 int sound = property_mapping[i].artwork_index;
629 // sound uses control definition; map it to position of graphic (artwork)
630 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
632 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
635 /* set animation part to base part, if not specified */
636 if (!IS_GLOBAL_ANIM_PART(part_nr))
637 part_nr = GLOBAL_ANIM_ID_PART_BASE;
639 /* set animation screen to default, if not specified */
640 if (!IS_SPECIAL_GFX_ARG(special))
641 special = GFX_SPECIAL_ARG_DEFAULT;
643 global_anim_info[anim_nr].sound[part_nr][special] = sound;
647 printf("::: InitGlobalAnimSoundInfo\n");
649 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
650 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
651 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
652 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
653 printf("::: - anim %d, part %d, mode %d => %d\n",
654 i, j, k, global_anim_info[i].sound[j][k]);
658 void InitGlobalAnimMusicInfo()
660 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
661 int num_property_mappings = getMusicListPropertyMappingSize();
664 /* always start with reliable default values (no global animation music) */
665 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
666 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
667 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
668 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
670 /* initialize global animation music definitions from dynamic configuration */
671 for (i = 0; i < num_property_mappings; i++)
673 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
674 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
675 int special = property_mapping[i].ext2_index;
676 int music = property_mapping[i].artwork_index;
678 // music uses control definition; map it to position of graphic (artwork)
679 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
681 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
684 /* set animation part to base part, if not specified */
685 if (!IS_GLOBAL_ANIM_PART(part_nr))
686 part_nr = GLOBAL_ANIM_ID_PART_BASE;
688 /* set animation screen to default, if not specified */
689 if (!IS_SPECIAL_GFX_ARG(special))
690 special = GFX_SPECIAL_ARG_DEFAULT;
692 global_anim_info[anim_nr].music[part_nr][special] = music;
696 printf("::: InitGlobalAnimMusicInfo\n");
698 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
699 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
700 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
701 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
702 printf("::: - anim %d, part %d, mode %d => %d\n",
703 i, j, k, global_anim_info[i].music[j][k]);
707 void InitElementGraphicInfo()
709 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
710 int num_property_mappings = getImageListPropertyMappingSize();
713 if (graphic_info == NULL) /* still at startup phase */
716 /* set values to -1 to identify later as "uninitialized" values */
717 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
719 for (act = 0; act < NUM_ACTIONS; act++)
721 element_info[i].graphic[act] = -1;
722 element_info[i].crumbled[act] = -1;
724 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
726 element_info[i].direction_graphic[act][dir] = -1;
727 element_info[i].direction_crumbled[act][dir] = -1;
734 /* initialize normal element/graphic mapping from static configuration */
735 for (i = 0; element_to_graphic[i].element > -1; i++)
737 int element = element_to_graphic[i].element;
738 int action = element_to_graphic[i].action;
739 int direction = element_to_graphic[i].direction;
740 boolean crumbled = element_to_graphic[i].crumbled;
741 int graphic = element_to_graphic[i].graphic;
742 int base_graphic = el2baseimg(element);
744 if (graphic_info[graphic].bitmap == NULL)
747 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
750 boolean base_redefined =
751 getImageListEntryFromImageID(base_graphic)->redefined;
752 boolean act_dir_redefined =
753 getImageListEntryFromImageID(graphic)->redefined;
755 /* if the base graphic ("emerald", for example) has been redefined,
756 but not the action graphic ("emerald.falling", for example), do not
757 use an existing (in this case considered obsolete) action graphic
758 anymore, but use the automatically determined default graphic */
759 if (base_redefined && !act_dir_redefined)
764 action = ACTION_DEFAULT;
769 element_info[element].direction_crumbled[action][direction] = graphic;
771 element_info[element].crumbled[action] = graphic;
776 element_info[element].direction_graphic[action][direction] = graphic;
778 element_info[element].graphic[action] = graphic;
782 /* initialize normal element/graphic mapping from dynamic configuration */
783 for (i = 0; i < num_property_mappings; i++)
785 int element = property_mapping[i].base_index;
786 int action = property_mapping[i].ext1_index;
787 int direction = property_mapping[i].ext2_index;
788 int special = property_mapping[i].ext3_index;
789 int graphic = property_mapping[i].artwork_index;
790 boolean crumbled = FALSE;
792 if (special == GFX_SPECIAL_ARG_CRUMBLED)
798 if (graphic_info[graphic].bitmap == NULL)
801 if (element >= MAX_NUM_ELEMENTS || special != -1)
805 action = ACTION_DEFAULT;
810 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
811 element_info[element].direction_crumbled[action][dir] = -1;
814 element_info[element].direction_crumbled[action][direction] = graphic;
816 element_info[element].crumbled[action] = graphic;
821 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
822 element_info[element].direction_graphic[action][dir] = -1;
825 element_info[element].direction_graphic[action][direction] = graphic;
827 element_info[element].graphic[action] = graphic;
831 /* now copy all graphics that are defined to be cloned from other graphics */
832 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
834 int graphic = element_info[i].graphic[ACTION_DEFAULT];
835 int crumbled_like, diggable_like;
840 crumbled_like = graphic_info[graphic].crumbled_like;
841 diggable_like = graphic_info[graphic].diggable_like;
843 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
845 for (act = 0; act < NUM_ACTIONS; act++)
846 element_info[i].crumbled[act] =
847 element_info[crumbled_like].crumbled[act];
848 for (act = 0; act < NUM_ACTIONS; act++)
849 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
850 element_info[i].direction_crumbled[act][dir] =
851 element_info[crumbled_like].direction_crumbled[act][dir];
854 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
856 element_info[i].graphic[ACTION_DIGGING] =
857 element_info[diggable_like].graphic[ACTION_DIGGING];
858 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
859 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
860 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
864 /* set hardcoded definitions for some runtime elements without graphic */
865 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
867 /* set hardcoded definitions for some internal elements without graphic */
868 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
870 if (IS_EDITOR_CASCADE_INACTIVE(i))
871 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
872 else if (IS_EDITOR_CASCADE_ACTIVE(i))
873 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
876 /* now set all undefined/invalid graphics to -1 to set to default after it */
877 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
879 for (act = 0; act < NUM_ACTIONS; act++)
883 graphic = element_info[i].graphic[act];
884 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
885 element_info[i].graphic[act] = -1;
887 graphic = element_info[i].crumbled[act];
888 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
889 element_info[i].crumbled[act] = -1;
891 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
893 graphic = element_info[i].direction_graphic[act][dir];
894 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
895 element_info[i].direction_graphic[act][dir] = -1;
897 graphic = element_info[i].direction_crumbled[act][dir];
898 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
899 element_info[i].direction_crumbled[act][dir] = -1;
906 /* adjust graphics with 2nd tile for movement according to direction
907 (do this before correcting '-1' values to minimize calculations) */
908 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
910 for (act = 0; act < NUM_ACTIONS; act++)
912 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
914 int graphic = element_info[i].direction_graphic[act][dir];
915 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
917 if (act == ACTION_FALLING) /* special case */
918 graphic = element_info[i].graphic[act];
921 graphic_info[graphic].double_movement &&
922 graphic_info[graphic].swap_double_tiles != 0)
924 struct GraphicInfo *g = &graphic_info[graphic];
925 int src_x_front = g->src_x;
926 int src_y_front = g->src_y;
927 int src_x_back = g->src_x + g->offset2_x;
928 int src_y_back = g->src_y + g->offset2_y;
929 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
931 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
932 src_y_front < src_y_back);
933 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
934 boolean swap_movement_tiles_autodetected =
935 (!frames_are_ordered_diagonally &&
936 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
937 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
938 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
939 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
942 /* swap frontside and backside graphic tile coordinates, if needed */
943 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
945 /* get current (wrong) backside tile coordinates */
946 getFixedGraphicSourceExt(graphic, 0, &dummy,
947 &src_x_back, &src_y_back, TRUE);
949 /* set frontside tile coordinates to backside tile coordinates */
950 g->src_x = src_x_back;
951 g->src_y = src_y_back;
953 /* invert tile offset to point to new backside tile coordinates */
957 /* do not swap front and backside tiles again after correction */
958 g->swap_double_tiles = 0;
967 /* now set all '-1' values to element specific default values */
968 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
970 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
971 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
972 int default_direction_graphic[NUM_DIRECTIONS_FULL];
973 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
975 if (default_graphic == -1)
976 default_graphic = IMG_UNKNOWN;
978 if (default_crumbled == -1)
979 default_crumbled = default_graphic;
981 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
983 default_direction_graphic[dir] =
984 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
985 default_direction_crumbled[dir] =
986 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
988 if (default_direction_graphic[dir] == -1)
989 default_direction_graphic[dir] = default_graphic;
991 if (default_direction_crumbled[dir] == -1)
992 default_direction_crumbled[dir] = default_direction_graphic[dir];
995 for (act = 0; act < NUM_ACTIONS; act++)
997 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
998 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
999 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1000 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1001 act == ACTION_TURNING_FROM_RIGHT ||
1002 act == ACTION_TURNING_FROM_UP ||
1003 act == ACTION_TURNING_FROM_DOWN);
1005 /* generic default action graphic (defined by "[default]" directive) */
1006 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1007 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1008 int default_remove_graphic = IMG_EMPTY;
1010 if (act_remove && default_action_graphic != -1)
1011 default_remove_graphic = default_action_graphic;
1013 /* look for special default action graphic (classic game specific) */
1014 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1015 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1016 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1017 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1018 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1019 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1021 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1022 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1023 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1024 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1025 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1026 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1028 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1029 /* !!! make this better !!! */
1030 if (i == EL_EMPTY_SPACE)
1032 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1033 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1036 if (default_action_graphic == -1)
1037 default_action_graphic = default_graphic;
1039 if (default_action_crumbled == -1)
1040 default_action_crumbled = default_action_graphic;
1042 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1044 /* use action graphic as the default direction graphic, if undefined */
1045 int default_action_direction_graphic = element_info[i].graphic[act];
1046 int default_action_direction_crumbled = element_info[i].crumbled[act];
1048 /* no graphic for current action -- use default direction graphic */
1049 if (default_action_direction_graphic == -1)
1050 default_action_direction_graphic =
1051 (act_remove ? default_remove_graphic :
1053 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1054 default_action_graphic != default_graphic ?
1055 default_action_graphic :
1056 default_direction_graphic[dir]);
1058 if (element_info[i].direction_graphic[act][dir] == -1)
1059 element_info[i].direction_graphic[act][dir] =
1060 default_action_direction_graphic;
1062 if (default_action_direction_crumbled == -1)
1063 default_action_direction_crumbled =
1064 element_info[i].direction_graphic[act][dir];
1066 if (element_info[i].direction_crumbled[act][dir] == -1)
1067 element_info[i].direction_crumbled[act][dir] =
1068 default_action_direction_crumbled;
1071 /* no graphic for this specific action -- use default action graphic */
1072 if (element_info[i].graphic[act] == -1)
1073 element_info[i].graphic[act] =
1074 (act_remove ? default_remove_graphic :
1075 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1076 default_action_graphic);
1078 if (element_info[i].crumbled[act] == -1)
1079 element_info[i].crumbled[act] = element_info[i].graphic[act];
1083 UPDATE_BUSY_STATE();
1086 void InitElementSpecialGraphicInfo()
1088 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1089 int num_property_mappings = getImageListPropertyMappingSize();
1092 /* always start with reliable default values */
1093 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1094 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1095 element_info[i].special_graphic[j] =
1096 element_info[i].graphic[ACTION_DEFAULT];
1098 /* initialize special element/graphic mapping from static configuration */
1099 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1101 int element = element_to_special_graphic[i].element;
1102 int special = element_to_special_graphic[i].special;
1103 int graphic = element_to_special_graphic[i].graphic;
1104 int base_graphic = el2baseimg(element);
1105 boolean base_redefined =
1106 getImageListEntryFromImageID(base_graphic)->redefined;
1107 boolean special_redefined =
1108 getImageListEntryFromImageID(graphic)->redefined;
1110 /* if the base graphic ("emerald", for example) has been redefined,
1111 but not the special graphic ("emerald.EDITOR", for example), do not
1112 use an existing (in this case considered obsolete) special graphic
1113 anymore, but use the automatically created (down-scaled) graphic */
1114 if (base_redefined && !special_redefined)
1117 element_info[element].special_graphic[special] = graphic;
1120 /* initialize special element/graphic mapping from dynamic configuration */
1121 for (i = 0; i < num_property_mappings; i++)
1123 int element = property_mapping[i].base_index;
1124 int action = property_mapping[i].ext1_index;
1125 int direction = property_mapping[i].ext2_index;
1126 int special = property_mapping[i].ext3_index;
1127 int graphic = property_mapping[i].artwork_index;
1129 /* for action ".active", replace element with active element, if exists */
1130 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1132 element = ELEMENT_ACTIVE(element);
1136 if (element >= MAX_NUM_ELEMENTS)
1139 /* do not change special graphic if action or direction was specified */
1140 if (action != -1 || direction != -1)
1143 if (IS_SPECIAL_GFX_ARG(special))
1144 element_info[element].special_graphic[special] = graphic;
1147 /* now set all undefined/invalid graphics to default */
1148 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1149 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1150 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1151 element_info[i].special_graphic[j] =
1152 element_info[i].graphic[ACTION_DEFAULT];
1155 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1157 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1158 return get_parameter_value(value_raw, suffix, type);
1160 if (strEqual(value_raw, ARG_UNDEFINED))
1161 return ARG_UNDEFINED_VALUE;
1163 if (type == TYPE_ELEMENT)
1165 char *value = getHashEntry(element_token_hash, value_raw);
1169 Error(ERR_INFO_LINE, "-");
1170 Error(ERR_INFO, "warning: error found in config file:");
1171 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1172 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1173 Error(ERR_INFO, "custom graphic rejected for this element/action");
1174 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1175 Error(ERR_INFO_LINE, "-");
1178 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1180 else if (type == TYPE_GRAPHIC)
1182 char *value = getHashEntry(graphic_token_hash, value_raw);
1183 int fallback_graphic = IMG_CHAR_EXCLAM;
1187 Error(ERR_INFO_LINE, "-");
1188 Error(ERR_INFO, "warning: error found in config file:");
1189 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1190 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1191 Error(ERR_INFO, "custom graphic rejected for this element/action");
1192 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1193 Error(ERR_INFO_LINE, "-");
1196 return (value != NULL ? atoi(value) : fallback_graphic);
1202 static int get_scaled_graphic_width(int graphic)
1204 int original_width = getOriginalImageWidthFromImageID(graphic);
1205 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1207 return original_width * scale_up_factor;
1210 static int get_scaled_graphic_height(int graphic)
1212 int original_height = getOriginalImageHeightFromImageID(graphic);
1213 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1215 return original_height * scale_up_factor;
1218 static void set_graphic_parameters_ext(int graphic, int *parameter,
1219 Bitmap **src_bitmaps)
1221 struct GraphicInfo *g = &graphic_info[graphic];
1222 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1223 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1224 int anim_frames_per_line = 1;
1226 /* always start with reliable default values */
1227 g->src_image_width = 0;
1228 g->src_image_height = 0;
1231 g->width = TILEX; /* default for element graphics */
1232 g->height = TILEY; /* default for element graphics */
1233 g->offset_x = 0; /* one or both of these values ... */
1234 g->offset_y = 0; /* ... will be corrected later */
1235 g->offset2_x = 0; /* one or both of these values ... */
1236 g->offset2_y = 0; /* ... will be corrected later */
1237 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1238 g->crumbled_like = -1; /* do not use clone element */
1239 g->diggable_like = -1; /* do not use clone element */
1240 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1241 g->scale_up_factor = 1; /* default: no scaling up */
1242 g->tile_size = TILESIZE; /* default: standard tile size */
1243 g->clone_from = -1; /* do not use clone graphic */
1244 g->init_delay_fixed = 0;
1245 g->init_delay_random = 0;
1246 g->anim_delay_fixed = 0;
1247 g->anim_delay_random = 0;
1248 g->post_delay_fixed = 0;
1249 g->post_delay_random = 0;
1251 g->fade_mode = FADE_MODE_DEFAULT;
1255 g->align = ALIGN_CENTER; /* default for title screens */
1256 g->valign = VALIGN_MIDDLE; /* default for title screens */
1257 g->sort_priority = 0; /* default for title screens */
1259 g->style = STYLE_DEFAULT;
1261 g->bitmaps = src_bitmaps;
1262 g->bitmap = src_bitmap;
1264 /* optional zoom factor for scaling up the image to a larger size */
1265 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1266 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1267 if (g->scale_up_factor < 1)
1268 g->scale_up_factor = 1; /* no scaling */
1270 /* optional tile size for using non-standard image size */
1271 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1273 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1276 // CHECK: should tile sizes less than standard tile size be allowed?
1277 if (g->tile_size < TILESIZE)
1278 g->tile_size = TILESIZE; /* standard tile size */
1281 // when setting tile size, also set width and height accordingly
1282 g->width = g->tile_size;
1283 g->height = g->tile_size;
1286 if (g->use_image_size)
1288 /* set new default bitmap size (with scaling, but without small images) */
1289 g->width = get_scaled_graphic_width(graphic);
1290 g->height = get_scaled_graphic_height(graphic);
1293 /* optional width and height of each animation frame */
1294 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1295 g->width = parameter[GFX_ARG_WIDTH];
1296 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1297 g->height = parameter[GFX_ARG_HEIGHT];
1299 /* optional x and y tile position of animation frame sequence */
1300 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1301 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1302 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1303 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1305 /* optional x and y pixel position of animation frame sequence */
1306 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1307 g->src_x = parameter[GFX_ARG_X];
1308 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1309 g->src_y = parameter[GFX_ARG_Y];
1315 Error(ERR_INFO_LINE, "-");
1316 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1317 g->width, getTokenFromImageID(graphic), TILEX);
1318 Error(ERR_INFO_LINE, "-");
1320 g->width = TILEX; /* will be checked to be inside bitmap later */
1325 Error(ERR_INFO_LINE, "-");
1326 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1327 g->height, getTokenFromImageID(graphic), TILEY);
1328 Error(ERR_INFO_LINE, "-");
1330 g->height = TILEY; /* will be checked to be inside bitmap later */
1336 /* get final bitmap size (with scaling, but without small images) */
1337 int src_image_width = get_scaled_graphic_width(graphic);
1338 int src_image_height = get_scaled_graphic_height(graphic);
1340 if (src_image_width == 0 || src_image_height == 0)
1342 /* only happens when loaded outside artwork system (like "global.busy") */
1343 src_image_width = src_bitmap->width;
1344 src_image_height = src_bitmap->height;
1347 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1349 anim_frames_per_row = src_image_width / g->tile_size;
1350 anim_frames_per_col = src_image_height / g->tile_size;
1354 anim_frames_per_row = src_image_width / g->width;
1355 anim_frames_per_col = src_image_height / g->height;
1358 g->src_image_width = src_image_width;
1359 g->src_image_height = src_image_height;
1362 /* correct x or y offset dependent of vertical or horizontal frame order */
1363 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1365 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1366 parameter[GFX_ARG_OFFSET] : g->height);
1367 anim_frames_per_line = anim_frames_per_col;
1369 else /* frames are ordered horizontally */
1371 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1372 parameter[GFX_ARG_OFFSET] : g->width);
1373 anim_frames_per_line = anim_frames_per_row;
1376 /* optionally, the x and y offset of frames can be specified directly */
1377 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1378 g->offset_x = parameter[GFX_ARG_XOFFSET];
1379 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1380 g->offset_y = parameter[GFX_ARG_YOFFSET];
1382 /* optionally, moving animations may have separate start and end graphics */
1383 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1385 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1386 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1388 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1389 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1390 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1391 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1392 else /* frames are ordered horizontally */
1393 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1394 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1396 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1397 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1398 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1399 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1400 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1402 /* optionally, the second movement tile can be specified as start tile */
1403 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1404 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1406 /* automatically determine correct number of frames, if not defined */
1407 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1408 g->anim_frames = parameter[GFX_ARG_FRAMES];
1409 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1410 g->anim_frames = anim_frames_per_row;
1411 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1412 g->anim_frames = anim_frames_per_col;
1416 if (g->anim_frames == 0) /* frames must be at least 1 */
1419 g->anim_frames_per_line =
1420 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1421 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1423 g->anim_delay = parameter[GFX_ARG_DELAY];
1424 if (g->anim_delay == 0) /* delay must be at least 1 */
1427 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1429 /* automatically determine correct start frame, if not defined */
1430 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1431 g->anim_start_frame = 0;
1432 else if (g->anim_mode & ANIM_REVERSE)
1433 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1435 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1437 /* animation synchronized with global frame counter, not move position */
1438 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1440 /* optional element for cloning crumble graphics */
1441 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1442 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1444 /* optional element for cloning digging graphics */
1445 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1446 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1448 /* optional border size for "crumbling" diggable graphics */
1449 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1450 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1452 /* used for global animations and player "boring" and "sleeping" actions */
1453 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1454 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1455 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1456 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1457 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1458 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1459 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1460 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1461 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1462 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1463 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1464 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1466 /* used for toon animations and global animations */
1467 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1468 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1469 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1470 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1471 g->direction = parameter[GFX_ARG_DIRECTION];
1472 g->position = parameter[GFX_ARG_POSITION];
1473 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1474 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1476 /* this is only used for drawing font characters */
1477 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1478 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1480 /* this is only used for drawing envelope graphics */
1481 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1483 /* used for toon animations and global animations */
1484 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1485 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1487 /* optional graphic for cloning all graphics settings */
1488 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1489 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1491 /* optional settings for drawing title screens and title messages */
1492 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1493 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1494 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1495 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1496 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1497 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1498 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1499 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1500 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1501 g->align = parameter[GFX_ARG_ALIGN];
1502 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1503 g->valign = parameter[GFX_ARG_VALIGN];
1504 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1505 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1507 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1508 g->class = parameter[GFX_ARG_CLASS];
1509 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1510 g->style = parameter[GFX_ARG_STYLE];
1512 /* this is only used for drawing menu buttons and text */
1513 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1514 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1515 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1516 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1519 static void set_graphic_parameters(int graphic)
1521 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1522 char **parameter_raw = image->parameter;
1523 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1524 int parameter[NUM_GFX_ARGS];
1527 /* if fallback to default artwork is done, also use the default parameters */
1528 if (image->fallback_to_default)
1529 parameter_raw = image->default_parameter;
1531 /* get integer values from string parameters */
1532 for (i = 0; i < NUM_GFX_ARGS; i++)
1533 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1534 image_config_suffix[i].token,
1535 image_config_suffix[i].type);
1537 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1539 UPDATE_BUSY_STATE();
1542 static void set_cloned_graphic_parameters(int graphic)
1544 int fallback_graphic = IMG_CHAR_EXCLAM;
1545 int max_num_images = getImageListSize();
1546 int clone_graphic = graphic_info[graphic].clone_from;
1547 int num_references_followed = 1;
1549 while (graphic_info[clone_graphic].clone_from != -1 &&
1550 num_references_followed < max_num_images)
1552 clone_graphic = graphic_info[clone_graphic].clone_from;
1554 num_references_followed++;
1557 if (num_references_followed >= max_num_images)
1559 Error(ERR_INFO_LINE, "-");
1560 Error(ERR_INFO, "warning: error found in config file:");
1561 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1562 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1563 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1564 Error(ERR_INFO, "custom graphic rejected for this element/action");
1566 if (graphic == fallback_graphic)
1567 Error(ERR_EXIT, "no fallback graphic available");
1569 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1570 Error(ERR_INFO_LINE, "-");
1572 graphic_info[graphic] = graphic_info[fallback_graphic];
1576 graphic_info[graphic] = graphic_info[clone_graphic];
1577 graphic_info[graphic].clone_from = clone_graphic;
1581 static void InitGraphicInfo()
1583 int fallback_graphic = IMG_CHAR_EXCLAM;
1584 int num_images = getImageListSize();
1587 /* use image size as default values for width and height for these images */
1588 static int full_size_graphics[] =
1591 IMG_GLOBAL_BORDER_MAIN,
1592 IMG_GLOBAL_BORDER_SCORES,
1593 IMG_GLOBAL_BORDER_EDITOR,
1594 IMG_GLOBAL_BORDER_PLAYING,
1597 IMG_BACKGROUND_ENVELOPE_1,
1598 IMG_BACKGROUND_ENVELOPE_2,
1599 IMG_BACKGROUND_ENVELOPE_3,
1600 IMG_BACKGROUND_ENVELOPE_4,
1601 IMG_BACKGROUND_REQUEST,
1604 IMG_BACKGROUND_TITLE_INITIAL,
1605 IMG_BACKGROUND_TITLE,
1606 IMG_BACKGROUND_MAIN,
1607 IMG_BACKGROUND_LEVELS,
1608 IMG_BACKGROUND_LEVELNR,
1609 IMG_BACKGROUND_SCORES,
1610 IMG_BACKGROUND_EDITOR,
1611 IMG_BACKGROUND_INFO,
1612 IMG_BACKGROUND_INFO_ELEMENTS,
1613 IMG_BACKGROUND_INFO_MUSIC,
1614 IMG_BACKGROUND_INFO_CREDITS,
1615 IMG_BACKGROUND_INFO_PROGRAM,
1616 IMG_BACKGROUND_INFO_VERSION,
1617 IMG_BACKGROUND_INFO_LEVELSET,
1618 IMG_BACKGROUND_SETUP,
1619 IMG_BACKGROUND_PLAYING,
1620 IMG_BACKGROUND_DOOR,
1621 IMG_BACKGROUND_TAPE,
1622 IMG_BACKGROUND_PANEL,
1623 IMG_BACKGROUND_PALETTE,
1624 IMG_BACKGROUND_TOOLBOX,
1626 IMG_TITLESCREEN_INITIAL_1,
1627 IMG_TITLESCREEN_INITIAL_2,
1628 IMG_TITLESCREEN_INITIAL_3,
1629 IMG_TITLESCREEN_INITIAL_4,
1630 IMG_TITLESCREEN_INITIAL_5,
1637 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1638 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1639 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1640 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1641 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1642 IMG_BACKGROUND_TITLEMESSAGE_1,
1643 IMG_BACKGROUND_TITLEMESSAGE_2,
1644 IMG_BACKGROUND_TITLEMESSAGE_3,
1645 IMG_BACKGROUND_TITLEMESSAGE_4,
1646 IMG_BACKGROUND_TITLEMESSAGE_5,
1651 checked_free(graphic_info);
1653 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1655 /* initialize "use_image_size" flag with default value */
1656 for (i = 0; i < num_images; i++)
1657 graphic_info[i].use_image_size = FALSE;
1659 /* initialize "use_image_size" flag from static configuration above */
1660 for (i = 0; full_size_graphics[i] != -1; i++)
1661 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1663 /* first set all graphic paramaters ... */
1664 for (i = 0; i < num_images; i++)
1665 set_graphic_parameters(i);
1667 /* ... then copy these parameters for cloned graphics */
1668 for (i = 0; i < num_images; i++)
1669 if (graphic_info[i].clone_from != -1)
1670 set_cloned_graphic_parameters(i);
1672 for (i = 0; i < num_images; i++)
1677 int first_frame, last_frame;
1678 int src_bitmap_width, src_bitmap_height;
1680 /* now check if no animation frames are outside of the loaded image */
1682 if (graphic_info[i].bitmap == NULL)
1683 continue; /* skip check for optional images that are undefined */
1685 /* get image size (this can differ from the standard element tile size!) */
1686 width = graphic_info[i].width;
1687 height = graphic_info[i].height;
1689 /* get final bitmap size (with scaling, but without small images) */
1690 src_bitmap_width = graphic_info[i].src_image_width;
1691 src_bitmap_height = graphic_info[i].src_image_height;
1693 /* check if first animation frame is inside specified bitmap */
1696 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1698 /* this avoids calculating wrong start position for out-of-bounds frame */
1699 src_x = graphic_info[i].src_x;
1700 src_y = graphic_info[i].src_y;
1702 if (src_x < 0 || src_y < 0 ||
1703 src_x + width > src_bitmap_width ||
1704 src_y + height > src_bitmap_height)
1706 Error(ERR_INFO_LINE, "-");
1707 Error(ERR_INFO, "warning: error found in config file:");
1708 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1709 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1710 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1712 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1713 src_x, src_y, src_bitmap_width, src_bitmap_height);
1714 Error(ERR_INFO, "custom graphic rejected for this element/action");
1716 if (i == fallback_graphic)
1717 Error(ERR_EXIT, "no fallback graphic available");
1719 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1720 Error(ERR_INFO_LINE, "-");
1722 graphic_info[i] = graphic_info[fallback_graphic];
1725 /* check if last animation frame is inside specified bitmap */
1727 last_frame = graphic_info[i].anim_frames - 1;
1728 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1730 if (src_x < 0 || src_y < 0 ||
1731 src_x + width > src_bitmap_width ||
1732 src_y + height > src_bitmap_height)
1734 Error(ERR_INFO_LINE, "-");
1735 Error(ERR_INFO, "warning: error found in config file:");
1736 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1737 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1738 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1740 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1741 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1742 Error(ERR_INFO, "::: %d, %d", width, height);
1743 Error(ERR_INFO, "custom graphic rejected for this element/action");
1745 if (i == fallback_graphic)
1746 Error(ERR_EXIT, "no fallback graphic available");
1748 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1749 Error(ERR_INFO_LINE, "-");
1751 graphic_info[i] = graphic_info[fallback_graphic];
1756 static void InitGraphicCompatibilityInfo()
1758 struct FileInfo *fi_global_door =
1759 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1760 int num_images = getImageListSize();
1763 /* the following compatibility handling is needed for the following case:
1764 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1765 graphics mainly used for door and panel graphics, like editor, tape and
1766 in-game buttons with hard-coded bitmap positions and button sizes; as
1767 these graphics now have individual definitions, redefining "global.door"
1768 to change all these graphics at once like before does not work anymore
1769 (because all those individual definitions still have their default values);
1770 to solve this, remap all those individual definitions that are not
1771 redefined to the new bitmap of "global.door" if it was redefined */
1773 /* special compatibility handling if image "global.door" was redefined */
1774 if (fi_global_door->redefined)
1776 for (i = 0; i < num_images; i++)
1778 struct FileInfo *fi = getImageListEntryFromImageID(i);
1780 /* process only those images that still use the default settings */
1783 /* process all images which default to same image as "global.door" */
1784 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1786 // printf("::: special treatment needed for token '%s'\n", fi->token);
1788 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1789 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1795 InitGraphicCompatibilityInfo_Doors();
1798 static void InitElementSoundInfo()
1800 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1801 int num_property_mappings = getSoundListPropertyMappingSize();
1804 /* set values to -1 to identify later as "uninitialized" values */
1805 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1806 for (act = 0; act < NUM_ACTIONS; act++)
1807 element_info[i].sound[act] = -1;
1809 /* initialize element/sound mapping from static configuration */
1810 for (i = 0; element_to_sound[i].element > -1; i++)
1812 int element = element_to_sound[i].element;
1813 int action = element_to_sound[i].action;
1814 int sound = element_to_sound[i].sound;
1815 boolean is_class = element_to_sound[i].is_class;
1818 action = ACTION_DEFAULT;
1821 element_info[element].sound[action] = sound;
1823 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1824 if (strEqual(element_info[j].class_name,
1825 element_info[element].class_name))
1826 element_info[j].sound[action] = sound;
1829 /* initialize element class/sound mapping from dynamic configuration */
1830 for (i = 0; i < num_property_mappings; i++)
1832 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1833 int action = property_mapping[i].ext1_index;
1834 int sound = property_mapping[i].artwork_index;
1836 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1840 action = ACTION_DEFAULT;
1842 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1843 if (strEqual(element_info[j].class_name,
1844 element_info[element_class].class_name))
1845 element_info[j].sound[action] = sound;
1848 /* initialize element/sound mapping from dynamic configuration */
1849 for (i = 0; i < num_property_mappings; i++)
1851 int element = property_mapping[i].base_index;
1852 int action = property_mapping[i].ext1_index;
1853 int sound = property_mapping[i].artwork_index;
1855 if (element >= MAX_NUM_ELEMENTS)
1859 action = ACTION_DEFAULT;
1861 element_info[element].sound[action] = sound;
1864 /* now set all '-1' values to element specific default values */
1865 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1867 for (act = 0; act < NUM_ACTIONS; act++)
1869 /* generic default action sound (defined by "[default]" directive) */
1870 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1872 /* look for special default action sound (classic game specific) */
1873 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1874 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1875 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1876 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1877 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1878 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1880 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1881 /* !!! make this better !!! */
1882 if (i == EL_EMPTY_SPACE)
1883 default_action_sound = element_info[EL_DEFAULT].sound[act];
1885 /* no sound for this specific action -- use default action sound */
1886 if (element_info[i].sound[act] == -1)
1887 element_info[i].sound[act] = default_action_sound;
1891 /* copy sound settings to some elements that are only stored in level file
1892 in native R'n'D levels, but are used by game engine in native EM levels */
1893 for (i = 0; copy_properties[i][0] != -1; i++)
1894 for (j = 1; j <= 4; j++)
1895 for (act = 0; act < NUM_ACTIONS; act++)
1896 element_info[copy_properties[i][j]].sound[act] =
1897 element_info[copy_properties[i][0]].sound[act];
1900 static void InitGameModeSoundInfo()
1904 /* set values to -1 to identify later as "uninitialized" values */
1905 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1908 /* initialize gamemode/sound mapping from static configuration */
1909 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1911 int gamemode = gamemode_to_sound[i].gamemode;
1912 int sound = gamemode_to_sound[i].sound;
1915 gamemode = GAME_MODE_DEFAULT;
1917 menu.sound[gamemode] = sound;
1920 /* now set all '-1' values to levelset specific default values */
1921 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1922 if (menu.sound[i] == -1)
1923 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1926 static void set_sound_parameters(int sound, char **parameter_raw)
1928 int parameter[NUM_SND_ARGS];
1931 /* get integer values from string parameters */
1932 for (i = 0; i < NUM_SND_ARGS; i++)
1934 get_parameter_value(parameter_raw[i],
1935 sound_config_suffix[i].token,
1936 sound_config_suffix[i].type);
1938 /* explicit loop mode setting in configuration overrides default value */
1939 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1940 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1942 /* sound volume to change the original volume when loading the sound file */
1943 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1945 /* sound priority to give certain sounds a higher or lower priority */
1946 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1949 static void InitSoundInfo()
1951 int *sound_effect_properties;
1952 int num_sounds = getSoundListSize();
1955 checked_free(sound_info);
1957 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1958 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1960 /* initialize sound effect for all elements to "no sound" */
1961 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1962 for (j = 0; j < NUM_ACTIONS; j++)
1963 element_info[i].sound[j] = SND_UNDEFINED;
1965 for (i = 0; i < num_sounds; i++)
1967 struct FileInfo *sound = getSoundListEntry(i);
1968 int len_effect_text = strlen(sound->token);
1970 sound_effect_properties[i] = ACTION_OTHER;
1971 sound_info[i].loop = FALSE; /* default: play sound only once */
1973 /* determine all loop sounds and identify certain sound classes */
1975 for (j = 0; element_action_info[j].suffix; j++)
1977 int len_action_text = strlen(element_action_info[j].suffix);
1979 if (len_action_text < len_effect_text &&
1980 strEqual(&sound->token[len_effect_text - len_action_text],
1981 element_action_info[j].suffix))
1983 sound_effect_properties[i] = element_action_info[j].value;
1984 sound_info[i].loop = element_action_info[j].is_loop_sound;
1990 /* associate elements and some selected sound actions */
1992 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1994 if (element_info[j].class_name)
1996 int len_class_text = strlen(element_info[j].class_name);
1998 if (len_class_text + 1 < len_effect_text &&
1999 strncmp(sound->token,
2000 element_info[j].class_name, len_class_text) == 0 &&
2001 sound->token[len_class_text] == '.')
2003 int sound_action_value = sound_effect_properties[i];
2005 element_info[j].sound[sound_action_value] = i;
2010 set_sound_parameters(i, sound->parameter);
2013 free(sound_effect_properties);
2016 static void InitGameModeMusicInfo()
2018 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2019 int num_property_mappings = getMusicListPropertyMappingSize();
2020 int default_levelset_music = -1;
2023 /* set values to -1 to identify later as "uninitialized" values */
2024 for (i = 0; i < MAX_LEVELS; i++)
2025 levelset.music[i] = -1;
2026 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2029 /* initialize gamemode/music mapping from static configuration */
2030 for (i = 0; gamemode_to_music[i].music > -1; i++)
2032 int gamemode = gamemode_to_music[i].gamemode;
2033 int music = gamemode_to_music[i].music;
2036 gamemode = GAME_MODE_DEFAULT;
2038 menu.music[gamemode] = music;
2041 /* initialize gamemode/music mapping from dynamic configuration */
2042 for (i = 0; i < num_property_mappings; i++)
2044 int prefix = property_mapping[i].base_index;
2045 int gamemode = property_mapping[i].ext2_index;
2046 int level = property_mapping[i].ext3_index;
2047 int music = property_mapping[i].artwork_index;
2049 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2053 gamemode = GAME_MODE_DEFAULT;
2055 /* level specific music only allowed for in-game music */
2056 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2057 gamemode = GAME_MODE_PLAYING;
2062 default_levelset_music = music;
2065 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2066 levelset.music[level] = music;
2067 if (gamemode != GAME_MODE_PLAYING)
2068 menu.music[gamemode] = music;
2071 /* now set all '-1' values to menu specific default values */
2072 /* (undefined values of "levelset.music[]" might stay at "-1" to
2073 allow dynamic selection of music files from music directory!) */
2074 for (i = 0; i < MAX_LEVELS; i++)
2075 if (levelset.music[i] == -1)
2076 levelset.music[i] = default_levelset_music;
2077 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2078 if (menu.music[i] == -1)
2079 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2082 static void set_music_parameters(int music, char **parameter_raw)
2084 int parameter[NUM_MUS_ARGS];
2087 /* get integer values from string parameters */
2088 for (i = 0; i < NUM_MUS_ARGS; i++)
2090 get_parameter_value(parameter_raw[i],
2091 music_config_suffix[i].token,
2092 music_config_suffix[i].type);
2094 /* explicit loop mode setting in configuration overrides default value */
2095 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2096 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2099 static void InitMusicInfo()
2101 int num_music = getMusicListSize();
2104 checked_free(music_info);
2106 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2108 for (i = 0; i < num_music; i++)
2110 struct FileInfo *music = getMusicListEntry(i);
2111 int len_music_text = strlen(music->token);
2113 music_info[i].loop = TRUE; /* default: play music in loop mode */
2115 /* determine all loop music */
2117 for (j = 0; music_prefix_info[j].prefix; j++)
2119 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2121 if (len_prefix_text < len_music_text &&
2122 strncmp(music->token,
2123 music_prefix_info[j].prefix, len_prefix_text) == 0)
2125 music_info[i].loop = music_prefix_info[j].is_loop_music;
2131 set_music_parameters(i, music->parameter);
2135 static void ReinitializeGraphics()
2137 print_timestamp_init("ReinitializeGraphics");
2139 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2141 InitGraphicInfo(); /* graphic properties mapping */
2142 print_timestamp_time("InitGraphicInfo");
2143 InitElementGraphicInfo(); /* element game graphic mapping */
2144 print_timestamp_time("InitElementGraphicInfo");
2145 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2146 print_timestamp_time("InitElementSpecialGraphicInfo");
2148 InitElementSmallImages(); /* scale elements to all needed sizes */
2149 print_timestamp_time("InitElementSmallImages");
2150 InitScaledImages(); /* scale all other images, if needed */
2151 print_timestamp_time("InitScaledImages");
2152 InitBitmapPointers(); /* set standard size bitmap pointers */
2153 print_timestamp_time("InitBitmapPointers");
2154 InitFontGraphicInfo(); /* initialize text drawing functions */
2155 print_timestamp_time("InitFontGraphicInfo");
2156 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2157 print_timestamp_time("InitGlobalAnimGraphicInfo");
2159 InitImageTextures(); /* create textures for certain images */
2160 print_timestamp_time("InitImageTextures");
2162 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2163 print_timestamp_time("InitGraphicInfo_EM");
2165 InitGraphicCompatibilityInfo();
2166 print_timestamp_time("InitGraphicCompatibilityInfo");
2168 SetMainBackgroundImage(IMG_BACKGROUND);
2169 print_timestamp_time("SetMainBackgroundImage");
2170 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2171 print_timestamp_time("SetDoorBackgroundImage");
2174 print_timestamp_time("InitGadgets");
2176 print_timestamp_time("InitDoors");
2178 print_timestamp_done("ReinitializeGraphics");
2181 static void ReinitializeSounds()
2183 InitSoundInfo(); /* sound properties mapping */
2184 InitElementSoundInfo(); /* element game sound mapping */
2185 InitGameModeSoundInfo(); /* game mode sound mapping */
2186 InitGlobalAnimSoundInfo(); /* global animation sound settings */
2188 InitPlayLevelSound(); /* internal game sound settings */
2191 static void ReinitializeMusic()
2193 InitMusicInfo(); /* music properties mapping */
2194 InitGameModeMusicInfo(); /* game mode music mapping */
2195 InitGlobalAnimMusicInfo(); /* global animation music settings */
2198 static int get_special_property_bit(int element, int property_bit_nr)
2200 struct PropertyBitInfo
2206 static struct PropertyBitInfo pb_can_move_into_acid[] =
2208 /* the player may be able fall into acid when gravity is activated */
2213 { EL_SP_MURPHY, 0 },
2214 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2216 /* all elements that can move may be able to also move into acid */
2219 { EL_BUG_RIGHT, 1 },
2222 { EL_SPACESHIP, 2 },
2223 { EL_SPACESHIP_LEFT, 2 },
2224 { EL_SPACESHIP_RIGHT, 2 },
2225 { EL_SPACESHIP_UP, 2 },
2226 { EL_SPACESHIP_DOWN, 2 },
2227 { EL_BD_BUTTERFLY, 3 },
2228 { EL_BD_BUTTERFLY_LEFT, 3 },
2229 { EL_BD_BUTTERFLY_RIGHT, 3 },
2230 { EL_BD_BUTTERFLY_UP, 3 },
2231 { EL_BD_BUTTERFLY_DOWN, 3 },
2232 { EL_BD_FIREFLY, 4 },
2233 { EL_BD_FIREFLY_LEFT, 4 },
2234 { EL_BD_FIREFLY_RIGHT, 4 },
2235 { EL_BD_FIREFLY_UP, 4 },
2236 { EL_BD_FIREFLY_DOWN, 4 },
2238 { EL_YAMYAM_LEFT, 5 },
2239 { EL_YAMYAM_RIGHT, 5 },
2240 { EL_YAMYAM_UP, 5 },
2241 { EL_YAMYAM_DOWN, 5 },
2242 { EL_DARK_YAMYAM, 6 },
2245 { EL_PACMAN_LEFT, 8 },
2246 { EL_PACMAN_RIGHT, 8 },
2247 { EL_PACMAN_UP, 8 },
2248 { EL_PACMAN_DOWN, 8 },
2250 { EL_MOLE_LEFT, 9 },
2251 { EL_MOLE_RIGHT, 9 },
2253 { EL_MOLE_DOWN, 9 },
2257 { EL_SATELLITE, 13 },
2258 { EL_SP_SNIKSNAK, 14 },
2259 { EL_SP_ELECTRON, 15 },
2262 { EL_EMC_ANDROID, 18 },
2267 static struct PropertyBitInfo pb_dont_collide_with[] =
2269 { EL_SP_SNIKSNAK, 0 },
2270 { EL_SP_ELECTRON, 1 },
2278 struct PropertyBitInfo *pb_info;
2281 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2282 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2287 struct PropertyBitInfo *pb_info = NULL;
2290 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2291 if (pb_definition[i].bit_nr == property_bit_nr)
2292 pb_info = pb_definition[i].pb_info;
2294 if (pb_info == NULL)
2297 for (i = 0; pb_info[i].element != -1; i++)
2298 if (pb_info[i].element == element)
2299 return pb_info[i].bit_nr;
2304 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2305 boolean property_value)
2307 int bit_nr = get_special_property_bit(element, property_bit_nr);
2312 *bitfield |= (1 << bit_nr);
2314 *bitfield &= ~(1 << bit_nr);
2318 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2320 int bit_nr = get_special_property_bit(element, property_bit_nr);
2323 return ((*bitfield & (1 << bit_nr)) != 0);
2328 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2330 static int group_nr;
2331 static struct ElementGroupInfo *group;
2332 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2335 if (actual_group == NULL) /* not yet initialized */
2338 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2340 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2341 group_element - EL_GROUP_START + 1);
2343 /* replace element which caused too deep recursion by question mark */
2344 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2349 if (recursion_depth == 0) /* initialization */
2351 group = actual_group;
2352 group_nr = GROUP_NR(group_element);
2354 group->num_elements_resolved = 0;
2355 group->choice_pos = 0;
2357 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2358 element_info[i].in_group[group_nr] = FALSE;
2361 for (i = 0; i < actual_group->num_elements; i++)
2363 int element = actual_group->element[i];
2365 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2368 if (IS_GROUP_ELEMENT(element))
2369 ResolveGroupElementExt(element, recursion_depth + 1);
2372 group->element_resolved[group->num_elements_resolved++] = element;
2373 element_info[element].in_group[group_nr] = TRUE;
2378 void ResolveGroupElement(int group_element)
2380 ResolveGroupElementExt(group_element, 0);
2383 void InitElementPropertiesStatic()
2385 static boolean clipboard_elements_initialized = FALSE;
2387 static int ep_diggable[] =
2392 EL_SP_BUGGY_BASE_ACTIVATING,
2395 EL_INVISIBLE_SAND_ACTIVE,
2398 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2399 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2404 EL_SP_BUGGY_BASE_ACTIVE,
2411 static int ep_collectible_only[] =
2433 EL_DYNABOMB_INCREASE_NUMBER,
2434 EL_DYNABOMB_INCREASE_SIZE,
2435 EL_DYNABOMB_INCREASE_POWER,
2453 /* !!! handle separately !!! */
2454 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2460 static int ep_dont_run_into[] =
2462 /* same elements as in 'ep_dont_touch' */
2468 /* same elements as in 'ep_dont_collide_with' */
2480 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2485 EL_SP_BUGGY_BASE_ACTIVE,
2492 static int ep_dont_collide_with[] =
2494 /* same elements as in 'ep_dont_touch' */
2511 static int ep_dont_touch[] =
2521 static int ep_indestructible[] =
2525 EL_ACID_POOL_TOPLEFT,
2526 EL_ACID_POOL_TOPRIGHT,
2527 EL_ACID_POOL_BOTTOMLEFT,
2528 EL_ACID_POOL_BOTTOM,
2529 EL_ACID_POOL_BOTTOMRIGHT,
2530 EL_SP_HARDWARE_GRAY,
2531 EL_SP_HARDWARE_GREEN,
2532 EL_SP_HARDWARE_BLUE,
2534 EL_SP_HARDWARE_YELLOW,
2535 EL_SP_HARDWARE_BASE_1,
2536 EL_SP_HARDWARE_BASE_2,
2537 EL_SP_HARDWARE_BASE_3,
2538 EL_SP_HARDWARE_BASE_4,
2539 EL_SP_HARDWARE_BASE_5,
2540 EL_SP_HARDWARE_BASE_6,
2541 EL_INVISIBLE_STEELWALL,
2542 EL_INVISIBLE_STEELWALL_ACTIVE,
2543 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2544 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2545 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2546 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2547 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2548 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2549 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2550 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2551 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2552 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2553 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2554 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2556 EL_LIGHT_SWITCH_ACTIVE,
2557 EL_SIGN_EXCLAMATION,
2558 EL_SIGN_RADIOACTIVITY,
2565 EL_SIGN_ENTRY_FORBIDDEN,
2566 EL_SIGN_EMERGENCY_EXIT,
2574 EL_STEEL_EXIT_CLOSED,
2576 EL_STEEL_EXIT_OPENING,
2577 EL_STEEL_EXIT_CLOSING,
2578 EL_EM_STEEL_EXIT_CLOSED,
2579 EL_EM_STEEL_EXIT_OPEN,
2580 EL_EM_STEEL_EXIT_OPENING,
2581 EL_EM_STEEL_EXIT_CLOSING,
2582 EL_DC_STEELWALL_1_LEFT,
2583 EL_DC_STEELWALL_1_RIGHT,
2584 EL_DC_STEELWALL_1_TOP,
2585 EL_DC_STEELWALL_1_BOTTOM,
2586 EL_DC_STEELWALL_1_HORIZONTAL,
2587 EL_DC_STEELWALL_1_VERTICAL,
2588 EL_DC_STEELWALL_1_TOPLEFT,
2589 EL_DC_STEELWALL_1_TOPRIGHT,
2590 EL_DC_STEELWALL_1_BOTTOMLEFT,
2591 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2592 EL_DC_STEELWALL_1_TOPLEFT_2,
2593 EL_DC_STEELWALL_1_TOPRIGHT_2,
2594 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2595 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2596 EL_DC_STEELWALL_2_LEFT,
2597 EL_DC_STEELWALL_2_RIGHT,
2598 EL_DC_STEELWALL_2_TOP,
2599 EL_DC_STEELWALL_2_BOTTOM,
2600 EL_DC_STEELWALL_2_HORIZONTAL,
2601 EL_DC_STEELWALL_2_VERTICAL,
2602 EL_DC_STEELWALL_2_MIDDLE,
2603 EL_DC_STEELWALL_2_SINGLE,
2604 EL_STEELWALL_SLIPPERY,
2618 EL_GATE_1_GRAY_ACTIVE,
2619 EL_GATE_2_GRAY_ACTIVE,
2620 EL_GATE_3_GRAY_ACTIVE,
2621 EL_GATE_4_GRAY_ACTIVE,
2630 EL_EM_GATE_1_GRAY_ACTIVE,
2631 EL_EM_GATE_2_GRAY_ACTIVE,
2632 EL_EM_GATE_3_GRAY_ACTIVE,
2633 EL_EM_GATE_4_GRAY_ACTIVE,
2642 EL_EMC_GATE_5_GRAY_ACTIVE,
2643 EL_EMC_GATE_6_GRAY_ACTIVE,
2644 EL_EMC_GATE_7_GRAY_ACTIVE,
2645 EL_EMC_GATE_8_GRAY_ACTIVE,
2647 EL_DC_GATE_WHITE_GRAY,
2648 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2649 EL_DC_GATE_FAKE_GRAY,
2651 EL_SWITCHGATE_OPENING,
2652 EL_SWITCHGATE_CLOSED,
2653 EL_SWITCHGATE_CLOSING,
2654 EL_DC_SWITCHGATE_SWITCH_UP,
2655 EL_DC_SWITCHGATE_SWITCH_DOWN,
2657 EL_TIMEGATE_OPENING,
2659 EL_TIMEGATE_CLOSING,
2660 EL_DC_TIMEGATE_SWITCH,
2661 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2665 EL_TUBE_VERTICAL_LEFT,
2666 EL_TUBE_VERTICAL_RIGHT,
2667 EL_TUBE_HORIZONTAL_UP,
2668 EL_TUBE_HORIZONTAL_DOWN,
2673 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2674 EL_EXPANDABLE_STEELWALL_VERTICAL,
2675 EL_EXPANDABLE_STEELWALL_ANY,
2680 static int ep_slippery[] =
2694 EL_ROBOT_WHEEL_ACTIVE,
2700 EL_ACID_POOL_TOPLEFT,
2701 EL_ACID_POOL_TOPRIGHT,
2711 EL_STEELWALL_SLIPPERY,
2714 EL_EMC_WALL_SLIPPERY_1,
2715 EL_EMC_WALL_SLIPPERY_2,
2716 EL_EMC_WALL_SLIPPERY_3,
2717 EL_EMC_WALL_SLIPPERY_4,
2719 EL_EMC_MAGIC_BALL_ACTIVE,
2724 static int ep_can_change[] =
2729 static int ep_can_move[] =
2731 /* same elements as in 'pb_can_move_into_acid' */
2754 static int ep_can_fall[] =
2768 EL_QUICKSAND_FAST_FULL,
2770 EL_BD_MAGIC_WALL_FULL,
2771 EL_DC_MAGIC_WALL_FULL,
2785 static int ep_can_smash_player[] =
2811 static int ep_can_smash_enemies[] =
2820 static int ep_can_smash_everything[] =
2829 static int ep_explodes_by_fire[] =
2831 /* same elements as in 'ep_explodes_impact' */
2836 /* same elements as in 'ep_explodes_smashed' */
2846 EL_EM_DYNAMITE_ACTIVE,
2847 EL_DYNABOMB_PLAYER_1_ACTIVE,
2848 EL_DYNABOMB_PLAYER_2_ACTIVE,
2849 EL_DYNABOMB_PLAYER_3_ACTIVE,
2850 EL_DYNABOMB_PLAYER_4_ACTIVE,
2851 EL_DYNABOMB_INCREASE_NUMBER,
2852 EL_DYNABOMB_INCREASE_SIZE,
2853 EL_DYNABOMB_INCREASE_POWER,
2854 EL_SP_DISK_RED_ACTIVE,
2868 static int ep_explodes_smashed[] =
2870 /* same elements as in 'ep_explodes_impact' */
2884 static int ep_explodes_impact[] =
2893 static int ep_walkable_over[] =
2897 EL_SOKOBAN_FIELD_EMPTY,
2904 EL_EM_STEEL_EXIT_OPEN,
2905 EL_EM_STEEL_EXIT_OPENING,
2914 EL_GATE_1_GRAY_ACTIVE,
2915 EL_GATE_2_GRAY_ACTIVE,
2916 EL_GATE_3_GRAY_ACTIVE,
2917 EL_GATE_4_GRAY_ACTIVE,
2925 static int ep_walkable_inside[] =
2930 EL_TUBE_VERTICAL_LEFT,
2931 EL_TUBE_VERTICAL_RIGHT,
2932 EL_TUBE_HORIZONTAL_UP,
2933 EL_TUBE_HORIZONTAL_DOWN,
2942 static int ep_walkable_under[] =
2947 static int ep_passable_over[] =
2957 EL_EM_GATE_1_GRAY_ACTIVE,
2958 EL_EM_GATE_2_GRAY_ACTIVE,
2959 EL_EM_GATE_3_GRAY_ACTIVE,
2960 EL_EM_GATE_4_GRAY_ACTIVE,
2969 EL_EMC_GATE_5_GRAY_ACTIVE,
2970 EL_EMC_GATE_6_GRAY_ACTIVE,
2971 EL_EMC_GATE_7_GRAY_ACTIVE,
2972 EL_EMC_GATE_8_GRAY_ACTIVE,
2974 EL_DC_GATE_WHITE_GRAY,
2975 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2982 static int ep_passable_inside[] =
2988 EL_SP_PORT_HORIZONTAL,
2989 EL_SP_PORT_VERTICAL,
2991 EL_SP_GRAVITY_PORT_LEFT,
2992 EL_SP_GRAVITY_PORT_RIGHT,
2993 EL_SP_GRAVITY_PORT_UP,
2994 EL_SP_GRAVITY_PORT_DOWN,
2995 EL_SP_GRAVITY_ON_PORT_LEFT,
2996 EL_SP_GRAVITY_ON_PORT_RIGHT,
2997 EL_SP_GRAVITY_ON_PORT_UP,
2998 EL_SP_GRAVITY_ON_PORT_DOWN,
2999 EL_SP_GRAVITY_OFF_PORT_LEFT,
3000 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3001 EL_SP_GRAVITY_OFF_PORT_UP,
3002 EL_SP_GRAVITY_OFF_PORT_DOWN,
3007 static int ep_passable_under[] =
3012 static int ep_droppable[] =
3017 static int ep_explodes_1x1_old[] =
3022 static int ep_pushable[] =
3034 EL_SOKOBAN_FIELD_FULL,
3043 static int ep_explodes_cross_old[] =
3048 static int ep_protected[] =
3050 /* same elements as in 'ep_walkable_inside' */
3054 EL_TUBE_VERTICAL_LEFT,
3055 EL_TUBE_VERTICAL_RIGHT,
3056 EL_TUBE_HORIZONTAL_UP,
3057 EL_TUBE_HORIZONTAL_DOWN,
3063 /* same elements as in 'ep_passable_over' */
3072 EL_EM_GATE_1_GRAY_ACTIVE,
3073 EL_EM_GATE_2_GRAY_ACTIVE,
3074 EL_EM_GATE_3_GRAY_ACTIVE,
3075 EL_EM_GATE_4_GRAY_ACTIVE,
3084 EL_EMC_GATE_5_GRAY_ACTIVE,
3085 EL_EMC_GATE_6_GRAY_ACTIVE,
3086 EL_EMC_GATE_7_GRAY_ACTIVE,
3087 EL_EMC_GATE_8_GRAY_ACTIVE,
3089 EL_DC_GATE_WHITE_GRAY,
3090 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3094 /* same elements as in 'ep_passable_inside' */
3099 EL_SP_PORT_HORIZONTAL,
3100 EL_SP_PORT_VERTICAL,
3102 EL_SP_GRAVITY_PORT_LEFT,
3103 EL_SP_GRAVITY_PORT_RIGHT,
3104 EL_SP_GRAVITY_PORT_UP,
3105 EL_SP_GRAVITY_PORT_DOWN,
3106 EL_SP_GRAVITY_ON_PORT_LEFT,
3107 EL_SP_GRAVITY_ON_PORT_RIGHT,
3108 EL_SP_GRAVITY_ON_PORT_UP,
3109 EL_SP_GRAVITY_ON_PORT_DOWN,
3110 EL_SP_GRAVITY_OFF_PORT_LEFT,
3111 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3112 EL_SP_GRAVITY_OFF_PORT_UP,
3113 EL_SP_GRAVITY_OFF_PORT_DOWN,
3118 static int ep_throwable[] =
3123 static int ep_can_explode[] =
3125 /* same elements as in 'ep_explodes_impact' */
3130 /* same elements as in 'ep_explodes_smashed' */
3136 /* elements that can explode by explosion or by dragonfire */
3140 EL_EM_DYNAMITE_ACTIVE,
3141 EL_DYNABOMB_PLAYER_1_ACTIVE,
3142 EL_DYNABOMB_PLAYER_2_ACTIVE,
3143 EL_DYNABOMB_PLAYER_3_ACTIVE,
3144 EL_DYNABOMB_PLAYER_4_ACTIVE,
3145 EL_DYNABOMB_INCREASE_NUMBER,
3146 EL_DYNABOMB_INCREASE_SIZE,
3147 EL_DYNABOMB_INCREASE_POWER,
3148 EL_SP_DISK_RED_ACTIVE,
3156 /* elements that can explode only by explosion */
3162 static int ep_gravity_reachable[] =
3168 EL_INVISIBLE_SAND_ACTIVE,
3173 EL_SP_PORT_HORIZONTAL,
3174 EL_SP_PORT_VERTICAL,
3176 EL_SP_GRAVITY_PORT_LEFT,
3177 EL_SP_GRAVITY_PORT_RIGHT,
3178 EL_SP_GRAVITY_PORT_UP,
3179 EL_SP_GRAVITY_PORT_DOWN,
3180 EL_SP_GRAVITY_ON_PORT_LEFT,
3181 EL_SP_GRAVITY_ON_PORT_RIGHT,
3182 EL_SP_GRAVITY_ON_PORT_UP,
3183 EL_SP_GRAVITY_ON_PORT_DOWN,
3184 EL_SP_GRAVITY_OFF_PORT_LEFT,
3185 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3186 EL_SP_GRAVITY_OFF_PORT_UP,
3187 EL_SP_GRAVITY_OFF_PORT_DOWN,
3193 static int ep_player[] =
3200 EL_SOKOBAN_FIELD_PLAYER,
3206 static int ep_can_pass_magic_wall[] =
3220 static int ep_can_pass_dc_magic_wall[] =
3236 static int ep_switchable[] =
3240 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3241 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3242 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3243 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3244 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3245 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3246 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3247 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3248 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3249 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3250 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3251 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3252 EL_SWITCHGATE_SWITCH_UP,
3253 EL_SWITCHGATE_SWITCH_DOWN,
3254 EL_DC_SWITCHGATE_SWITCH_UP,
3255 EL_DC_SWITCHGATE_SWITCH_DOWN,
3257 EL_LIGHT_SWITCH_ACTIVE,
3259 EL_DC_TIMEGATE_SWITCH,
3260 EL_BALLOON_SWITCH_LEFT,
3261 EL_BALLOON_SWITCH_RIGHT,
3262 EL_BALLOON_SWITCH_UP,
3263 EL_BALLOON_SWITCH_DOWN,
3264 EL_BALLOON_SWITCH_ANY,
3265 EL_BALLOON_SWITCH_NONE,
3268 EL_EMC_MAGIC_BALL_SWITCH,
3269 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3274 static int ep_bd_element[] =
3308 static int ep_sp_element[] =
3310 /* should always be valid */
3313 /* standard classic Supaplex elements */
3320 EL_SP_HARDWARE_GRAY,
3328 EL_SP_GRAVITY_PORT_RIGHT,
3329 EL_SP_GRAVITY_PORT_DOWN,
3330 EL_SP_GRAVITY_PORT_LEFT,
3331 EL_SP_GRAVITY_PORT_UP,
3336 EL_SP_PORT_VERTICAL,
3337 EL_SP_PORT_HORIZONTAL,
3343 EL_SP_HARDWARE_BASE_1,
3344 EL_SP_HARDWARE_GREEN,
3345 EL_SP_HARDWARE_BLUE,
3347 EL_SP_HARDWARE_YELLOW,
3348 EL_SP_HARDWARE_BASE_2,
3349 EL_SP_HARDWARE_BASE_3,
3350 EL_SP_HARDWARE_BASE_4,
3351 EL_SP_HARDWARE_BASE_5,
3352 EL_SP_HARDWARE_BASE_6,
3356 /* additional elements that appeared in newer Supaplex levels */
3359 /* additional gravity port elements (not switching, but setting gravity) */
3360 EL_SP_GRAVITY_ON_PORT_LEFT,
3361 EL_SP_GRAVITY_ON_PORT_RIGHT,
3362 EL_SP_GRAVITY_ON_PORT_UP,
3363 EL_SP_GRAVITY_ON_PORT_DOWN,
3364 EL_SP_GRAVITY_OFF_PORT_LEFT,
3365 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3366 EL_SP_GRAVITY_OFF_PORT_UP,
3367 EL_SP_GRAVITY_OFF_PORT_DOWN,
3369 /* more than one Murphy in a level results in an inactive clone */
3372 /* runtime Supaplex elements */
3373 EL_SP_DISK_RED_ACTIVE,
3374 EL_SP_TERMINAL_ACTIVE,
3375 EL_SP_BUGGY_BASE_ACTIVATING,
3376 EL_SP_BUGGY_BASE_ACTIVE,
3383 static int ep_sb_element[] =
3388 EL_SOKOBAN_FIELD_EMPTY,
3389 EL_SOKOBAN_FIELD_FULL,
3390 EL_SOKOBAN_FIELD_PLAYER,
3395 EL_INVISIBLE_STEELWALL,
3400 static int ep_gem[] =
3412 static int ep_food_dark_yamyam[] =
3440 static int ep_food_penguin[] =
3454 static int ep_food_pig[] =
3466 static int ep_historic_wall[] =
3477 EL_GATE_1_GRAY_ACTIVE,
3478 EL_GATE_2_GRAY_ACTIVE,
3479 EL_GATE_3_GRAY_ACTIVE,
3480 EL_GATE_4_GRAY_ACTIVE,
3489 EL_EM_GATE_1_GRAY_ACTIVE,
3490 EL_EM_GATE_2_GRAY_ACTIVE,
3491 EL_EM_GATE_3_GRAY_ACTIVE,
3492 EL_EM_GATE_4_GRAY_ACTIVE,
3499 EL_EXPANDABLE_WALL_HORIZONTAL,
3500 EL_EXPANDABLE_WALL_VERTICAL,
3501 EL_EXPANDABLE_WALL_ANY,
3502 EL_EXPANDABLE_WALL_GROWING,
3503 EL_BD_EXPANDABLE_WALL,
3510 EL_SP_HARDWARE_GRAY,
3511 EL_SP_HARDWARE_GREEN,
3512 EL_SP_HARDWARE_BLUE,
3514 EL_SP_HARDWARE_YELLOW,
3515 EL_SP_HARDWARE_BASE_1,
3516 EL_SP_HARDWARE_BASE_2,
3517 EL_SP_HARDWARE_BASE_3,
3518 EL_SP_HARDWARE_BASE_4,
3519 EL_SP_HARDWARE_BASE_5,
3520 EL_SP_HARDWARE_BASE_6,
3522 EL_SP_TERMINAL_ACTIVE,
3525 EL_INVISIBLE_STEELWALL,
3526 EL_INVISIBLE_STEELWALL_ACTIVE,
3528 EL_INVISIBLE_WALL_ACTIVE,
3529 EL_STEELWALL_SLIPPERY,
3546 static int ep_historic_solid[] =
3550 EL_EXPANDABLE_WALL_HORIZONTAL,
3551 EL_EXPANDABLE_WALL_VERTICAL,
3552 EL_EXPANDABLE_WALL_ANY,
3553 EL_BD_EXPANDABLE_WALL,
3566 EL_QUICKSAND_FILLING,
3567 EL_QUICKSAND_EMPTYING,
3569 EL_MAGIC_WALL_ACTIVE,
3570 EL_MAGIC_WALL_EMPTYING,
3571 EL_MAGIC_WALL_FILLING,
3575 EL_BD_MAGIC_WALL_ACTIVE,
3576 EL_BD_MAGIC_WALL_EMPTYING,
3577 EL_BD_MAGIC_WALL_FULL,
3578 EL_BD_MAGIC_WALL_FILLING,
3579 EL_BD_MAGIC_WALL_DEAD,
3588 EL_SP_TERMINAL_ACTIVE,
3592 EL_INVISIBLE_WALL_ACTIVE,
3593 EL_SWITCHGATE_SWITCH_UP,
3594 EL_SWITCHGATE_SWITCH_DOWN,
3595 EL_DC_SWITCHGATE_SWITCH_UP,
3596 EL_DC_SWITCHGATE_SWITCH_DOWN,
3598 EL_TIMEGATE_SWITCH_ACTIVE,
3599 EL_DC_TIMEGATE_SWITCH,
3600 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3612 /* the following elements are a direct copy of "indestructible" elements,
3613 except "EL_ACID", which is "indestructible", but not "solid"! */
3618 EL_ACID_POOL_TOPLEFT,
3619 EL_ACID_POOL_TOPRIGHT,
3620 EL_ACID_POOL_BOTTOMLEFT,
3621 EL_ACID_POOL_BOTTOM,
3622 EL_ACID_POOL_BOTTOMRIGHT,
3623 EL_SP_HARDWARE_GRAY,
3624 EL_SP_HARDWARE_GREEN,
3625 EL_SP_HARDWARE_BLUE,
3627 EL_SP_HARDWARE_YELLOW,
3628 EL_SP_HARDWARE_BASE_1,
3629 EL_SP_HARDWARE_BASE_2,
3630 EL_SP_HARDWARE_BASE_3,
3631 EL_SP_HARDWARE_BASE_4,
3632 EL_SP_HARDWARE_BASE_5,
3633 EL_SP_HARDWARE_BASE_6,
3634 EL_INVISIBLE_STEELWALL,
3635 EL_INVISIBLE_STEELWALL_ACTIVE,
3636 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3637 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3638 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3639 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3640 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3641 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3642 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3643 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3644 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3645 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3646 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3647 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3649 EL_LIGHT_SWITCH_ACTIVE,
3650 EL_SIGN_EXCLAMATION,
3651 EL_SIGN_RADIOACTIVITY,
3658 EL_SIGN_ENTRY_FORBIDDEN,
3659 EL_SIGN_EMERGENCY_EXIT,
3667 EL_STEEL_EXIT_CLOSED,
3669 EL_DC_STEELWALL_1_LEFT,
3670 EL_DC_STEELWALL_1_RIGHT,
3671 EL_DC_STEELWALL_1_TOP,
3672 EL_DC_STEELWALL_1_BOTTOM,
3673 EL_DC_STEELWALL_1_HORIZONTAL,
3674 EL_DC_STEELWALL_1_VERTICAL,
3675 EL_DC_STEELWALL_1_TOPLEFT,
3676 EL_DC_STEELWALL_1_TOPRIGHT,
3677 EL_DC_STEELWALL_1_BOTTOMLEFT,
3678 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3679 EL_DC_STEELWALL_1_TOPLEFT_2,
3680 EL_DC_STEELWALL_1_TOPRIGHT_2,
3681 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3682 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3683 EL_DC_STEELWALL_2_LEFT,
3684 EL_DC_STEELWALL_2_RIGHT,
3685 EL_DC_STEELWALL_2_TOP,
3686 EL_DC_STEELWALL_2_BOTTOM,
3687 EL_DC_STEELWALL_2_HORIZONTAL,
3688 EL_DC_STEELWALL_2_VERTICAL,
3689 EL_DC_STEELWALL_2_MIDDLE,
3690 EL_DC_STEELWALL_2_SINGLE,
3691 EL_STEELWALL_SLIPPERY,
3705 EL_GATE_1_GRAY_ACTIVE,
3706 EL_GATE_2_GRAY_ACTIVE,
3707 EL_GATE_3_GRAY_ACTIVE,
3708 EL_GATE_4_GRAY_ACTIVE,
3717 EL_EM_GATE_1_GRAY_ACTIVE,
3718 EL_EM_GATE_2_GRAY_ACTIVE,
3719 EL_EM_GATE_3_GRAY_ACTIVE,
3720 EL_EM_GATE_4_GRAY_ACTIVE,
3722 EL_SWITCHGATE_OPENING,
3723 EL_SWITCHGATE_CLOSED,
3724 EL_SWITCHGATE_CLOSING,
3726 EL_TIMEGATE_OPENING,
3728 EL_TIMEGATE_CLOSING,
3732 EL_TUBE_VERTICAL_LEFT,
3733 EL_TUBE_VERTICAL_RIGHT,
3734 EL_TUBE_HORIZONTAL_UP,
3735 EL_TUBE_HORIZONTAL_DOWN,
3744 static int ep_classic_enemy[] =
3761 static int ep_belt[] =
3763 EL_CONVEYOR_BELT_1_LEFT,
3764 EL_CONVEYOR_BELT_1_MIDDLE,
3765 EL_CONVEYOR_BELT_1_RIGHT,
3766 EL_CONVEYOR_BELT_2_LEFT,
3767 EL_CONVEYOR_BELT_2_MIDDLE,
3768 EL_CONVEYOR_BELT_2_RIGHT,
3769 EL_CONVEYOR_BELT_3_LEFT,
3770 EL_CONVEYOR_BELT_3_MIDDLE,
3771 EL_CONVEYOR_BELT_3_RIGHT,
3772 EL_CONVEYOR_BELT_4_LEFT,
3773 EL_CONVEYOR_BELT_4_MIDDLE,
3774 EL_CONVEYOR_BELT_4_RIGHT,
3779 static int ep_belt_active[] =
3781 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3782 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3783 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3784 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3785 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3786 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3787 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3788 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3789 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3790 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3791 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3792 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3797 static int ep_belt_switch[] =
3799 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3800 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3801 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3802 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3803 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3804 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3805 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3806 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3807 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3808 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3809 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3810 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3815 static int ep_tube[] =
3822 EL_TUBE_HORIZONTAL_UP,
3823 EL_TUBE_HORIZONTAL_DOWN,
3825 EL_TUBE_VERTICAL_LEFT,
3826 EL_TUBE_VERTICAL_RIGHT,
3832 static int ep_acid_pool[] =
3834 EL_ACID_POOL_TOPLEFT,
3835 EL_ACID_POOL_TOPRIGHT,
3836 EL_ACID_POOL_BOTTOMLEFT,
3837 EL_ACID_POOL_BOTTOM,
3838 EL_ACID_POOL_BOTTOMRIGHT,
3843 static int ep_keygate[] =
3853 EL_GATE_1_GRAY_ACTIVE,
3854 EL_GATE_2_GRAY_ACTIVE,
3855 EL_GATE_3_GRAY_ACTIVE,
3856 EL_GATE_4_GRAY_ACTIVE,
3865 EL_EM_GATE_1_GRAY_ACTIVE,
3866 EL_EM_GATE_2_GRAY_ACTIVE,
3867 EL_EM_GATE_3_GRAY_ACTIVE,
3868 EL_EM_GATE_4_GRAY_ACTIVE,
3877 EL_EMC_GATE_5_GRAY_ACTIVE,
3878 EL_EMC_GATE_6_GRAY_ACTIVE,
3879 EL_EMC_GATE_7_GRAY_ACTIVE,
3880 EL_EMC_GATE_8_GRAY_ACTIVE,
3882 EL_DC_GATE_WHITE_GRAY,
3883 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3888 static int ep_amoeboid[] =
3900 static int ep_amoebalive[] =
3911 static int ep_has_editor_content[] =
3917 EL_SOKOBAN_FIELD_PLAYER,
3934 static int ep_can_turn_each_move[] =
3936 /* !!! do something with this one !!! */
3940 static int ep_can_grow[] =
3954 static int ep_active_bomb[] =
3957 EL_EM_DYNAMITE_ACTIVE,
3958 EL_DYNABOMB_PLAYER_1_ACTIVE,
3959 EL_DYNABOMB_PLAYER_2_ACTIVE,
3960 EL_DYNABOMB_PLAYER_3_ACTIVE,
3961 EL_DYNABOMB_PLAYER_4_ACTIVE,
3962 EL_SP_DISK_RED_ACTIVE,
3967 static int ep_inactive[] =
3977 EL_QUICKSAND_FAST_EMPTY,
4000 EL_GATE_1_GRAY_ACTIVE,
4001 EL_GATE_2_GRAY_ACTIVE,
4002 EL_GATE_3_GRAY_ACTIVE,
4003 EL_GATE_4_GRAY_ACTIVE,
4012 EL_EM_GATE_1_GRAY_ACTIVE,
4013 EL_EM_GATE_2_GRAY_ACTIVE,
4014 EL_EM_GATE_3_GRAY_ACTIVE,
4015 EL_EM_GATE_4_GRAY_ACTIVE,
4024 EL_EMC_GATE_5_GRAY_ACTIVE,
4025 EL_EMC_GATE_6_GRAY_ACTIVE,
4026 EL_EMC_GATE_7_GRAY_ACTIVE,
4027 EL_EMC_GATE_8_GRAY_ACTIVE,
4029 EL_DC_GATE_WHITE_GRAY,
4030 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4031 EL_DC_GATE_FAKE_GRAY,
4034 EL_INVISIBLE_STEELWALL,
4042 EL_WALL_EMERALD_YELLOW,
4043 EL_DYNABOMB_INCREASE_NUMBER,
4044 EL_DYNABOMB_INCREASE_SIZE,
4045 EL_DYNABOMB_INCREASE_POWER,
4049 EL_SOKOBAN_FIELD_EMPTY,
4050 EL_SOKOBAN_FIELD_FULL,
4051 EL_WALL_EMERALD_RED,
4052 EL_WALL_EMERALD_PURPLE,
4053 EL_ACID_POOL_TOPLEFT,
4054 EL_ACID_POOL_TOPRIGHT,
4055 EL_ACID_POOL_BOTTOMLEFT,
4056 EL_ACID_POOL_BOTTOM,
4057 EL_ACID_POOL_BOTTOMRIGHT,
4061 EL_BD_MAGIC_WALL_DEAD,
4063 EL_DC_MAGIC_WALL_DEAD,
4064 EL_AMOEBA_TO_DIAMOND,
4072 EL_SP_GRAVITY_PORT_RIGHT,
4073 EL_SP_GRAVITY_PORT_DOWN,
4074 EL_SP_GRAVITY_PORT_LEFT,
4075 EL_SP_GRAVITY_PORT_UP,
4076 EL_SP_PORT_HORIZONTAL,
4077 EL_SP_PORT_VERTICAL,
4088 EL_SP_HARDWARE_GRAY,
4089 EL_SP_HARDWARE_GREEN,
4090 EL_SP_HARDWARE_BLUE,
4092 EL_SP_HARDWARE_YELLOW,
4093 EL_SP_HARDWARE_BASE_1,
4094 EL_SP_HARDWARE_BASE_2,
4095 EL_SP_HARDWARE_BASE_3,
4096 EL_SP_HARDWARE_BASE_4,
4097 EL_SP_HARDWARE_BASE_5,
4098 EL_SP_HARDWARE_BASE_6,
4099 EL_SP_GRAVITY_ON_PORT_LEFT,
4100 EL_SP_GRAVITY_ON_PORT_RIGHT,
4101 EL_SP_GRAVITY_ON_PORT_UP,
4102 EL_SP_GRAVITY_ON_PORT_DOWN,
4103 EL_SP_GRAVITY_OFF_PORT_LEFT,
4104 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4105 EL_SP_GRAVITY_OFF_PORT_UP,
4106 EL_SP_GRAVITY_OFF_PORT_DOWN,
4107 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4108 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4109 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4110 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4111 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4112 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4113 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4114 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4115 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4116 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4117 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4118 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4119 EL_SIGN_EXCLAMATION,
4120 EL_SIGN_RADIOACTIVITY,
4127 EL_SIGN_ENTRY_FORBIDDEN,
4128 EL_SIGN_EMERGENCY_EXIT,
4136 EL_DC_STEELWALL_1_LEFT,
4137 EL_DC_STEELWALL_1_RIGHT,
4138 EL_DC_STEELWALL_1_TOP,
4139 EL_DC_STEELWALL_1_BOTTOM,
4140 EL_DC_STEELWALL_1_HORIZONTAL,
4141 EL_DC_STEELWALL_1_VERTICAL,
4142 EL_DC_STEELWALL_1_TOPLEFT,
4143 EL_DC_STEELWALL_1_TOPRIGHT,
4144 EL_DC_STEELWALL_1_BOTTOMLEFT,
4145 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4146 EL_DC_STEELWALL_1_TOPLEFT_2,
4147 EL_DC_STEELWALL_1_TOPRIGHT_2,
4148 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4149 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4150 EL_DC_STEELWALL_2_LEFT,
4151 EL_DC_STEELWALL_2_RIGHT,
4152 EL_DC_STEELWALL_2_TOP,
4153 EL_DC_STEELWALL_2_BOTTOM,
4154 EL_DC_STEELWALL_2_HORIZONTAL,
4155 EL_DC_STEELWALL_2_VERTICAL,
4156 EL_DC_STEELWALL_2_MIDDLE,
4157 EL_DC_STEELWALL_2_SINGLE,
4158 EL_STEELWALL_SLIPPERY,
4163 EL_EMC_WALL_SLIPPERY_1,
4164 EL_EMC_WALL_SLIPPERY_2,
4165 EL_EMC_WALL_SLIPPERY_3,
4166 EL_EMC_WALL_SLIPPERY_4,
4187 static int ep_em_slippery_wall[] =
4192 static int ep_gfx_crumbled[] =
4203 static int ep_editor_cascade_active[] =
4205 EL_INTERNAL_CASCADE_BD_ACTIVE,
4206 EL_INTERNAL_CASCADE_EM_ACTIVE,
4207 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4208 EL_INTERNAL_CASCADE_RND_ACTIVE,
4209 EL_INTERNAL_CASCADE_SB_ACTIVE,
4210 EL_INTERNAL_CASCADE_SP_ACTIVE,
4211 EL_INTERNAL_CASCADE_DC_ACTIVE,
4212 EL_INTERNAL_CASCADE_DX_ACTIVE,
4213 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4214 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4215 EL_INTERNAL_CASCADE_CE_ACTIVE,
4216 EL_INTERNAL_CASCADE_GE_ACTIVE,
4217 EL_INTERNAL_CASCADE_REF_ACTIVE,
4218 EL_INTERNAL_CASCADE_USER_ACTIVE,
4219 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4224 static int ep_editor_cascade_inactive[] =
4226 EL_INTERNAL_CASCADE_BD,
4227 EL_INTERNAL_CASCADE_EM,
4228 EL_INTERNAL_CASCADE_EMC,
4229 EL_INTERNAL_CASCADE_RND,
4230 EL_INTERNAL_CASCADE_SB,
4231 EL_INTERNAL_CASCADE_SP,
4232 EL_INTERNAL_CASCADE_DC,
4233 EL_INTERNAL_CASCADE_DX,
4234 EL_INTERNAL_CASCADE_CHARS,
4235 EL_INTERNAL_CASCADE_STEEL_CHARS,
4236 EL_INTERNAL_CASCADE_CE,
4237 EL_INTERNAL_CASCADE_GE,
4238 EL_INTERNAL_CASCADE_REF,
4239 EL_INTERNAL_CASCADE_USER,
4240 EL_INTERNAL_CASCADE_DYNAMIC,
4245 static int ep_obsolete[] =
4249 EL_EM_KEY_1_FILE_OBSOLETE,
4250 EL_EM_KEY_2_FILE_OBSOLETE,
4251 EL_EM_KEY_3_FILE_OBSOLETE,
4252 EL_EM_KEY_4_FILE_OBSOLETE,
4253 EL_ENVELOPE_OBSOLETE,
4262 } element_properties[] =
4264 { ep_diggable, EP_DIGGABLE },
4265 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4266 { ep_dont_run_into, EP_DONT_RUN_INTO },
4267 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4268 { ep_dont_touch, EP_DONT_TOUCH },
4269 { ep_indestructible, EP_INDESTRUCTIBLE },
4270 { ep_slippery, EP_SLIPPERY },
4271 { ep_can_change, EP_CAN_CHANGE },
4272 { ep_can_move, EP_CAN_MOVE },
4273 { ep_can_fall, EP_CAN_FALL },
4274 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4275 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4276 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4277 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4278 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4279 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4280 { ep_walkable_over, EP_WALKABLE_OVER },
4281 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4282 { ep_walkable_under, EP_WALKABLE_UNDER },
4283 { ep_passable_over, EP_PASSABLE_OVER },
4284 { ep_passable_inside, EP_PASSABLE_INSIDE },
4285 { ep_passable_under, EP_PASSABLE_UNDER },
4286 { ep_droppable, EP_DROPPABLE },
4287 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4288 { ep_pushable, EP_PUSHABLE },
4289 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4290 { ep_protected, EP_PROTECTED },
4291 { ep_throwable, EP_THROWABLE },
4292 { ep_can_explode, EP_CAN_EXPLODE },
4293 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4295 { ep_player, EP_PLAYER },
4296 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4297 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4298 { ep_switchable, EP_SWITCHABLE },
4299 { ep_bd_element, EP_BD_ELEMENT },
4300 { ep_sp_element, EP_SP_ELEMENT },
4301 { ep_sb_element, EP_SB_ELEMENT },
4303 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4304 { ep_food_penguin, EP_FOOD_PENGUIN },
4305 { ep_food_pig, EP_FOOD_PIG },
4306 { ep_historic_wall, EP_HISTORIC_WALL },
4307 { ep_historic_solid, EP_HISTORIC_SOLID },
4308 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4309 { ep_belt, EP_BELT },
4310 { ep_belt_active, EP_BELT_ACTIVE },
4311 { ep_belt_switch, EP_BELT_SWITCH },
4312 { ep_tube, EP_TUBE },
4313 { ep_acid_pool, EP_ACID_POOL },
4314 { ep_keygate, EP_KEYGATE },
4315 { ep_amoeboid, EP_AMOEBOID },
4316 { ep_amoebalive, EP_AMOEBALIVE },
4317 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4318 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4319 { ep_can_grow, EP_CAN_GROW },
4320 { ep_active_bomb, EP_ACTIVE_BOMB },
4321 { ep_inactive, EP_INACTIVE },
4323 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4325 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4327 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4328 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4330 { ep_obsolete, EP_OBSOLETE },
4337 /* always start with reliable default values (element has no properties) */
4338 /* (but never initialize clipboard elements after the very first time) */
4339 /* (to be able to use clipboard elements between several levels) */
4340 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4341 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4342 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4343 SET_PROPERTY(i, j, FALSE);
4345 /* set all base element properties from above array definitions */
4346 for (i = 0; element_properties[i].elements != NULL; i++)
4347 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4348 SET_PROPERTY((element_properties[i].elements)[j],
4349 element_properties[i].property, TRUE);
4351 /* copy properties to some elements that are only stored in level file */
4352 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4353 for (j = 0; copy_properties[j][0] != -1; j++)
4354 if (HAS_PROPERTY(copy_properties[j][0], i))
4355 for (k = 1; k <= 4; k++)
4356 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4358 /* set static element properties that are not listed in array definitions */
4359 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4360 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4362 clipboard_elements_initialized = TRUE;
4365 void InitElementPropertiesEngine(int engine_version)
4367 static int no_wall_properties[] =
4370 EP_COLLECTIBLE_ONLY,
4372 EP_DONT_COLLIDE_WITH,
4375 EP_CAN_SMASH_PLAYER,
4376 EP_CAN_SMASH_ENEMIES,
4377 EP_CAN_SMASH_EVERYTHING,
4382 EP_FOOD_DARK_YAMYAM,
4398 /* important: after initialization in InitElementPropertiesStatic(), the
4399 elements are not again initialized to a default value; therefore all
4400 changes have to make sure that they leave the element with a defined
4401 property (which means that conditional property changes must be set to
4402 a reliable default value before) */
4404 /* resolve group elements */
4405 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4406 ResolveGroupElement(EL_GROUP_START + i);
4408 /* set all special, combined or engine dependent element properties */
4409 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4411 /* do not change (already initialized) clipboard elements here */
4412 if (IS_CLIPBOARD_ELEMENT(i))
4415 /* ---------- INACTIVE ------------------------------------------------- */
4416 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4417 i <= EL_CHAR_END) ||
4418 (i >= EL_STEEL_CHAR_START &&
4419 i <= EL_STEEL_CHAR_END)));
4421 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4422 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4423 IS_WALKABLE_INSIDE(i) ||
4424 IS_WALKABLE_UNDER(i)));
4426 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4427 IS_PASSABLE_INSIDE(i) ||
4428 IS_PASSABLE_UNDER(i)));
4430 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4431 IS_PASSABLE_OVER(i)));
4433 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4434 IS_PASSABLE_INSIDE(i)));
4436 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4437 IS_PASSABLE_UNDER(i)));
4439 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4442 /* ---------- COLLECTIBLE ---------------------------------------------- */
4443 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4447 /* ---------- SNAPPABLE ------------------------------------------------ */
4448 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4449 IS_COLLECTIBLE(i) ||
4453 /* ---------- WALL ----------------------------------------------------- */
4454 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4456 for (j = 0; no_wall_properties[j] != -1; j++)
4457 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4458 i >= EL_FIRST_RUNTIME_UNREAL)
4459 SET_PROPERTY(i, EP_WALL, FALSE);
4461 if (IS_HISTORIC_WALL(i))
4462 SET_PROPERTY(i, EP_WALL, TRUE);
4464 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4465 if (engine_version < VERSION_IDENT(2,2,0,0))
4466 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4468 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4470 !IS_COLLECTIBLE(i)));
4472 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4473 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4474 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4476 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4477 IS_INDESTRUCTIBLE(i)));
4479 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4481 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4482 else if (engine_version < VERSION_IDENT(2,2,0,0))
4483 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4485 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4489 if (IS_CUSTOM_ELEMENT(i))
4491 /* these are additional properties which are initially false when set */
4493 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4495 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4496 if (DONT_COLLIDE_WITH(i))
4497 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4499 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4500 if (CAN_SMASH_EVERYTHING(i))
4501 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4502 if (CAN_SMASH_ENEMIES(i))
4503 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4506 /* ---------- CAN_SMASH ------------------------------------------------ */
4507 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4508 CAN_SMASH_ENEMIES(i) ||
4509 CAN_SMASH_EVERYTHING(i)));
4511 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4512 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4513 EXPLODES_BY_FIRE(i)));
4515 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4516 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4517 EXPLODES_SMASHED(i)));
4519 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4520 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4521 EXPLODES_IMPACT(i)));
4523 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4524 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4526 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4527 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4528 i == EL_BLACK_ORB));
4530 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4531 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4533 IS_CUSTOM_ELEMENT(i)));
4535 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4536 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4537 i == EL_SP_ELECTRON));
4539 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4540 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4541 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4542 getMoveIntoAcidProperty(&level, i));
4544 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4545 if (MAYBE_DONT_COLLIDE_WITH(i))
4546 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4547 getDontCollideWithProperty(&level, i));
4549 /* ---------- SP_PORT -------------------------------------------------- */
4550 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4551 IS_PASSABLE_INSIDE(i)));
4553 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4554 for (j = 0; j < level.num_android_clone_elements; j++)
4555 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4557 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4559 /* ---------- CAN_CHANGE ----------------------------------------------- */
4560 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4561 for (j = 0; j < element_info[i].num_change_pages; j++)
4562 if (element_info[i].change_page[j].can_change)
4563 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4565 /* ---------- HAS_ACTION ----------------------------------------------- */
4566 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4567 for (j = 0; j < element_info[i].num_change_pages; j++)
4568 if (element_info[i].change_page[j].has_action)
4569 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4571 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4572 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4575 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4576 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4577 element_info[i].crumbled[ACTION_DEFAULT] !=
4578 element_info[i].graphic[ACTION_DEFAULT]);
4580 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4581 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4582 IS_EDITOR_CASCADE_INACTIVE(i)));
4585 /* dynamically adjust element properties according to game engine version */
4587 static int ep_em_slippery_wall[] =
4592 EL_EXPANDABLE_WALL_HORIZONTAL,
4593 EL_EXPANDABLE_WALL_VERTICAL,
4594 EL_EXPANDABLE_WALL_ANY,
4595 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4596 EL_EXPANDABLE_STEELWALL_VERTICAL,
4597 EL_EXPANDABLE_STEELWALL_ANY,
4598 EL_EXPANDABLE_STEELWALL_GROWING,
4602 static int ep_em_explodes_by_fire[] =
4605 EL_EM_DYNAMITE_ACTIVE,
4610 /* special EM style gems behaviour */
4611 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4612 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4613 level.em_slippery_gems);
4615 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4616 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4617 (level.em_slippery_gems &&
4618 engine_version > VERSION_IDENT(2,0,1,0)));
4620 /* special EM style explosion behaviour regarding chain reactions */
4621 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4622 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4623 level.em_explodes_by_fire);
4626 /* this is needed because some graphics depend on element properties */
4627 if (game_status == GAME_MODE_PLAYING)
4628 InitElementGraphicInfo();
4631 void InitElementPropertiesAfterLoading(int engine_version)
4635 /* set some other uninitialized values of custom elements in older levels */
4636 if (engine_version < VERSION_IDENT(3,1,0,0))
4638 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4640 int element = EL_CUSTOM_START + i;
4642 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4644 element_info[element].explosion_delay = 17;
4645 element_info[element].ignition_delay = 8;
4650 void InitElementPropertiesGfxElement()
4654 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4656 struct ElementInfo *ei = &element_info[i];
4658 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4662 static void InitGlobal()
4667 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4669 /* check if element_name_info entry defined for each element in "main.h" */
4670 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4671 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4673 element_info[i].token_name = element_name_info[i].token_name;
4674 element_info[i].class_name = element_name_info[i].class_name;
4675 element_info[i].editor_description= element_name_info[i].editor_description;
4678 /* create hash from image config list */
4679 image_config_hash = newSetupFileHash();
4680 for (i = 0; image_config[i].token != NULL; i++)
4681 setHashEntry(image_config_hash,
4682 image_config[i].token,
4683 image_config[i].value);
4685 /* create hash from element token list */
4686 element_token_hash = newSetupFileHash();
4687 for (i = 0; element_name_info[i].token_name != NULL; i++)
4688 setHashEntry(element_token_hash,
4689 element_name_info[i].token_name,
4692 /* create hash from graphic token list */
4693 graphic_token_hash = newSetupFileHash();
4694 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4695 if (strSuffix(image_config[i].value, ".png") ||
4696 strSuffix(image_config[i].value, ".pcx") ||
4697 strSuffix(image_config[i].value, ".wav") ||
4698 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4699 setHashEntry(graphic_token_hash,
4700 image_config[i].token,
4701 int2str(graphic++, 0));
4703 /* create hash from font token list */
4704 font_token_hash = newSetupFileHash();
4705 for (i = 0; font_info[i].token_name != NULL; i++)
4706 setHashEntry(font_token_hash,
4707 font_info[i].token_name,
4710 /* set default filenames for all cloned graphics in static configuration */
4711 for (i = 0; image_config[i].token != NULL; i++)
4713 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4715 char *token = image_config[i].token;
4716 char *token_clone_from = getStringCat2(token, ".clone_from");
4717 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4719 if (token_cloned != NULL)
4721 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4723 if (value_cloned != NULL)
4725 /* set default filename in static configuration */
4726 image_config[i].value = value_cloned;
4728 /* set default filename in image config hash */
4729 setHashEntry(image_config_hash, token, value_cloned);
4733 free(token_clone_from);
4737 /* always start with reliable default values (all elements) */
4738 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4739 ActiveElement[i] = i;
4741 /* now add all entries that have an active state (active elements) */
4742 for (i = 0; element_with_active_state[i].element != -1; i++)
4744 int element = element_with_active_state[i].element;
4745 int element_active = element_with_active_state[i].element_active;
4747 ActiveElement[element] = element_active;
4750 /* always start with reliable default values (all buttons) */
4751 for (i = 0; i < NUM_IMAGE_FILES; i++)
4752 ActiveButton[i] = i;
4754 /* now add all entries that have an active state (active buttons) */
4755 for (i = 0; button_with_active_state[i].button != -1; i++)
4757 int button = button_with_active_state[i].button;
4758 int button_active = button_with_active_state[i].button_active;
4760 ActiveButton[button] = button_active;
4763 /* always start with reliable default values (all fonts) */
4764 for (i = 0; i < NUM_FONTS; i++)
4767 /* now add all entries that have an active state (active fonts) */
4768 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4770 int font = font_with_active_state[i].font_nr;
4771 int font_active = font_with_active_state[i].font_nr_active;
4773 ActiveFont[font] = font_active;
4776 global.autoplay_leveldir = NULL;
4777 global.convert_leveldir = NULL;
4778 global.create_images_dir = NULL;
4780 global.frames_per_second = 0;
4782 global.border_status = GAME_MODE_LOADING;
4783 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4785 global.use_envelope_request = FALSE;
4788 void Execute_Command(char *command)
4792 if (strEqual(command, "print graphicsinfo.conf"))
4794 Print("# You can configure additional/alternative image files here.\n");
4795 Print("# (The entries below are default and therefore commented out.)\n");
4797 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4799 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4802 for (i = 0; image_config[i].token != NULL; i++)
4803 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4804 image_config[i].value));
4808 else if (strEqual(command, "print soundsinfo.conf"))
4810 Print("# You can configure additional/alternative sound files here.\n");
4811 Print("# (The entries below are default and therefore commented out.)\n");
4813 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4815 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4818 for (i = 0; sound_config[i].token != NULL; i++)
4819 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4820 sound_config[i].value));
4824 else if (strEqual(command, "print musicinfo.conf"))
4826 Print("# You can configure additional/alternative music files here.\n");
4827 Print("# (The entries below are default and therefore commented out.)\n");
4829 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4831 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4834 for (i = 0; music_config[i].token != NULL; i++)
4835 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4836 music_config[i].value));
4840 else if (strEqual(command, "print editorsetup.conf"))
4842 Print("# You can configure your personal editor element list here.\n");
4843 Print("# (The entries below are default and therefore commented out.)\n");
4846 /* this is needed to be able to check element list for cascade elements */
4847 InitElementPropertiesStatic();
4848 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4850 PrintEditorElementList();
4854 else if (strEqual(command, "print helpanim.conf"))
4856 Print("# You can configure different element help animations here.\n");
4857 Print("# (The entries below are default and therefore commented out.)\n");
4860 for (i = 0; helpanim_config[i].token != NULL; i++)
4862 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4863 helpanim_config[i].value));
4865 if (strEqual(helpanim_config[i].token, "end"))
4871 else if (strEqual(command, "print helptext.conf"))
4873 Print("# You can configure different element help text here.\n");
4874 Print("# (The entries below are default and therefore commented out.)\n");
4877 for (i = 0; helptext_config[i].token != NULL; i++)
4878 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4879 helptext_config[i].value));
4883 else if (strPrefix(command, "dump level "))
4885 char *filename = &command[11];
4887 if (!fileExists(filename))
4888 Error(ERR_EXIT, "cannot open file '%s'", filename);
4890 LoadLevelFromFilename(&level, filename);
4895 else if (strPrefix(command, "dump tape "))
4897 char *filename = &command[10];
4899 if (!fileExists(filename))
4900 Error(ERR_EXIT, "cannot open file '%s'", filename);
4902 LoadTapeFromFilename(filename);
4907 else if (strPrefix(command, "autotest ") ||
4908 strPrefix(command, "autoplay ") ||
4909 strPrefix(command, "autoffwd ") ||
4910 strPrefix(command, "autowarp "))
4912 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4914 global.autoplay_mode =
4915 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
4916 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
4917 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
4918 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
4919 AUTOPLAY_MODE_NONE);
4921 while (*str_ptr != '\0') /* continue parsing string */
4923 /* cut leading whitespace from string, replace it by string terminator */
4924 while (*str_ptr == ' ' || *str_ptr == '\t')
4927 if (*str_ptr == '\0') /* end of string reached */
4930 if (global.autoplay_leveldir == NULL) /* read level set string */
4932 global.autoplay_leveldir = str_ptr;
4933 global.autoplay_all = TRUE; /* default: play all tapes */
4935 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4936 global.autoplay_level[i] = FALSE;
4938 else /* read level number string */
4940 int level_nr = atoi(str_ptr); /* get level_nr value */
4942 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4943 global.autoplay_level[level_nr] = TRUE;
4945 global.autoplay_all = FALSE;
4948 /* advance string pointer to the next whitespace (or end of string) */
4949 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4953 else if (strPrefix(command, "convert "))
4955 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4956 char *str_ptr = strchr(str_copy, ' ');
4958 global.convert_leveldir = str_copy;
4959 global.convert_level_nr = -1;
4961 if (str_ptr != NULL) /* level number follows */
4963 *str_ptr++ = '\0'; /* terminate leveldir string */
4964 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4967 else if (strPrefix(command, "create images "))
4969 global.create_images_dir = getStringCopy(&command[14]);
4971 if (access(global.create_images_dir, W_OK) != 0)
4972 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4973 global.create_images_dir);
4975 else if (strPrefix(command, "create CE image "))
4977 CreateCustomElementImages(&command[16]);
4983 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4987 static void InitSetup()
4989 LoadSetup(); /* global setup info */
4991 /* set some options from setup file */
4993 if (setup.options.verbose)
4994 options.verbose = TRUE;
4997 static void InitGameInfo()
4999 game.restart_level = FALSE;
5002 static void InitPlayerInfo()
5006 /* choose default local player */
5007 local_player = &stored_player[0];
5009 for (i = 0; i < MAX_PLAYERS; i++)
5010 stored_player[i].connected = FALSE;
5012 local_player->connected = TRUE;
5015 static void InitArtworkInfo()
5020 static char *get_string_in_brackets(char *string)
5022 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5024 sprintf(string_in_brackets, "[%s]", string);
5026 return string_in_brackets;
5029 static char *get_level_id_suffix(int id_nr)
5031 char *id_suffix = checked_malloc(1 + 3 + 1);
5033 if (id_nr < 0 || id_nr > 999)
5036 sprintf(id_suffix, ".%03d", id_nr);
5041 static void InitArtworkConfig()
5043 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5045 NUM_GLOBAL_ANIM_TOKENS + 1];
5046 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5047 NUM_GLOBAL_ANIM_TOKENS + 1];
5048 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5049 NUM_GLOBAL_ANIM_TOKENS + 1];
5050 static char *action_id_suffix[NUM_ACTIONS + 1];
5051 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5052 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5053 static char *level_id_suffix[MAX_LEVELS + 1];
5054 static char *dummy[1] = { NULL };
5055 static char *ignore_generic_tokens[] =
5061 static char **ignore_image_tokens;
5062 static char **ignore_sound_tokens;
5063 static char **ignore_music_tokens;
5064 int num_ignore_generic_tokens;
5065 int num_ignore_image_tokens;
5066 int num_ignore_sound_tokens;
5067 int num_ignore_music_tokens;
5070 /* dynamically determine list of generic tokens to be ignored */
5071 num_ignore_generic_tokens = 0;
5072 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5073 num_ignore_generic_tokens++;
5075 /* dynamically determine list of image tokens to be ignored */
5076 num_ignore_image_tokens = num_ignore_generic_tokens;
5077 for (i = 0; image_config_vars[i].token != NULL; i++)
5078 num_ignore_image_tokens++;
5079 ignore_image_tokens =
5080 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5081 for (i = 0; i < num_ignore_generic_tokens; i++)
5082 ignore_image_tokens[i] = ignore_generic_tokens[i];
5083 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5084 ignore_image_tokens[num_ignore_generic_tokens + i] =
5085 image_config_vars[i].token;
5086 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5088 /* dynamically determine list of sound tokens to be ignored */
5089 num_ignore_sound_tokens = num_ignore_generic_tokens;
5090 ignore_sound_tokens =
5091 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5092 for (i = 0; i < num_ignore_generic_tokens; i++)
5093 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5094 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5096 /* dynamically determine list of music tokens to be ignored */
5097 num_ignore_music_tokens = num_ignore_generic_tokens;
5098 ignore_music_tokens =
5099 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5100 for (i = 0; i < num_ignore_generic_tokens; i++)
5101 ignore_music_tokens[i] = ignore_generic_tokens[i];
5102 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5104 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5105 image_id_prefix[i] = element_info[i].token_name;
5106 for (i = 0; i < NUM_FONTS; i++)
5107 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5108 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5109 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5110 global_anim_info[i].token_name;
5111 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5113 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5114 sound_id_prefix[i] = element_info[i].token_name;
5115 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5116 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5117 get_string_in_brackets(element_info[i].class_name);
5118 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5119 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5120 global_anim_info[i].token_name;
5121 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5123 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5124 music_id_prefix[i] = music_prefix_info[i].prefix;
5125 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5126 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5127 global_anim_info[i].token_name;
5128 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5130 for (i = 0; i < NUM_ACTIONS; i++)
5131 action_id_suffix[i] = element_action_info[i].suffix;
5132 action_id_suffix[NUM_ACTIONS] = NULL;
5134 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5135 direction_id_suffix[i] = element_direction_info[i].suffix;
5136 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5138 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5139 special_id_suffix[i] = special_suffix_info[i].suffix;
5140 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5142 for (i = 0; i < MAX_LEVELS; i++)
5143 level_id_suffix[i] = get_level_id_suffix(i);
5144 level_id_suffix[MAX_LEVELS] = NULL;
5146 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5147 image_id_prefix, action_id_suffix, direction_id_suffix,
5148 special_id_suffix, ignore_image_tokens);
5149 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5150 sound_id_prefix, action_id_suffix, dummy,
5151 special_id_suffix, ignore_sound_tokens);
5152 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5153 music_id_prefix, action_id_suffix, special_id_suffix,
5154 level_id_suffix, ignore_music_tokens);
5157 static void InitMixer()
5164 void InitGfxBuffers()
5166 static int win_xsize_last = -1;
5167 static int win_ysize_last = -1;
5169 /* create additional image buffers for double-buffering and cross-fading */
5171 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5173 /* used to temporarily store the backbuffer -- only re-create if changed */
5174 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5175 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5177 win_xsize_last = WIN_XSIZE;
5178 win_ysize_last = WIN_YSIZE;
5181 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5182 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5183 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5184 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5186 /* initialize screen properties */
5187 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5188 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5190 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5191 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5192 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5193 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5194 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5195 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5197 /* required if door size definitions have changed */
5198 InitGraphicCompatibilityInfo_Doors();
5200 InitGfxBuffers_EM();
5201 InitGfxBuffers_SP();
5206 struct GraphicInfo *graphic_info_last = graphic_info;
5207 char *filename_font_initial = NULL;
5208 char *filename_anim_initial = NULL;
5209 Bitmap *bitmap_font_initial = NULL;
5213 /* determine settings for initial font (for displaying startup messages) */
5214 for (i = 0; image_config[i].token != NULL; i++)
5216 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5218 char font_token[128];
5221 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5222 len_font_token = strlen(font_token);
5224 if (strEqual(image_config[i].token, font_token))
5225 filename_font_initial = image_config[i].value;
5226 else if (strlen(image_config[i].token) > len_font_token &&
5227 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5229 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5230 font_initial[j].src_x = atoi(image_config[i].value);
5231 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5232 font_initial[j].src_y = atoi(image_config[i].value);
5233 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5234 font_initial[j].width = atoi(image_config[i].value);
5235 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5236 font_initial[j].height = atoi(image_config[i].value);
5241 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5243 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5244 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5247 if (filename_font_initial == NULL) /* should not happen */
5248 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5251 InitGfxCustomArtworkInfo();
5252 InitGfxOtherSettings();
5254 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5256 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5257 font_initial[j].bitmap = bitmap_font_initial;
5259 InitFontGraphicInfo();
5261 font_height = getFontHeight(FC_RED);
5263 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5264 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5265 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5268 DrawInitText("Loading graphics", 120, FC_GREEN);
5270 /* initialize settings for busy animation with default values */
5271 int parameter[NUM_GFX_ARGS];
5272 for (i = 0; i < NUM_GFX_ARGS; i++)
5273 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5274 image_config_suffix[i].token,
5275 image_config_suffix[i].type);
5277 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5278 int len_anim_token = strlen(anim_token);
5280 /* read settings for busy animation from default custom artwork config */
5281 char *gfx_config_filename = getPath3(options.graphics_directory,
5283 GRAPHICSINFO_FILENAME);
5285 if (fileExists(gfx_config_filename))
5287 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5289 if (setup_file_hash)
5291 char *filename = getHashEntry(setup_file_hash, anim_token);
5295 filename_anim_initial = getStringCopy(filename);
5297 for (j = 0; image_config_suffix[j].token != NULL; j++)
5299 int type = image_config_suffix[j].type;
5300 char *suffix = image_config_suffix[j].token;
5301 char *token = getStringCat2(anim_token, suffix);
5302 char *value = getHashEntry(setup_file_hash, token);
5304 checked_free(token);
5307 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5311 freeSetupFileHash(setup_file_hash);
5315 if (filename_anim_initial == NULL)
5317 /* read settings for busy animation from static default artwork config */
5318 for (i = 0; image_config[i].token != NULL; i++)
5320 if (strEqual(image_config[i].token, anim_token))
5321 filename_anim_initial = getStringCopy(image_config[i].value);
5322 else if (strlen(image_config[i].token) > len_anim_token &&
5323 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5325 for (j = 0; image_config_suffix[j].token != NULL; j++)
5327 if (strEqual(&image_config[i].token[len_anim_token],
5328 image_config_suffix[j].token))
5330 get_graphic_parameter_value(image_config[i].value,
5331 image_config_suffix[j].token,
5332 image_config_suffix[j].type);
5338 if (filename_anim_initial == NULL) /* should not happen */
5339 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5341 anim_initial.bitmaps =
5342 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5344 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5345 LoadCustomImage(filename_anim_initial);
5347 checked_free(filename_anim_initial);
5349 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5351 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5353 graphic_info = graphic_info_last;
5355 init.busy.width = anim_initial.width;
5356 init.busy.height = anim_initial.height;
5358 InitMenuDesignSettings_Static();
5360 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5361 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5362 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5364 gfx.fade_border_source_status = global.border_status;
5365 gfx.fade_border_target_status = global.border_status;
5366 gfx.masked_border_bitmap_ptr = backbuffer;
5368 /* use copy of busy animation to prevent change while reloading artwork */
5372 void InitGfxBackground()
5374 fieldbuffer = bitmap_db_field;
5375 SetDrawtoField(DRAW_TO_BACKBUFFER);
5377 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5379 redraw_mask = REDRAW_ALL;
5382 static void InitLevelInfo()
5384 LoadLevelInfo(); /* global level info */
5385 LoadLevelSetup_LastSeries(); /* last played series info */
5386 LoadLevelSetup_SeriesInfo(); /* last played level info */
5388 if (global.autoplay_leveldir &&
5389 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5391 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5392 global.autoplay_leveldir);
5393 if (leveldir_current == NULL)
5394 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5398 static void InitLevelArtworkInfo()
5400 LoadLevelArtworkInfo();
5403 static void InitImages()
5405 print_timestamp_init("InitImages");
5408 printf("::: leveldir_current->identifier == '%s'\n",
5409 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5410 printf("::: leveldir_current->graphics_path == '%s'\n",
5411 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5412 printf("::: leveldir_current->graphics_set == '%s'\n",
5413 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5414 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5415 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5418 setLevelArtworkDir(artwork.gfx_first);
5421 printf("::: leveldir_current->identifier == '%s'\n",
5422 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5423 printf("::: leveldir_current->graphics_path == '%s'\n",
5424 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5425 printf("::: leveldir_current->graphics_set == '%s'\n",
5426 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5427 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5428 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5432 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5433 leveldir_current->identifier,
5434 artwork.gfx_current_identifier,
5435 artwork.gfx_current->identifier,
5436 leveldir_current->graphics_set,
5437 leveldir_current->graphics_path);
5440 UPDATE_BUSY_STATE();
5442 ReloadCustomImages();
5443 print_timestamp_time("ReloadCustomImages");
5445 UPDATE_BUSY_STATE();
5447 LoadCustomElementDescriptions();
5448 print_timestamp_time("LoadCustomElementDescriptions");
5450 UPDATE_BUSY_STATE();
5452 LoadMenuDesignSettings();
5453 print_timestamp_time("LoadMenuDesignSettings");
5455 UPDATE_BUSY_STATE();
5457 ReinitializeGraphics();
5458 print_timestamp_time("ReinitializeGraphics");
5460 UPDATE_BUSY_STATE();
5462 print_timestamp_done("InitImages");
5465 static void InitSound(char *identifier)
5467 print_timestamp_init("InitSound");
5469 if (identifier == NULL)
5470 identifier = artwork.snd_current->identifier;
5472 /* set artwork path to send it to the sound server process */
5473 setLevelArtworkDir(artwork.snd_first);
5475 InitReloadCustomSounds(identifier);
5476 print_timestamp_time("InitReloadCustomSounds");
5478 ReinitializeSounds();
5479 print_timestamp_time("ReinitializeSounds");
5481 print_timestamp_done("InitSound");
5484 static void InitMusic(char *identifier)
5486 print_timestamp_init("InitMusic");
5488 if (identifier == NULL)
5489 identifier = artwork.mus_current->identifier;
5491 /* set artwork path to send it to the sound server process */
5492 setLevelArtworkDir(artwork.mus_first);
5494 InitReloadCustomMusic(identifier);
5495 print_timestamp_time("InitReloadCustomMusic");
5497 ReinitializeMusic();
5498 print_timestamp_time("ReinitializeMusic");
5500 print_timestamp_done("InitMusic");
5503 static void InitArtworkDone()
5505 InitGlobalAnimations();
5508 void InitNetworkServer()
5510 #if defined(NETWORK_AVALIABLE)
5514 if (!options.network)
5517 #if defined(NETWORK_AVALIABLE)
5518 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5520 if (!ConnectToServer(options.server_host, options.server_port))
5521 Error(ERR_EXIT, "cannot connect to network game server");
5523 SendToServer_PlayerName(setup.player_name);
5524 SendToServer_ProtocolVersion();
5527 SendToServer_NrWanted(nr_wanted);
5531 static boolean CheckArtworkConfigForCustomElements(char *filename)
5533 SetupFileHash *setup_file_hash;
5534 boolean redefined_ce_found = FALSE;
5536 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5538 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5540 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5542 char *token = HASH_ITERATION_TOKEN(itr);
5544 if (strPrefix(token, "custom_"))
5546 redefined_ce_found = TRUE;
5551 END_HASH_ITERATION(setup_file_hash, itr)
5553 freeSetupFileHash(setup_file_hash);
5556 return redefined_ce_found;
5559 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5561 char *filename_base, *filename_local;
5562 boolean redefined_ce_found = FALSE;
5564 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5567 printf("::: leveldir_current->identifier == '%s'\n",
5568 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5569 printf("::: leveldir_current->graphics_path == '%s'\n",
5570 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5571 printf("::: leveldir_current->graphics_set == '%s'\n",
5572 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5573 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5574 leveldir_current == NULL ? "[NULL]" :
5575 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5578 /* first look for special artwork configured in level series config */
5579 filename_base = getCustomArtworkLevelConfigFilename(type);
5582 printf("::: filename_base == '%s'\n", filename_base);
5585 if (fileExists(filename_base))
5586 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5588 filename_local = getCustomArtworkConfigFilename(type);
5591 printf("::: filename_local == '%s'\n", filename_local);
5594 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5595 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5598 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5601 return redefined_ce_found;
5604 static void InitOverrideArtwork()
5606 boolean redefined_ce_found = FALSE;
5608 /* to check if this level set redefines any CEs, do not use overriding */
5609 gfx.override_level_graphics = FALSE;
5610 gfx.override_level_sounds = FALSE;
5611 gfx.override_level_music = FALSE;
5613 /* now check if this level set has definitions for custom elements */
5614 if (setup.override_level_graphics == AUTO ||
5615 setup.override_level_sounds == AUTO ||
5616 setup.override_level_music == AUTO)
5617 redefined_ce_found =
5618 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5619 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5620 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5623 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5626 if (redefined_ce_found)
5628 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5629 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5630 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5631 gfx.override_level_music = (setup.override_level_music == TRUE);
5635 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5636 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5637 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5638 gfx.override_level_music = (setup.override_level_music != FALSE);
5642 printf("::: => %d, %d, %d\n",
5643 gfx.override_level_graphics,
5644 gfx.override_level_sounds,
5645 gfx.override_level_music);
5649 static char *getNewArtworkIdentifier(int type)
5651 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5652 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5653 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5654 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5655 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5656 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5657 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5658 char *leveldir_identifier = leveldir_current->identifier;
5659 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5660 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5661 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5662 char *artwork_current_identifier;
5663 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5665 /* leveldir_current may be invalid (level group, parent link) */
5666 if (!validLevelSeries(leveldir_current))
5669 /* 1st step: determine artwork set to be activated in descending order:
5670 --------------------------------------------------------------------
5671 1. setup artwork (when configured to override everything else)
5672 2. artwork set configured in "levelinfo.conf" of current level set
5673 (artwork in level directory will have priority when loading later)
5674 3. artwork in level directory (stored in artwork sub-directory)
5675 4. setup artwork (currently configured in setup menu) */
5677 if (setup_override_artwork)
5678 artwork_current_identifier = setup_artwork_set;
5679 else if (leveldir_artwork_set != NULL)
5680 artwork_current_identifier = leveldir_artwork_set;
5681 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5682 artwork_current_identifier = leveldir_identifier;
5684 artwork_current_identifier = setup_artwork_set;
5687 /* 2nd step: check if it is really needed to reload artwork set
5688 ------------------------------------------------------------ */
5690 /* ---------- reload if level set and also artwork set has changed ------- */
5691 if (leveldir_current_identifier[type] != leveldir_identifier &&
5692 (last_has_level_artwork_set[type] || has_level_artwork_set))
5693 artwork_new_identifier = artwork_current_identifier;
5695 leveldir_current_identifier[type] = leveldir_identifier;
5696 last_has_level_artwork_set[type] = has_level_artwork_set;
5698 /* ---------- reload if "override artwork" setting has changed ----------- */
5699 if (last_override_level_artwork[type] != setup_override_artwork)
5700 artwork_new_identifier = artwork_current_identifier;
5702 last_override_level_artwork[type] = setup_override_artwork;
5704 /* ---------- reload if current artwork identifier has changed ----------- */
5705 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5706 artwork_current_identifier))
5707 artwork_new_identifier = artwork_current_identifier;
5709 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5711 /* ---------- do not reload directly after starting ---------------------- */
5712 if (!initialized[type])
5713 artwork_new_identifier = NULL;
5715 initialized[type] = TRUE;
5717 return artwork_new_identifier;
5720 void ReloadCustomArtwork(int force_reload)
5722 int last_game_status = game_status; /* save current game status */
5723 char *gfx_new_identifier;
5724 char *snd_new_identifier;
5725 char *mus_new_identifier;
5726 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5727 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5728 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5729 boolean reload_needed;
5731 InitOverrideArtwork();
5733 force_reload_gfx |= AdjustGraphicsForEMC();
5735 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5736 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5737 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5739 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5740 snd_new_identifier != NULL || force_reload_snd ||
5741 mus_new_identifier != NULL || force_reload_mus);
5746 print_timestamp_init("ReloadCustomArtwork");
5748 SetGameStatus(GAME_MODE_LOADING);
5750 FadeOut(REDRAW_ALL);
5752 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5753 print_timestamp_time("ClearRectangle");
5757 if (gfx_new_identifier != NULL || force_reload_gfx)
5760 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5761 artwork.gfx_current_identifier,
5763 artwork.gfx_current->identifier,
5764 leveldir_current->graphics_set);
5768 print_timestamp_time("InitImages");
5771 if (snd_new_identifier != NULL || force_reload_snd)
5773 InitSound(snd_new_identifier);
5774 print_timestamp_time("InitSound");
5777 if (mus_new_identifier != NULL || force_reload_mus)
5779 InitMusic(mus_new_identifier);
5780 print_timestamp_time("InitMusic");
5785 SetGameStatus(last_game_status); /* restore current game status */
5787 init_last = init; /* switch to new busy animation */
5789 FadeOut(REDRAW_ALL);
5791 RedrawGlobalBorder();
5793 /* force redraw of (open or closed) door graphics */
5794 SetDoorState(DOOR_OPEN_ALL);
5795 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5797 FadeSetEnterScreen();
5798 FadeSkipNextFadeOut();
5800 print_timestamp_done("ReloadCustomArtwork");
5802 LimitScreenUpdates(FALSE);
5805 void KeyboardAutoRepeatOffUnlessAutoplay()
5807 if (global.autoplay_leveldir == NULL)
5808 KeyboardAutoRepeatOff();
5811 void DisplayExitMessage(char *format, va_list ap)
5813 // check if draw buffer and fonts for exit message are already available
5814 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5817 int font_1 = FC_RED;
5818 int font_2 = FC_YELLOW;
5819 int font_3 = FC_BLUE;
5820 int font_width = getFontWidth(font_2);
5821 int font_height = getFontHeight(font_2);
5824 int sxsize = WIN_XSIZE - 2 * sx;
5825 int sysize = WIN_YSIZE - 2 * sy;
5826 int line_length = sxsize / font_width;
5827 int max_lines = sysize / font_height;
5828 int num_lines_printed;
5832 gfx.sxsize = sxsize;
5833 gfx.sysize = sysize;
5837 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5839 DrawTextSCentered(sy, font_1, "Fatal error:");
5840 sy += 3 * font_height;;
5843 DrawTextBufferVA(sx, sy, format, ap, font_2,
5844 line_length, line_length, max_lines,
5845 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5846 sy += (num_lines_printed + 3) * font_height;
5848 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5849 sy += 3 * font_height;
5852 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5853 line_length, line_length, max_lines,
5854 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5856 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5858 redraw_mask = REDRAW_ALL;
5860 /* force drawing exit message even if screen updates are currently limited */
5861 LimitScreenUpdates(FALSE);
5865 /* deactivate toons on error message screen */
5866 setup.toons = FALSE;
5868 WaitForEventToContinue();
5872 /* ========================================================================= */
5874 /* ========================================================================= */
5878 print_timestamp_init("OpenAll");
5880 SetGameStatus(GAME_MODE_LOADING);
5884 InitGlobal(); /* initialize some global variables */
5886 print_timestamp_time("[init global stuff]");
5890 print_timestamp_time("[init setup/config stuff (1)]");
5892 if (options.execute_command)
5893 Execute_Command(options.execute_command);
5895 if (options.serveronly)
5897 #if defined(PLATFORM_UNIX)
5898 NetworkServer(options.server_port, options.serveronly);
5900 Error(ERR_WARN, "networking only supported in Unix version");
5903 exit(0); /* never reached, server loops forever */
5907 print_timestamp_time("[init setup/config stuff (2)]");
5909 print_timestamp_time("[init setup/config stuff (3)]");
5910 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5911 print_timestamp_time("[init setup/config stuff (4)]");
5912 InitArtworkConfig(); /* needed before forking sound child process */
5913 print_timestamp_time("[init setup/config stuff (5)]");
5915 print_timestamp_time("[init setup/config stuff (6)]");
5917 InitRND(NEW_RANDOMIZE);
5918 InitSimpleRandom(NEW_RANDOMIZE);
5922 print_timestamp_time("[init setup/config stuff]");
5925 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5927 InitEventFilter(FilterEvents);
5929 print_timestamp_time("[init video stuff]");
5931 InitElementPropertiesStatic();
5932 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5933 InitElementPropertiesGfxElement();
5935 print_timestamp_time("[init element properties stuff]");
5939 print_timestamp_time("InitGfx");
5942 print_timestamp_time("InitLevelInfo");
5944 InitLevelArtworkInfo();
5945 print_timestamp_time("InitLevelArtworkInfo");
5947 InitOverrideArtwork(); /* needs to know current level directory */
5948 print_timestamp_time("InitOverrideArtwork");
5950 InitImages(); /* needs to know current level directory */
5951 print_timestamp_time("InitImages");
5953 InitSound(NULL); /* needs to know current level directory */
5954 print_timestamp_time("InitSound");
5956 InitMusic(NULL); /* needs to know current level directory */
5957 print_timestamp_time("InitMusic");
5961 InitGfxBackground();
5966 if (global.autoplay_leveldir)
5971 else if (global.convert_leveldir)
5976 else if (global.create_images_dir)
5978 CreateLevelSketchImages();
5982 SetGameStatus(GAME_MODE_MAIN);
5984 FadeSetEnterScreen();
5985 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5986 FadeSkipNextFadeOut();
5988 print_timestamp_time("[post-artwork]");
5990 print_timestamp_done("OpenAll");
5994 InitNetworkServer();
5997 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5999 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6000 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6001 #if defined(PLATFORM_ANDROID)
6002 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6003 SDL_AndroidGetInternalStoragePath());
6004 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6005 SDL_AndroidGetExternalStoragePath());
6006 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6007 (SDL_AndroidGetExternalStorageState() ==
6008 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
6009 SDL_AndroidGetExternalStorageState() ==
6010 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
6015 void CloseAllAndExit(int exit_value)
6020 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6027 #if defined(TARGET_SDL)
6028 #if defined(TARGET_SDL2)
6030 // set a flag to tell the network server thread to quit and wait for it
6031 // using SDL_WaitThread()
6033 if (network_server) /* terminate network server */
6034 SDL_KillThread(server_thread);
6038 CloseVideoDisplay();
6039 ClosePlatformDependentStuff();
6041 if (exit_value != 0)
6043 /* fall back to default level set (current set may have caused an error) */
6044 SaveLevelSetup_LastSeries_Deactivate();
6046 /* tell user where to find error log file which may contain more details */
6047 // (error notification now directly displayed on screen inside R'n'D
6048 // NotifyUserAboutErrorFile(); /* currently only works for Windows */