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)));
941 /* swap frontside and backside graphic tile coordinates, if needed */
942 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
944 /* get current (wrong) backside tile coordinates */
945 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
947 /* set frontside tile coordinates to backside tile coordinates */
948 g->src_x = src_x_back;
949 g->src_y = src_y_back;
951 /* invert tile offset to point to new backside tile coordinates */
955 /* do not swap front and backside tiles again after correction */
956 g->swap_double_tiles = 0;
965 /* now set all '-1' values to element specific default values */
966 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
968 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
969 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
970 int default_direction_graphic[NUM_DIRECTIONS_FULL];
971 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
973 if (default_graphic == -1)
974 default_graphic = IMG_UNKNOWN;
976 if (default_crumbled == -1)
977 default_crumbled = default_graphic;
979 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
981 default_direction_graphic[dir] =
982 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
983 default_direction_crumbled[dir] =
984 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
986 if (default_direction_graphic[dir] == -1)
987 default_direction_graphic[dir] = default_graphic;
989 if (default_direction_crumbled[dir] == -1)
990 default_direction_crumbled[dir] = default_direction_graphic[dir];
993 for (act = 0; act < NUM_ACTIONS; act++)
995 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
996 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
997 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
998 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
999 act == ACTION_TURNING_FROM_RIGHT ||
1000 act == ACTION_TURNING_FROM_UP ||
1001 act == ACTION_TURNING_FROM_DOWN);
1003 /* generic default action graphic (defined by "[default]" directive) */
1004 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1005 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1006 int default_remove_graphic = IMG_EMPTY;
1008 if (act_remove && default_action_graphic != -1)
1009 default_remove_graphic = default_action_graphic;
1011 /* look for special default action graphic (classic game specific) */
1012 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1013 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1014 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1015 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1016 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1017 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1019 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1020 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1021 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1022 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1023 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1024 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1026 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1027 /* !!! make this better !!! */
1028 if (i == EL_EMPTY_SPACE)
1030 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1031 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1034 if (default_action_graphic == -1)
1035 default_action_graphic = default_graphic;
1037 if (default_action_crumbled == -1)
1038 default_action_crumbled = default_action_graphic;
1040 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1042 /* use action graphic as the default direction graphic, if undefined */
1043 int default_action_direction_graphic = element_info[i].graphic[act];
1044 int default_action_direction_crumbled = element_info[i].crumbled[act];
1046 /* no graphic for current action -- use default direction graphic */
1047 if (default_action_direction_graphic == -1)
1048 default_action_direction_graphic =
1049 (act_remove ? default_remove_graphic :
1051 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1052 default_action_graphic != default_graphic ?
1053 default_action_graphic :
1054 default_direction_graphic[dir]);
1056 if (element_info[i].direction_graphic[act][dir] == -1)
1057 element_info[i].direction_graphic[act][dir] =
1058 default_action_direction_graphic;
1060 if (default_action_direction_crumbled == -1)
1061 default_action_direction_crumbled =
1062 element_info[i].direction_graphic[act][dir];
1064 if (element_info[i].direction_crumbled[act][dir] == -1)
1065 element_info[i].direction_crumbled[act][dir] =
1066 default_action_direction_crumbled;
1069 /* no graphic for this specific action -- use default action graphic */
1070 if (element_info[i].graphic[act] == -1)
1071 element_info[i].graphic[act] =
1072 (act_remove ? default_remove_graphic :
1073 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1074 default_action_graphic);
1076 if (element_info[i].crumbled[act] == -1)
1077 element_info[i].crumbled[act] = element_info[i].graphic[act];
1081 UPDATE_BUSY_STATE();
1084 void InitElementSpecialGraphicInfo()
1086 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1087 int num_property_mappings = getImageListPropertyMappingSize();
1090 /* always start with reliable default values */
1091 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1092 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1093 element_info[i].special_graphic[j] =
1094 element_info[i].graphic[ACTION_DEFAULT];
1096 /* initialize special element/graphic mapping from static configuration */
1097 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1099 int element = element_to_special_graphic[i].element;
1100 int special = element_to_special_graphic[i].special;
1101 int graphic = element_to_special_graphic[i].graphic;
1102 int base_graphic = el2baseimg(element);
1103 boolean base_redefined =
1104 getImageListEntryFromImageID(base_graphic)->redefined;
1105 boolean special_redefined =
1106 getImageListEntryFromImageID(graphic)->redefined;
1108 /* if the base graphic ("emerald", for example) has been redefined,
1109 but not the special graphic ("emerald.EDITOR", for example), do not
1110 use an existing (in this case considered obsolete) special graphic
1111 anymore, but use the automatically created (down-scaled) graphic */
1112 if (base_redefined && !special_redefined)
1115 element_info[element].special_graphic[special] = graphic;
1118 /* initialize special element/graphic mapping from dynamic configuration */
1119 for (i = 0; i < num_property_mappings; i++)
1121 int element = property_mapping[i].base_index;
1122 int action = property_mapping[i].ext1_index;
1123 int direction = property_mapping[i].ext2_index;
1124 int special = property_mapping[i].ext3_index;
1125 int graphic = property_mapping[i].artwork_index;
1127 /* for action ".active", replace element with active element, if exists */
1128 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1130 element = ELEMENT_ACTIVE(element);
1134 if (element >= MAX_NUM_ELEMENTS)
1137 /* do not change special graphic if action or direction was specified */
1138 if (action != -1 || direction != -1)
1141 if (IS_SPECIAL_GFX_ARG(special))
1142 element_info[element].special_graphic[special] = graphic;
1145 /* now set all undefined/invalid graphics to default */
1146 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1147 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1148 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1149 element_info[i].special_graphic[j] =
1150 element_info[i].graphic[ACTION_DEFAULT];
1153 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1155 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1156 return get_parameter_value(value_raw, suffix, type);
1158 if (strEqual(value_raw, ARG_UNDEFINED))
1159 return ARG_UNDEFINED_VALUE;
1161 if (type == TYPE_ELEMENT)
1163 char *value = getHashEntry(element_token_hash, value_raw);
1167 Error(ERR_INFO_LINE, "-");
1168 Error(ERR_INFO, "warning: error found in config file:");
1169 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1170 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1171 Error(ERR_INFO, "custom graphic rejected for this element/action");
1172 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1173 Error(ERR_INFO_LINE, "-");
1176 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1178 else if (type == TYPE_GRAPHIC)
1180 char *value = getHashEntry(graphic_token_hash, value_raw);
1181 int fallback_graphic = IMG_CHAR_EXCLAM;
1185 Error(ERR_INFO_LINE, "-");
1186 Error(ERR_INFO, "warning: error found in config file:");
1187 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1188 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1189 Error(ERR_INFO, "custom graphic rejected for this element/action");
1190 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1191 Error(ERR_INFO_LINE, "-");
1194 return (value != NULL ? atoi(value) : fallback_graphic);
1200 static int get_scaled_graphic_width(int graphic)
1202 int original_width = getOriginalImageWidthFromImageID(graphic);
1203 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1205 return original_width * scale_up_factor;
1208 static int get_scaled_graphic_height(int graphic)
1210 int original_height = getOriginalImageHeightFromImageID(graphic);
1211 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1213 return original_height * scale_up_factor;
1216 static void set_graphic_parameters_ext(int graphic, int *parameter,
1217 Bitmap **src_bitmaps)
1219 struct GraphicInfo *g = &graphic_info[graphic];
1220 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1221 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1222 int anim_frames_per_line = 1;
1224 /* always start with reliable default values */
1225 g->src_image_width = 0;
1226 g->src_image_height = 0;
1229 g->width = TILEX; /* default for element graphics */
1230 g->height = TILEY; /* default for element graphics */
1231 g->offset_x = 0; /* one or both of these values ... */
1232 g->offset_y = 0; /* ... will be corrected later */
1233 g->offset2_x = 0; /* one or both of these values ... */
1234 g->offset2_y = 0; /* ... will be corrected later */
1235 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1236 g->crumbled_like = -1; /* do not use clone element */
1237 g->diggable_like = -1; /* do not use clone element */
1238 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1239 g->scale_up_factor = 1; /* default: no scaling up */
1240 g->tile_size = TILESIZE; /* default: standard tile size */
1241 g->clone_from = -1; /* do not use clone graphic */
1242 g->init_delay_fixed = 0;
1243 g->init_delay_random = 0;
1244 g->anim_delay_fixed = 0;
1245 g->anim_delay_random = 0;
1246 g->post_delay_fixed = 0;
1247 g->post_delay_random = 0;
1249 g->fade_mode = FADE_MODE_DEFAULT;
1253 g->align = ALIGN_CENTER; /* default for title screens */
1254 g->valign = VALIGN_MIDDLE; /* default for title screens */
1255 g->sort_priority = 0; /* default for title screens */
1257 g->style = STYLE_DEFAULT;
1259 g->bitmaps = src_bitmaps;
1260 g->bitmap = src_bitmap;
1262 /* optional zoom factor for scaling up the image to a larger size */
1263 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1264 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1265 if (g->scale_up_factor < 1)
1266 g->scale_up_factor = 1; /* no scaling */
1268 /* optional tile size for using non-standard image size */
1269 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1271 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1274 // CHECK: should tile sizes less than standard tile size be allowed?
1275 if (g->tile_size < TILESIZE)
1276 g->tile_size = TILESIZE; /* standard tile size */
1279 // when setting tile size, also set width and height accordingly
1280 g->width = g->tile_size;
1281 g->height = g->tile_size;
1284 if (g->use_image_size)
1286 /* set new default bitmap size (with scaling, but without small images) */
1287 g->width = get_scaled_graphic_width(graphic);
1288 g->height = get_scaled_graphic_height(graphic);
1291 /* optional width and height of each animation frame */
1292 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1293 g->width = parameter[GFX_ARG_WIDTH];
1294 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1295 g->height = parameter[GFX_ARG_HEIGHT];
1297 /* optional x and y tile position of animation frame sequence */
1298 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1299 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1300 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1301 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1303 /* optional x and y pixel position of animation frame sequence */
1304 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1305 g->src_x = parameter[GFX_ARG_X];
1306 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1307 g->src_y = parameter[GFX_ARG_Y];
1313 Error(ERR_INFO_LINE, "-");
1314 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1315 g->width, getTokenFromImageID(graphic), TILEX);
1316 Error(ERR_INFO_LINE, "-");
1318 g->width = TILEX; /* will be checked to be inside bitmap later */
1323 Error(ERR_INFO_LINE, "-");
1324 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1325 g->height, getTokenFromImageID(graphic), TILEY);
1326 Error(ERR_INFO_LINE, "-");
1328 g->height = TILEY; /* will be checked to be inside bitmap later */
1334 /* get final bitmap size (with scaling, but without small images) */
1335 int src_image_width = get_scaled_graphic_width(graphic);
1336 int src_image_height = get_scaled_graphic_height(graphic);
1338 if (src_image_width == 0 || src_image_height == 0)
1340 /* only happens when loaded outside artwork system (like "global.busy") */
1341 src_image_width = src_bitmap->width;
1342 src_image_height = src_bitmap->height;
1345 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1347 anim_frames_per_row = src_image_width / g->tile_size;
1348 anim_frames_per_col = src_image_height / g->tile_size;
1352 anim_frames_per_row = src_image_width / g->width;
1353 anim_frames_per_col = src_image_height / g->height;
1356 g->src_image_width = src_image_width;
1357 g->src_image_height = src_image_height;
1360 /* correct x or y offset dependent of vertical or horizontal frame order */
1361 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1363 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1364 parameter[GFX_ARG_OFFSET] : g->height);
1365 anim_frames_per_line = anim_frames_per_col;
1367 else /* frames are ordered horizontally */
1369 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1370 parameter[GFX_ARG_OFFSET] : g->width);
1371 anim_frames_per_line = anim_frames_per_row;
1374 /* optionally, the x and y offset of frames can be specified directly */
1375 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1376 g->offset_x = parameter[GFX_ARG_XOFFSET];
1377 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1378 g->offset_y = parameter[GFX_ARG_YOFFSET];
1380 /* optionally, moving animations may have separate start and end graphics */
1381 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1383 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1384 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1386 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1387 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1388 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1389 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1390 else /* frames are ordered horizontally */
1391 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1392 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1394 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1395 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1396 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1397 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1398 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1400 /* optionally, the second movement tile can be specified as start tile */
1401 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1402 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1404 /* automatically determine correct number of frames, if not defined */
1405 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1406 g->anim_frames = parameter[GFX_ARG_FRAMES];
1407 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1408 g->anim_frames = anim_frames_per_row;
1409 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1410 g->anim_frames = anim_frames_per_col;
1414 if (g->anim_frames == 0) /* frames must be at least 1 */
1417 g->anim_frames_per_line =
1418 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1419 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1421 g->anim_delay = parameter[GFX_ARG_DELAY];
1422 if (g->anim_delay == 0) /* delay must be at least 1 */
1425 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1427 /* automatically determine correct start frame, if not defined */
1428 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1429 g->anim_start_frame = 0;
1430 else if (g->anim_mode & ANIM_REVERSE)
1431 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1433 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1435 /* animation synchronized with global frame counter, not move position */
1436 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1438 /* optional element for cloning crumble graphics */
1439 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1440 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1442 /* optional element for cloning digging graphics */
1443 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1444 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1446 /* optional border size for "crumbling" diggable graphics */
1447 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1448 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1450 /* used for global animations and player "boring" and "sleeping" actions */
1451 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1452 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1453 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1454 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1455 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1456 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1457 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1458 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1459 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1460 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1461 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1462 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1464 /* used for toon animations and global animations */
1465 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1466 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1467 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1468 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1469 g->direction = parameter[GFX_ARG_DIRECTION];
1470 g->position = parameter[GFX_ARG_POSITION];
1471 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1472 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1474 /* this is only used for drawing font characters */
1475 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1476 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1478 /* this is only used for drawing envelope graphics */
1479 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1481 /* used for toon animations and global animations */
1482 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1483 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1485 /* optional graphic for cloning all graphics settings */
1486 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1487 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1489 /* optional settings for drawing title screens and title messages */
1490 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1491 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1492 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1493 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1494 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1495 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1496 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1497 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1498 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1499 g->align = parameter[GFX_ARG_ALIGN];
1500 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1501 g->valign = parameter[GFX_ARG_VALIGN];
1502 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1503 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1505 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1506 g->class = parameter[GFX_ARG_CLASS];
1507 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1508 g->style = parameter[GFX_ARG_STYLE];
1510 /* this is only used for drawing menu buttons and text */
1511 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1512 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1513 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1514 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1517 static void set_graphic_parameters(int graphic)
1519 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1520 char **parameter_raw = image->parameter;
1521 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1522 int parameter[NUM_GFX_ARGS];
1525 /* if fallback to default artwork is done, also use the default parameters */
1526 if (image->fallback_to_default)
1527 parameter_raw = image->default_parameter;
1529 /* get integer values from string parameters */
1530 for (i = 0; i < NUM_GFX_ARGS; i++)
1531 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1532 image_config_suffix[i].token,
1533 image_config_suffix[i].type);
1535 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1537 UPDATE_BUSY_STATE();
1540 static void set_cloned_graphic_parameters(int graphic)
1542 int fallback_graphic = IMG_CHAR_EXCLAM;
1543 int max_num_images = getImageListSize();
1544 int clone_graphic = graphic_info[graphic].clone_from;
1545 int num_references_followed = 1;
1547 while (graphic_info[clone_graphic].clone_from != -1 &&
1548 num_references_followed < max_num_images)
1550 clone_graphic = graphic_info[clone_graphic].clone_from;
1552 num_references_followed++;
1555 if (num_references_followed >= max_num_images)
1557 Error(ERR_INFO_LINE, "-");
1558 Error(ERR_INFO, "warning: error found in config file:");
1559 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1560 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1561 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1562 Error(ERR_INFO, "custom graphic rejected for this element/action");
1564 if (graphic == fallback_graphic)
1565 Error(ERR_EXIT, "no fallback graphic available");
1567 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1568 Error(ERR_INFO_LINE, "-");
1570 graphic_info[graphic] = graphic_info[fallback_graphic];
1574 graphic_info[graphic] = graphic_info[clone_graphic];
1575 graphic_info[graphic].clone_from = clone_graphic;
1579 static void InitGraphicInfo()
1581 int fallback_graphic = IMG_CHAR_EXCLAM;
1582 int num_images = getImageListSize();
1585 /* use image size as default values for width and height for these images */
1586 static int full_size_graphics[] =
1589 IMG_GLOBAL_BORDER_MAIN,
1590 IMG_GLOBAL_BORDER_SCORES,
1591 IMG_GLOBAL_BORDER_EDITOR,
1592 IMG_GLOBAL_BORDER_PLAYING,
1595 IMG_BACKGROUND_ENVELOPE_1,
1596 IMG_BACKGROUND_ENVELOPE_2,
1597 IMG_BACKGROUND_ENVELOPE_3,
1598 IMG_BACKGROUND_ENVELOPE_4,
1599 IMG_BACKGROUND_REQUEST,
1602 IMG_BACKGROUND_TITLE_INITIAL,
1603 IMG_BACKGROUND_TITLE,
1604 IMG_BACKGROUND_MAIN,
1605 IMG_BACKGROUND_LEVELS,
1606 IMG_BACKGROUND_LEVELNR,
1607 IMG_BACKGROUND_SCORES,
1608 IMG_BACKGROUND_EDITOR,
1609 IMG_BACKGROUND_INFO,
1610 IMG_BACKGROUND_INFO_ELEMENTS,
1611 IMG_BACKGROUND_INFO_MUSIC,
1612 IMG_BACKGROUND_INFO_CREDITS,
1613 IMG_BACKGROUND_INFO_PROGRAM,
1614 IMG_BACKGROUND_INFO_VERSION,
1615 IMG_BACKGROUND_INFO_LEVELSET,
1616 IMG_BACKGROUND_SETUP,
1617 IMG_BACKGROUND_PLAYING,
1618 IMG_BACKGROUND_DOOR,
1619 IMG_BACKGROUND_TAPE,
1620 IMG_BACKGROUND_PANEL,
1621 IMG_BACKGROUND_PALETTE,
1622 IMG_BACKGROUND_TOOLBOX,
1624 IMG_TITLESCREEN_INITIAL_1,
1625 IMG_TITLESCREEN_INITIAL_2,
1626 IMG_TITLESCREEN_INITIAL_3,
1627 IMG_TITLESCREEN_INITIAL_4,
1628 IMG_TITLESCREEN_INITIAL_5,
1635 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1636 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1637 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1638 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1639 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1640 IMG_BACKGROUND_TITLEMESSAGE_1,
1641 IMG_BACKGROUND_TITLEMESSAGE_2,
1642 IMG_BACKGROUND_TITLEMESSAGE_3,
1643 IMG_BACKGROUND_TITLEMESSAGE_4,
1644 IMG_BACKGROUND_TITLEMESSAGE_5,
1649 checked_free(graphic_info);
1651 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1653 /* initialize "use_image_size" flag with default value */
1654 for (i = 0; i < num_images; i++)
1655 graphic_info[i].use_image_size = FALSE;
1657 /* initialize "use_image_size" flag from static configuration above */
1658 for (i = 0; full_size_graphics[i] != -1; i++)
1659 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1661 /* first set all graphic paramaters ... */
1662 for (i = 0; i < num_images; i++)
1663 set_graphic_parameters(i);
1665 /* ... then copy these parameters for cloned graphics */
1666 for (i = 0; i < num_images; i++)
1667 if (graphic_info[i].clone_from != -1)
1668 set_cloned_graphic_parameters(i);
1670 for (i = 0; i < num_images; i++)
1675 int first_frame, last_frame;
1676 int src_bitmap_width, src_bitmap_height;
1678 /* now check if no animation frames are outside of the loaded image */
1680 if (graphic_info[i].bitmap == NULL)
1681 continue; /* skip check for optional images that are undefined */
1683 /* get image size (this can differ from the standard element tile size!) */
1684 width = graphic_info[i].width;
1685 height = graphic_info[i].height;
1687 /* get final bitmap size (with scaling, but without small images) */
1688 src_bitmap_width = graphic_info[i].src_image_width;
1689 src_bitmap_height = graphic_info[i].src_image_height;
1691 /* check if first animation frame is inside specified bitmap */
1694 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1696 /* this avoids calculating wrong start position for out-of-bounds frame */
1697 src_x = graphic_info[i].src_x;
1698 src_y = graphic_info[i].src_y;
1700 if (src_x < 0 || src_y < 0 ||
1701 src_x + width > src_bitmap_width ||
1702 src_y + height > src_bitmap_height)
1704 Error(ERR_INFO_LINE, "-");
1705 Error(ERR_INFO, "warning: error found in config file:");
1706 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1707 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1708 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1710 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1711 src_x, src_y, src_bitmap_width, src_bitmap_height);
1712 Error(ERR_INFO, "custom graphic rejected for this element/action");
1714 if (i == fallback_graphic)
1715 Error(ERR_EXIT, "no fallback graphic available");
1717 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1718 Error(ERR_INFO_LINE, "-");
1720 graphic_info[i] = graphic_info[fallback_graphic];
1723 /* check if last animation frame is inside specified bitmap */
1725 last_frame = graphic_info[i].anim_frames - 1;
1726 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1728 if (src_x < 0 || src_y < 0 ||
1729 src_x + width > src_bitmap_width ||
1730 src_y + height > src_bitmap_height)
1732 Error(ERR_INFO_LINE, "-");
1733 Error(ERR_INFO, "warning: error found in config file:");
1734 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1735 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1736 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1738 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1739 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1740 Error(ERR_INFO, "::: %d, %d", width, height);
1741 Error(ERR_INFO, "custom graphic rejected for this element/action");
1743 if (i == fallback_graphic)
1744 Error(ERR_EXIT, "no fallback graphic available");
1746 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1747 Error(ERR_INFO_LINE, "-");
1749 graphic_info[i] = graphic_info[fallback_graphic];
1754 static void InitGraphicCompatibilityInfo()
1756 struct FileInfo *fi_global_door =
1757 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1758 int num_images = getImageListSize();
1761 /* the following compatibility handling is needed for the following case:
1762 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1763 graphics mainly used for door and panel graphics, like editor, tape and
1764 in-game buttons with hard-coded bitmap positions and button sizes; as
1765 these graphics now have individual definitions, redefining "global.door"
1766 to change all these graphics at once like before does not work anymore
1767 (because all those individual definitions still have their default values);
1768 to solve this, remap all those individual definitions that are not
1769 redefined to the new bitmap of "global.door" if it was redefined */
1771 /* special compatibility handling if image "global.door" was redefined */
1772 if (fi_global_door->redefined)
1774 for (i = 0; i < num_images; i++)
1776 struct FileInfo *fi = getImageListEntryFromImageID(i);
1778 /* process only those images that still use the default settings */
1781 /* process all images which default to same image as "global.door" */
1782 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1784 // printf("::: special treatment needed for token '%s'\n", fi->token);
1786 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1787 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1793 InitGraphicCompatibilityInfo_Doors();
1796 static void InitElementSoundInfo()
1798 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1799 int num_property_mappings = getSoundListPropertyMappingSize();
1802 /* set values to -1 to identify later as "uninitialized" values */
1803 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1804 for (act = 0; act < NUM_ACTIONS; act++)
1805 element_info[i].sound[act] = -1;
1807 /* initialize element/sound mapping from static configuration */
1808 for (i = 0; element_to_sound[i].element > -1; i++)
1810 int element = element_to_sound[i].element;
1811 int action = element_to_sound[i].action;
1812 int sound = element_to_sound[i].sound;
1813 boolean is_class = element_to_sound[i].is_class;
1816 action = ACTION_DEFAULT;
1819 element_info[element].sound[action] = sound;
1821 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1822 if (strEqual(element_info[j].class_name,
1823 element_info[element].class_name))
1824 element_info[j].sound[action] = sound;
1827 /* initialize element class/sound mapping from dynamic configuration */
1828 for (i = 0; i < num_property_mappings; i++)
1830 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1831 int action = property_mapping[i].ext1_index;
1832 int sound = property_mapping[i].artwork_index;
1834 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1838 action = ACTION_DEFAULT;
1840 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1841 if (strEqual(element_info[j].class_name,
1842 element_info[element_class].class_name))
1843 element_info[j].sound[action] = sound;
1846 /* initialize element/sound mapping from dynamic configuration */
1847 for (i = 0; i < num_property_mappings; i++)
1849 int element = property_mapping[i].base_index;
1850 int action = property_mapping[i].ext1_index;
1851 int sound = property_mapping[i].artwork_index;
1853 if (element >= MAX_NUM_ELEMENTS)
1857 action = ACTION_DEFAULT;
1859 element_info[element].sound[action] = sound;
1862 /* now set all '-1' values to element specific default values */
1863 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1865 for (act = 0; act < NUM_ACTIONS; act++)
1867 /* generic default action sound (defined by "[default]" directive) */
1868 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1870 /* look for special default action sound (classic game specific) */
1871 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1872 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1873 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1874 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1875 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1876 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1878 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1879 /* !!! make this better !!! */
1880 if (i == EL_EMPTY_SPACE)
1881 default_action_sound = element_info[EL_DEFAULT].sound[act];
1883 /* no sound for this specific action -- use default action sound */
1884 if (element_info[i].sound[act] == -1)
1885 element_info[i].sound[act] = default_action_sound;
1889 /* copy sound settings to some elements that are only stored in level file
1890 in native R'n'D levels, but are used by game engine in native EM levels */
1891 for (i = 0; copy_properties[i][0] != -1; i++)
1892 for (j = 1; j <= 4; j++)
1893 for (act = 0; act < NUM_ACTIONS; act++)
1894 element_info[copy_properties[i][j]].sound[act] =
1895 element_info[copy_properties[i][0]].sound[act];
1898 static void InitGameModeSoundInfo()
1902 /* set values to -1 to identify later as "uninitialized" values */
1903 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1906 /* initialize gamemode/sound mapping from static configuration */
1907 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1909 int gamemode = gamemode_to_sound[i].gamemode;
1910 int sound = gamemode_to_sound[i].sound;
1913 gamemode = GAME_MODE_DEFAULT;
1915 menu.sound[gamemode] = sound;
1918 /* now set all '-1' values to levelset specific default values */
1919 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1920 if (menu.sound[i] == -1)
1921 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1924 static void set_sound_parameters(int sound, char **parameter_raw)
1926 int parameter[NUM_SND_ARGS];
1929 /* get integer values from string parameters */
1930 for (i = 0; i < NUM_SND_ARGS; i++)
1932 get_parameter_value(parameter_raw[i],
1933 sound_config_suffix[i].token,
1934 sound_config_suffix[i].type);
1936 /* explicit loop mode setting in configuration overrides default value */
1937 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1938 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1940 /* sound volume to change the original volume when loading the sound file */
1941 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1943 /* sound priority to give certain sounds a higher or lower priority */
1944 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1947 static void InitSoundInfo()
1949 int *sound_effect_properties;
1950 int num_sounds = getSoundListSize();
1953 checked_free(sound_info);
1955 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1956 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1958 /* initialize sound effect for all elements to "no sound" */
1959 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1960 for (j = 0; j < NUM_ACTIONS; j++)
1961 element_info[i].sound[j] = SND_UNDEFINED;
1963 for (i = 0; i < num_sounds; i++)
1965 struct FileInfo *sound = getSoundListEntry(i);
1966 int len_effect_text = strlen(sound->token);
1968 sound_effect_properties[i] = ACTION_OTHER;
1969 sound_info[i].loop = FALSE; /* default: play sound only once */
1971 /* determine all loop sounds and identify certain sound classes */
1973 for (j = 0; element_action_info[j].suffix; j++)
1975 int len_action_text = strlen(element_action_info[j].suffix);
1977 if (len_action_text < len_effect_text &&
1978 strEqual(&sound->token[len_effect_text - len_action_text],
1979 element_action_info[j].suffix))
1981 sound_effect_properties[i] = element_action_info[j].value;
1982 sound_info[i].loop = element_action_info[j].is_loop_sound;
1988 /* associate elements and some selected sound actions */
1990 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1992 if (element_info[j].class_name)
1994 int len_class_text = strlen(element_info[j].class_name);
1996 if (len_class_text + 1 < len_effect_text &&
1997 strncmp(sound->token,
1998 element_info[j].class_name, len_class_text) == 0 &&
1999 sound->token[len_class_text] == '.')
2001 int sound_action_value = sound_effect_properties[i];
2003 element_info[j].sound[sound_action_value] = i;
2008 set_sound_parameters(i, sound->parameter);
2011 free(sound_effect_properties);
2014 static void InitGameModeMusicInfo()
2016 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2017 int num_property_mappings = getMusicListPropertyMappingSize();
2018 int default_levelset_music = -1;
2021 /* set values to -1 to identify later as "uninitialized" values */
2022 for (i = 0; i < MAX_LEVELS; i++)
2023 levelset.music[i] = -1;
2024 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2027 /* initialize gamemode/music mapping from static configuration */
2028 for (i = 0; gamemode_to_music[i].music > -1; i++)
2030 int gamemode = gamemode_to_music[i].gamemode;
2031 int music = gamemode_to_music[i].music;
2034 gamemode = GAME_MODE_DEFAULT;
2036 menu.music[gamemode] = music;
2039 /* initialize gamemode/music mapping from dynamic configuration */
2040 for (i = 0; i < num_property_mappings; i++)
2042 int prefix = property_mapping[i].base_index;
2043 int gamemode = property_mapping[i].ext2_index;
2044 int level = property_mapping[i].ext3_index;
2045 int music = property_mapping[i].artwork_index;
2047 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2051 gamemode = GAME_MODE_DEFAULT;
2053 /* level specific music only allowed for in-game music */
2054 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2055 gamemode = GAME_MODE_PLAYING;
2060 default_levelset_music = music;
2063 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2064 levelset.music[level] = music;
2065 if (gamemode != GAME_MODE_PLAYING)
2066 menu.music[gamemode] = music;
2069 /* now set all '-1' values to menu specific default values */
2070 /* (undefined values of "levelset.music[]" might stay at "-1" to
2071 allow dynamic selection of music files from music directory!) */
2072 for (i = 0; i < MAX_LEVELS; i++)
2073 if (levelset.music[i] == -1)
2074 levelset.music[i] = default_levelset_music;
2075 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2076 if (menu.music[i] == -1)
2077 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2080 static void set_music_parameters(int music, char **parameter_raw)
2082 int parameter[NUM_MUS_ARGS];
2085 /* get integer values from string parameters */
2086 for (i = 0; i < NUM_MUS_ARGS; i++)
2088 get_parameter_value(parameter_raw[i],
2089 music_config_suffix[i].token,
2090 music_config_suffix[i].type);
2092 /* explicit loop mode setting in configuration overrides default value */
2093 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2094 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2097 static void InitMusicInfo()
2099 int num_music = getMusicListSize();
2102 checked_free(music_info);
2104 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2106 for (i = 0; i < num_music; i++)
2108 struct FileInfo *music = getMusicListEntry(i);
2109 int len_music_text = strlen(music->token);
2111 music_info[i].loop = TRUE; /* default: play music in loop mode */
2113 /* determine all loop music */
2115 for (j = 0; music_prefix_info[j].prefix; j++)
2117 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2119 if (len_prefix_text < len_music_text &&
2120 strncmp(music->token,
2121 music_prefix_info[j].prefix, len_prefix_text) == 0)
2123 music_info[i].loop = music_prefix_info[j].is_loop_music;
2129 set_music_parameters(i, music->parameter);
2133 static void ReinitializeGraphics()
2135 print_timestamp_init("ReinitializeGraphics");
2137 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2139 InitGraphicInfo(); /* graphic properties mapping */
2140 print_timestamp_time("InitGraphicInfo");
2141 InitElementGraphicInfo(); /* element game graphic mapping */
2142 print_timestamp_time("InitElementGraphicInfo");
2143 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2144 print_timestamp_time("InitElementSpecialGraphicInfo");
2146 InitElementSmallImages(); /* scale elements to all needed sizes */
2147 print_timestamp_time("InitElementSmallImages");
2148 InitScaledImages(); /* scale all other images, if needed */
2149 print_timestamp_time("InitScaledImages");
2150 InitBitmapPointers(); /* set standard size bitmap pointers */
2151 print_timestamp_time("InitBitmapPointers");
2152 InitFontGraphicInfo(); /* initialize text drawing functions */
2153 print_timestamp_time("InitFontGraphicInfo");
2154 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2155 print_timestamp_time("InitGlobalAnimGraphicInfo");
2157 InitImageTextures(); /* create textures for certain images */
2158 print_timestamp_time("InitImageTextures");
2160 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2161 print_timestamp_time("InitGraphicInfo_EM");
2163 InitGraphicCompatibilityInfo();
2164 print_timestamp_time("InitGraphicCompatibilityInfo");
2166 SetMainBackgroundImage(IMG_BACKGROUND);
2167 print_timestamp_time("SetMainBackgroundImage");
2168 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2169 print_timestamp_time("SetDoorBackgroundImage");
2172 print_timestamp_time("InitGadgets");
2174 print_timestamp_time("InitDoors");
2176 print_timestamp_done("ReinitializeGraphics");
2179 static void ReinitializeSounds()
2181 InitSoundInfo(); /* sound properties mapping */
2182 InitElementSoundInfo(); /* element game sound mapping */
2183 InitGameModeSoundInfo(); /* game mode sound mapping */
2184 InitGlobalAnimSoundInfo(); /* global animation sound settings */
2186 InitPlayLevelSound(); /* internal game sound settings */
2189 static void ReinitializeMusic()
2191 InitMusicInfo(); /* music properties mapping */
2192 InitGameModeMusicInfo(); /* game mode music mapping */
2193 InitGlobalAnimMusicInfo(); /* global animation music settings */
2196 static int get_special_property_bit(int element, int property_bit_nr)
2198 struct PropertyBitInfo
2204 static struct PropertyBitInfo pb_can_move_into_acid[] =
2206 /* the player may be able fall into acid when gravity is activated */
2211 { EL_SP_MURPHY, 0 },
2212 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2214 /* all elements that can move may be able to also move into acid */
2217 { EL_BUG_RIGHT, 1 },
2220 { EL_SPACESHIP, 2 },
2221 { EL_SPACESHIP_LEFT, 2 },
2222 { EL_SPACESHIP_RIGHT, 2 },
2223 { EL_SPACESHIP_UP, 2 },
2224 { EL_SPACESHIP_DOWN, 2 },
2225 { EL_BD_BUTTERFLY, 3 },
2226 { EL_BD_BUTTERFLY_LEFT, 3 },
2227 { EL_BD_BUTTERFLY_RIGHT, 3 },
2228 { EL_BD_BUTTERFLY_UP, 3 },
2229 { EL_BD_BUTTERFLY_DOWN, 3 },
2230 { EL_BD_FIREFLY, 4 },
2231 { EL_BD_FIREFLY_LEFT, 4 },
2232 { EL_BD_FIREFLY_RIGHT, 4 },
2233 { EL_BD_FIREFLY_UP, 4 },
2234 { EL_BD_FIREFLY_DOWN, 4 },
2236 { EL_YAMYAM_LEFT, 5 },
2237 { EL_YAMYAM_RIGHT, 5 },
2238 { EL_YAMYAM_UP, 5 },
2239 { EL_YAMYAM_DOWN, 5 },
2240 { EL_DARK_YAMYAM, 6 },
2243 { EL_PACMAN_LEFT, 8 },
2244 { EL_PACMAN_RIGHT, 8 },
2245 { EL_PACMAN_UP, 8 },
2246 { EL_PACMAN_DOWN, 8 },
2248 { EL_MOLE_LEFT, 9 },
2249 { EL_MOLE_RIGHT, 9 },
2251 { EL_MOLE_DOWN, 9 },
2255 { EL_SATELLITE, 13 },
2256 { EL_SP_SNIKSNAK, 14 },
2257 { EL_SP_ELECTRON, 15 },
2260 { EL_EMC_ANDROID, 18 },
2265 static struct PropertyBitInfo pb_dont_collide_with[] =
2267 { EL_SP_SNIKSNAK, 0 },
2268 { EL_SP_ELECTRON, 1 },
2276 struct PropertyBitInfo *pb_info;
2279 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2280 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2285 struct PropertyBitInfo *pb_info = NULL;
2288 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2289 if (pb_definition[i].bit_nr == property_bit_nr)
2290 pb_info = pb_definition[i].pb_info;
2292 if (pb_info == NULL)
2295 for (i = 0; pb_info[i].element != -1; i++)
2296 if (pb_info[i].element == element)
2297 return pb_info[i].bit_nr;
2302 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2303 boolean property_value)
2305 int bit_nr = get_special_property_bit(element, property_bit_nr);
2310 *bitfield |= (1 << bit_nr);
2312 *bitfield &= ~(1 << bit_nr);
2316 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2318 int bit_nr = get_special_property_bit(element, property_bit_nr);
2321 return ((*bitfield & (1 << bit_nr)) != 0);
2326 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2328 static int group_nr;
2329 static struct ElementGroupInfo *group;
2330 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2333 if (actual_group == NULL) /* not yet initialized */
2336 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2338 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2339 group_element - EL_GROUP_START + 1);
2341 /* replace element which caused too deep recursion by question mark */
2342 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2347 if (recursion_depth == 0) /* initialization */
2349 group = actual_group;
2350 group_nr = GROUP_NR(group_element);
2352 group->num_elements_resolved = 0;
2353 group->choice_pos = 0;
2355 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2356 element_info[i].in_group[group_nr] = FALSE;
2359 for (i = 0; i < actual_group->num_elements; i++)
2361 int element = actual_group->element[i];
2363 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2366 if (IS_GROUP_ELEMENT(element))
2367 ResolveGroupElementExt(element, recursion_depth + 1);
2370 group->element_resolved[group->num_elements_resolved++] = element;
2371 element_info[element].in_group[group_nr] = TRUE;
2376 void ResolveGroupElement(int group_element)
2378 ResolveGroupElementExt(group_element, 0);
2381 void InitElementPropertiesStatic()
2383 static boolean clipboard_elements_initialized = FALSE;
2385 static int ep_diggable[] =
2390 EL_SP_BUGGY_BASE_ACTIVATING,
2393 EL_INVISIBLE_SAND_ACTIVE,
2396 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2397 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2402 EL_SP_BUGGY_BASE_ACTIVE,
2409 static int ep_collectible_only[] =
2431 EL_DYNABOMB_INCREASE_NUMBER,
2432 EL_DYNABOMB_INCREASE_SIZE,
2433 EL_DYNABOMB_INCREASE_POWER,
2451 /* !!! handle separately !!! */
2452 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2458 static int ep_dont_run_into[] =
2460 /* same elements as in 'ep_dont_touch' */
2466 /* same elements as in 'ep_dont_collide_with' */
2478 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2483 EL_SP_BUGGY_BASE_ACTIVE,
2490 static int ep_dont_collide_with[] =
2492 /* same elements as in 'ep_dont_touch' */
2509 static int ep_dont_touch[] =
2519 static int ep_indestructible[] =
2523 EL_ACID_POOL_TOPLEFT,
2524 EL_ACID_POOL_TOPRIGHT,
2525 EL_ACID_POOL_BOTTOMLEFT,
2526 EL_ACID_POOL_BOTTOM,
2527 EL_ACID_POOL_BOTTOMRIGHT,
2528 EL_SP_HARDWARE_GRAY,
2529 EL_SP_HARDWARE_GREEN,
2530 EL_SP_HARDWARE_BLUE,
2532 EL_SP_HARDWARE_YELLOW,
2533 EL_SP_HARDWARE_BASE_1,
2534 EL_SP_HARDWARE_BASE_2,
2535 EL_SP_HARDWARE_BASE_3,
2536 EL_SP_HARDWARE_BASE_4,
2537 EL_SP_HARDWARE_BASE_5,
2538 EL_SP_HARDWARE_BASE_6,
2539 EL_INVISIBLE_STEELWALL,
2540 EL_INVISIBLE_STEELWALL_ACTIVE,
2541 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2542 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2543 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2544 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2545 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2546 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2547 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2548 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2549 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2550 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2551 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2552 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2554 EL_LIGHT_SWITCH_ACTIVE,
2555 EL_SIGN_EXCLAMATION,
2556 EL_SIGN_RADIOACTIVITY,
2563 EL_SIGN_ENTRY_FORBIDDEN,
2564 EL_SIGN_EMERGENCY_EXIT,
2572 EL_STEEL_EXIT_CLOSED,
2574 EL_STEEL_EXIT_OPENING,
2575 EL_STEEL_EXIT_CLOSING,
2576 EL_EM_STEEL_EXIT_CLOSED,
2577 EL_EM_STEEL_EXIT_OPEN,
2578 EL_EM_STEEL_EXIT_OPENING,
2579 EL_EM_STEEL_EXIT_CLOSING,
2580 EL_DC_STEELWALL_1_LEFT,
2581 EL_DC_STEELWALL_1_RIGHT,
2582 EL_DC_STEELWALL_1_TOP,
2583 EL_DC_STEELWALL_1_BOTTOM,
2584 EL_DC_STEELWALL_1_HORIZONTAL,
2585 EL_DC_STEELWALL_1_VERTICAL,
2586 EL_DC_STEELWALL_1_TOPLEFT,
2587 EL_DC_STEELWALL_1_TOPRIGHT,
2588 EL_DC_STEELWALL_1_BOTTOMLEFT,
2589 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2590 EL_DC_STEELWALL_1_TOPLEFT_2,
2591 EL_DC_STEELWALL_1_TOPRIGHT_2,
2592 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2593 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2594 EL_DC_STEELWALL_2_LEFT,
2595 EL_DC_STEELWALL_2_RIGHT,
2596 EL_DC_STEELWALL_2_TOP,
2597 EL_DC_STEELWALL_2_BOTTOM,
2598 EL_DC_STEELWALL_2_HORIZONTAL,
2599 EL_DC_STEELWALL_2_VERTICAL,
2600 EL_DC_STEELWALL_2_MIDDLE,
2601 EL_DC_STEELWALL_2_SINGLE,
2602 EL_STEELWALL_SLIPPERY,
2616 EL_GATE_1_GRAY_ACTIVE,
2617 EL_GATE_2_GRAY_ACTIVE,
2618 EL_GATE_3_GRAY_ACTIVE,
2619 EL_GATE_4_GRAY_ACTIVE,
2628 EL_EM_GATE_1_GRAY_ACTIVE,
2629 EL_EM_GATE_2_GRAY_ACTIVE,
2630 EL_EM_GATE_3_GRAY_ACTIVE,
2631 EL_EM_GATE_4_GRAY_ACTIVE,
2640 EL_EMC_GATE_5_GRAY_ACTIVE,
2641 EL_EMC_GATE_6_GRAY_ACTIVE,
2642 EL_EMC_GATE_7_GRAY_ACTIVE,
2643 EL_EMC_GATE_8_GRAY_ACTIVE,
2645 EL_DC_GATE_WHITE_GRAY,
2646 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2647 EL_DC_GATE_FAKE_GRAY,
2649 EL_SWITCHGATE_OPENING,
2650 EL_SWITCHGATE_CLOSED,
2651 EL_SWITCHGATE_CLOSING,
2652 EL_DC_SWITCHGATE_SWITCH_UP,
2653 EL_DC_SWITCHGATE_SWITCH_DOWN,
2655 EL_TIMEGATE_OPENING,
2657 EL_TIMEGATE_CLOSING,
2658 EL_DC_TIMEGATE_SWITCH,
2659 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2663 EL_TUBE_VERTICAL_LEFT,
2664 EL_TUBE_VERTICAL_RIGHT,
2665 EL_TUBE_HORIZONTAL_UP,
2666 EL_TUBE_HORIZONTAL_DOWN,
2671 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2672 EL_EXPANDABLE_STEELWALL_VERTICAL,
2673 EL_EXPANDABLE_STEELWALL_ANY,
2678 static int ep_slippery[] =
2692 EL_ROBOT_WHEEL_ACTIVE,
2698 EL_ACID_POOL_TOPLEFT,
2699 EL_ACID_POOL_TOPRIGHT,
2709 EL_STEELWALL_SLIPPERY,
2712 EL_EMC_WALL_SLIPPERY_1,
2713 EL_EMC_WALL_SLIPPERY_2,
2714 EL_EMC_WALL_SLIPPERY_3,
2715 EL_EMC_WALL_SLIPPERY_4,
2717 EL_EMC_MAGIC_BALL_ACTIVE,
2722 static int ep_can_change[] =
2727 static int ep_can_move[] =
2729 /* same elements as in 'pb_can_move_into_acid' */
2752 static int ep_can_fall[] =
2766 EL_QUICKSAND_FAST_FULL,
2768 EL_BD_MAGIC_WALL_FULL,
2769 EL_DC_MAGIC_WALL_FULL,
2783 static int ep_can_smash_player[] =
2809 static int ep_can_smash_enemies[] =
2818 static int ep_can_smash_everything[] =
2827 static int ep_explodes_by_fire[] =
2829 /* same elements as in 'ep_explodes_impact' */
2834 /* same elements as in 'ep_explodes_smashed' */
2844 EL_EM_DYNAMITE_ACTIVE,
2845 EL_DYNABOMB_PLAYER_1_ACTIVE,
2846 EL_DYNABOMB_PLAYER_2_ACTIVE,
2847 EL_DYNABOMB_PLAYER_3_ACTIVE,
2848 EL_DYNABOMB_PLAYER_4_ACTIVE,
2849 EL_DYNABOMB_INCREASE_NUMBER,
2850 EL_DYNABOMB_INCREASE_SIZE,
2851 EL_DYNABOMB_INCREASE_POWER,
2852 EL_SP_DISK_RED_ACTIVE,
2866 static int ep_explodes_smashed[] =
2868 /* same elements as in 'ep_explodes_impact' */
2882 static int ep_explodes_impact[] =
2891 static int ep_walkable_over[] =
2895 EL_SOKOBAN_FIELD_EMPTY,
2902 EL_EM_STEEL_EXIT_OPEN,
2903 EL_EM_STEEL_EXIT_OPENING,
2912 EL_GATE_1_GRAY_ACTIVE,
2913 EL_GATE_2_GRAY_ACTIVE,
2914 EL_GATE_3_GRAY_ACTIVE,
2915 EL_GATE_4_GRAY_ACTIVE,
2923 static int ep_walkable_inside[] =
2928 EL_TUBE_VERTICAL_LEFT,
2929 EL_TUBE_VERTICAL_RIGHT,
2930 EL_TUBE_HORIZONTAL_UP,
2931 EL_TUBE_HORIZONTAL_DOWN,
2940 static int ep_walkable_under[] =
2945 static int ep_passable_over[] =
2955 EL_EM_GATE_1_GRAY_ACTIVE,
2956 EL_EM_GATE_2_GRAY_ACTIVE,
2957 EL_EM_GATE_3_GRAY_ACTIVE,
2958 EL_EM_GATE_4_GRAY_ACTIVE,
2967 EL_EMC_GATE_5_GRAY_ACTIVE,
2968 EL_EMC_GATE_6_GRAY_ACTIVE,
2969 EL_EMC_GATE_7_GRAY_ACTIVE,
2970 EL_EMC_GATE_8_GRAY_ACTIVE,
2972 EL_DC_GATE_WHITE_GRAY,
2973 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2980 static int ep_passable_inside[] =
2986 EL_SP_PORT_HORIZONTAL,
2987 EL_SP_PORT_VERTICAL,
2989 EL_SP_GRAVITY_PORT_LEFT,
2990 EL_SP_GRAVITY_PORT_RIGHT,
2991 EL_SP_GRAVITY_PORT_UP,
2992 EL_SP_GRAVITY_PORT_DOWN,
2993 EL_SP_GRAVITY_ON_PORT_LEFT,
2994 EL_SP_GRAVITY_ON_PORT_RIGHT,
2995 EL_SP_GRAVITY_ON_PORT_UP,
2996 EL_SP_GRAVITY_ON_PORT_DOWN,
2997 EL_SP_GRAVITY_OFF_PORT_LEFT,
2998 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2999 EL_SP_GRAVITY_OFF_PORT_UP,
3000 EL_SP_GRAVITY_OFF_PORT_DOWN,
3005 static int ep_passable_under[] =
3010 static int ep_droppable[] =
3015 static int ep_explodes_1x1_old[] =
3020 static int ep_pushable[] =
3032 EL_SOKOBAN_FIELD_FULL,
3041 static int ep_explodes_cross_old[] =
3046 static int ep_protected[] =
3048 /* same elements as in 'ep_walkable_inside' */
3052 EL_TUBE_VERTICAL_LEFT,
3053 EL_TUBE_VERTICAL_RIGHT,
3054 EL_TUBE_HORIZONTAL_UP,
3055 EL_TUBE_HORIZONTAL_DOWN,
3061 /* same elements as in 'ep_passable_over' */
3070 EL_EM_GATE_1_GRAY_ACTIVE,
3071 EL_EM_GATE_2_GRAY_ACTIVE,
3072 EL_EM_GATE_3_GRAY_ACTIVE,
3073 EL_EM_GATE_4_GRAY_ACTIVE,
3082 EL_EMC_GATE_5_GRAY_ACTIVE,
3083 EL_EMC_GATE_6_GRAY_ACTIVE,
3084 EL_EMC_GATE_7_GRAY_ACTIVE,
3085 EL_EMC_GATE_8_GRAY_ACTIVE,
3087 EL_DC_GATE_WHITE_GRAY,
3088 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3092 /* same elements as in 'ep_passable_inside' */
3097 EL_SP_PORT_HORIZONTAL,
3098 EL_SP_PORT_VERTICAL,
3100 EL_SP_GRAVITY_PORT_LEFT,
3101 EL_SP_GRAVITY_PORT_RIGHT,
3102 EL_SP_GRAVITY_PORT_UP,
3103 EL_SP_GRAVITY_PORT_DOWN,
3104 EL_SP_GRAVITY_ON_PORT_LEFT,
3105 EL_SP_GRAVITY_ON_PORT_RIGHT,
3106 EL_SP_GRAVITY_ON_PORT_UP,
3107 EL_SP_GRAVITY_ON_PORT_DOWN,
3108 EL_SP_GRAVITY_OFF_PORT_LEFT,
3109 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3110 EL_SP_GRAVITY_OFF_PORT_UP,
3111 EL_SP_GRAVITY_OFF_PORT_DOWN,
3116 static int ep_throwable[] =
3121 static int ep_can_explode[] =
3123 /* same elements as in 'ep_explodes_impact' */
3128 /* same elements as in 'ep_explodes_smashed' */
3134 /* elements that can explode by explosion or by dragonfire */
3138 EL_EM_DYNAMITE_ACTIVE,
3139 EL_DYNABOMB_PLAYER_1_ACTIVE,
3140 EL_DYNABOMB_PLAYER_2_ACTIVE,
3141 EL_DYNABOMB_PLAYER_3_ACTIVE,
3142 EL_DYNABOMB_PLAYER_4_ACTIVE,
3143 EL_DYNABOMB_INCREASE_NUMBER,
3144 EL_DYNABOMB_INCREASE_SIZE,
3145 EL_DYNABOMB_INCREASE_POWER,
3146 EL_SP_DISK_RED_ACTIVE,
3154 /* elements that can explode only by explosion */
3160 static int ep_gravity_reachable[] =
3166 EL_INVISIBLE_SAND_ACTIVE,
3171 EL_SP_PORT_HORIZONTAL,
3172 EL_SP_PORT_VERTICAL,
3174 EL_SP_GRAVITY_PORT_LEFT,
3175 EL_SP_GRAVITY_PORT_RIGHT,
3176 EL_SP_GRAVITY_PORT_UP,
3177 EL_SP_GRAVITY_PORT_DOWN,
3178 EL_SP_GRAVITY_ON_PORT_LEFT,
3179 EL_SP_GRAVITY_ON_PORT_RIGHT,
3180 EL_SP_GRAVITY_ON_PORT_UP,
3181 EL_SP_GRAVITY_ON_PORT_DOWN,
3182 EL_SP_GRAVITY_OFF_PORT_LEFT,
3183 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3184 EL_SP_GRAVITY_OFF_PORT_UP,
3185 EL_SP_GRAVITY_OFF_PORT_DOWN,
3191 static int ep_player[] =
3198 EL_SOKOBAN_FIELD_PLAYER,
3204 static int ep_can_pass_magic_wall[] =
3218 static int ep_can_pass_dc_magic_wall[] =
3234 static int ep_switchable[] =
3238 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3239 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3240 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3241 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3242 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3243 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3244 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3245 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3246 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3247 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3248 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3249 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3250 EL_SWITCHGATE_SWITCH_UP,
3251 EL_SWITCHGATE_SWITCH_DOWN,
3252 EL_DC_SWITCHGATE_SWITCH_UP,
3253 EL_DC_SWITCHGATE_SWITCH_DOWN,
3255 EL_LIGHT_SWITCH_ACTIVE,
3257 EL_DC_TIMEGATE_SWITCH,
3258 EL_BALLOON_SWITCH_LEFT,
3259 EL_BALLOON_SWITCH_RIGHT,
3260 EL_BALLOON_SWITCH_UP,
3261 EL_BALLOON_SWITCH_DOWN,
3262 EL_BALLOON_SWITCH_ANY,
3263 EL_BALLOON_SWITCH_NONE,
3266 EL_EMC_MAGIC_BALL_SWITCH,
3267 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3272 static int ep_bd_element[] =
3306 static int ep_sp_element[] =
3308 /* should always be valid */
3311 /* standard classic Supaplex elements */
3318 EL_SP_HARDWARE_GRAY,
3326 EL_SP_GRAVITY_PORT_RIGHT,
3327 EL_SP_GRAVITY_PORT_DOWN,
3328 EL_SP_GRAVITY_PORT_LEFT,
3329 EL_SP_GRAVITY_PORT_UP,
3334 EL_SP_PORT_VERTICAL,
3335 EL_SP_PORT_HORIZONTAL,
3341 EL_SP_HARDWARE_BASE_1,
3342 EL_SP_HARDWARE_GREEN,
3343 EL_SP_HARDWARE_BLUE,
3345 EL_SP_HARDWARE_YELLOW,
3346 EL_SP_HARDWARE_BASE_2,
3347 EL_SP_HARDWARE_BASE_3,
3348 EL_SP_HARDWARE_BASE_4,
3349 EL_SP_HARDWARE_BASE_5,
3350 EL_SP_HARDWARE_BASE_6,
3354 /* additional elements that appeared in newer Supaplex levels */
3357 /* additional gravity port elements (not switching, but setting gravity) */
3358 EL_SP_GRAVITY_ON_PORT_LEFT,
3359 EL_SP_GRAVITY_ON_PORT_RIGHT,
3360 EL_SP_GRAVITY_ON_PORT_UP,
3361 EL_SP_GRAVITY_ON_PORT_DOWN,
3362 EL_SP_GRAVITY_OFF_PORT_LEFT,
3363 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3364 EL_SP_GRAVITY_OFF_PORT_UP,
3365 EL_SP_GRAVITY_OFF_PORT_DOWN,
3367 /* more than one Murphy in a level results in an inactive clone */
3370 /* runtime Supaplex elements */
3371 EL_SP_DISK_RED_ACTIVE,
3372 EL_SP_TERMINAL_ACTIVE,
3373 EL_SP_BUGGY_BASE_ACTIVATING,
3374 EL_SP_BUGGY_BASE_ACTIVE,
3381 static int ep_sb_element[] =
3386 EL_SOKOBAN_FIELD_EMPTY,
3387 EL_SOKOBAN_FIELD_FULL,
3388 EL_SOKOBAN_FIELD_PLAYER,
3393 EL_INVISIBLE_STEELWALL,
3398 static int ep_gem[] =
3410 static int ep_food_dark_yamyam[] =
3438 static int ep_food_penguin[] =
3452 static int ep_food_pig[] =
3464 static int ep_historic_wall[] =
3475 EL_GATE_1_GRAY_ACTIVE,
3476 EL_GATE_2_GRAY_ACTIVE,
3477 EL_GATE_3_GRAY_ACTIVE,
3478 EL_GATE_4_GRAY_ACTIVE,
3487 EL_EM_GATE_1_GRAY_ACTIVE,
3488 EL_EM_GATE_2_GRAY_ACTIVE,
3489 EL_EM_GATE_3_GRAY_ACTIVE,
3490 EL_EM_GATE_4_GRAY_ACTIVE,
3497 EL_EXPANDABLE_WALL_HORIZONTAL,
3498 EL_EXPANDABLE_WALL_VERTICAL,
3499 EL_EXPANDABLE_WALL_ANY,
3500 EL_EXPANDABLE_WALL_GROWING,
3501 EL_BD_EXPANDABLE_WALL,
3508 EL_SP_HARDWARE_GRAY,
3509 EL_SP_HARDWARE_GREEN,
3510 EL_SP_HARDWARE_BLUE,
3512 EL_SP_HARDWARE_YELLOW,
3513 EL_SP_HARDWARE_BASE_1,
3514 EL_SP_HARDWARE_BASE_2,
3515 EL_SP_HARDWARE_BASE_3,
3516 EL_SP_HARDWARE_BASE_4,
3517 EL_SP_HARDWARE_BASE_5,
3518 EL_SP_HARDWARE_BASE_6,
3520 EL_SP_TERMINAL_ACTIVE,
3523 EL_INVISIBLE_STEELWALL,
3524 EL_INVISIBLE_STEELWALL_ACTIVE,
3526 EL_INVISIBLE_WALL_ACTIVE,
3527 EL_STEELWALL_SLIPPERY,
3544 static int ep_historic_solid[] =
3548 EL_EXPANDABLE_WALL_HORIZONTAL,
3549 EL_EXPANDABLE_WALL_VERTICAL,
3550 EL_EXPANDABLE_WALL_ANY,
3551 EL_BD_EXPANDABLE_WALL,
3564 EL_QUICKSAND_FILLING,
3565 EL_QUICKSAND_EMPTYING,
3567 EL_MAGIC_WALL_ACTIVE,
3568 EL_MAGIC_WALL_EMPTYING,
3569 EL_MAGIC_WALL_FILLING,
3573 EL_BD_MAGIC_WALL_ACTIVE,
3574 EL_BD_MAGIC_WALL_EMPTYING,
3575 EL_BD_MAGIC_WALL_FULL,
3576 EL_BD_MAGIC_WALL_FILLING,
3577 EL_BD_MAGIC_WALL_DEAD,
3586 EL_SP_TERMINAL_ACTIVE,
3590 EL_INVISIBLE_WALL_ACTIVE,
3591 EL_SWITCHGATE_SWITCH_UP,
3592 EL_SWITCHGATE_SWITCH_DOWN,
3593 EL_DC_SWITCHGATE_SWITCH_UP,
3594 EL_DC_SWITCHGATE_SWITCH_DOWN,
3596 EL_TIMEGATE_SWITCH_ACTIVE,
3597 EL_DC_TIMEGATE_SWITCH,
3598 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3610 /* the following elements are a direct copy of "indestructible" elements,
3611 except "EL_ACID", which is "indestructible", but not "solid"! */
3616 EL_ACID_POOL_TOPLEFT,
3617 EL_ACID_POOL_TOPRIGHT,
3618 EL_ACID_POOL_BOTTOMLEFT,
3619 EL_ACID_POOL_BOTTOM,
3620 EL_ACID_POOL_BOTTOMRIGHT,
3621 EL_SP_HARDWARE_GRAY,
3622 EL_SP_HARDWARE_GREEN,
3623 EL_SP_HARDWARE_BLUE,
3625 EL_SP_HARDWARE_YELLOW,
3626 EL_SP_HARDWARE_BASE_1,
3627 EL_SP_HARDWARE_BASE_2,
3628 EL_SP_HARDWARE_BASE_3,
3629 EL_SP_HARDWARE_BASE_4,
3630 EL_SP_HARDWARE_BASE_5,
3631 EL_SP_HARDWARE_BASE_6,
3632 EL_INVISIBLE_STEELWALL,
3633 EL_INVISIBLE_STEELWALL_ACTIVE,
3634 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3635 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3636 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3637 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3638 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3639 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3640 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3641 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3642 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3643 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3644 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3645 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3647 EL_LIGHT_SWITCH_ACTIVE,
3648 EL_SIGN_EXCLAMATION,
3649 EL_SIGN_RADIOACTIVITY,
3656 EL_SIGN_ENTRY_FORBIDDEN,
3657 EL_SIGN_EMERGENCY_EXIT,
3665 EL_STEEL_EXIT_CLOSED,
3667 EL_DC_STEELWALL_1_LEFT,
3668 EL_DC_STEELWALL_1_RIGHT,
3669 EL_DC_STEELWALL_1_TOP,
3670 EL_DC_STEELWALL_1_BOTTOM,
3671 EL_DC_STEELWALL_1_HORIZONTAL,
3672 EL_DC_STEELWALL_1_VERTICAL,
3673 EL_DC_STEELWALL_1_TOPLEFT,
3674 EL_DC_STEELWALL_1_TOPRIGHT,
3675 EL_DC_STEELWALL_1_BOTTOMLEFT,
3676 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3677 EL_DC_STEELWALL_1_TOPLEFT_2,
3678 EL_DC_STEELWALL_1_TOPRIGHT_2,
3679 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3680 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3681 EL_DC_STEELWALL_2_LEFT,
3682 EL_DC_STEELWALL_2_RIGHT,
3683 EL_DC_STEELWALL_2_TOP,
3684 EL_DC_STEELWALL_2_BOTTOM,
3685 EL_DC_STEELWALL_2_HORIZONTAL,
3686 EL_DC_STEELWALL_2_VERTICAL,
3687 EL_DC_STEELWALL_2_MIDDLE,
3688 EL_DC_STEELWALL_2_SINGLE,
3689 EL_STEELWALL_SLIPPERY,
3703 EL_GATE_1_GRAY_ACTIVE,
3704 EL_GATE_2_GRAY_ACTIVE,
3705 EL_GATE_3_GRAY_ACTIVE,
3706 EL_GATE_4_GRAY_ACTIVE,
3715 EL_EM_GATE_1_GRAY_ACTIVE,
3716 EL_EM_GATE_2_GRAY_ACTIVE,
3717 EL_EM_GATE_3_GRAY_ACTIVE,
3718 EL_EM_GATE_4_GRAY_ACTIVE,
3720 EL_SWITCHGATE_OPENING,
3721 EL_SWITCHGATE_CLOSED,
3722 EL_SWITCHGATE_CLOSING,
3724 EL_TIMEGATE_OPENING,
3726 EL_TIMEGATE_CLOSING,
3730 EL_TUBE_VERTICAL_LEFT,
3731 EL_TUBE_VERTICAL_RIGHT,
3732 EL_TUBE_HORIZONTAL_UP,
3733 EL_TUBE_HORIZONTAL_DOWN,
3742 static int ep_classic_enemy[] =
3759 static int ep_belt[] =
3761 EL_CONVEYOR_BELT_1_LEFT,
3762 EL_CONVEYOR_BELT_1_MIDDLE,
3763 EL_CONVEYOR_BELT_1_RIGHT,
3764 EL_CONVEYOR_BELT_2_LEFT,
3765 EL_CONVEYOR_BELT_2_MIDDLE,
3766 EL_CONVEYOR_BELT_2_RIGHT,
3767 EL_CONVEYOR_BELT_3_LEFT,
3768 EL_CONVEYOR_BELT_3_MIDDLE,
3769 EL_CONVEYOR_BELT_3_RIGHT,
3770 EL_CONVEYOR_BELT_4_LEFT,
3771 EL_CONVEYOR_BELT_4_MIDDLE,
3772 EL_CONVEYOR_BELT_4_RIGHT,
3777 static int ep_belt_active[] =
3779 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3780 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3781 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3782 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3783 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3784 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3785 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3786 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3787 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3788 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3789 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3790 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3795 static int ep_belt_switch[] =
3797 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3798 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3799 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3800 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3801 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3802 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3803 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3804 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3805 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3806 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3807 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3808 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3813 static int ep_tube[] =
3820 EL_TUBE_HORIZONTAL_UP,
3821 EL_TUBE_HORIZONTAL_DOWN,
3823 EL_TUBE_VERTICAL_LEFT,
3824 EL_TUBE_VERTICAL_RIGHT,
3830 static int ep_acid_pool[] =
3832 EL_ACID_POOL_TOPLEFT,
3833 EL_ACID_POOL_TOPRIGHT,
3834 EL_ACID_POOL_BOTTOMLEFT,
3835 EL_ACID_POOL_BOTTOM,
3836 EL_ACID_POOL_BOTTOMRIGHT,
3841 static int ep_keygate[] =
3851 EL_GATE_1_GRAY_ACTIVE,
3852 EL_GATE_2_GRAY_ACTIVE,
3853 EL_GATE_3_GRAY_ACTIVE,
3854 EL_GATE_4_GRAY_ACTIVE,
3863 EL_EM_GATE_1_GRAY_ACTIVE,
3864 EL_EM_GATE_2_GRAY_ACTIVE,
3865 EL_EM_GATE_3_GRAY_ACTIVE,
3866 EL_EM_GATE_4_GRAY_ACTIVE,
3875 EL_EMC_GATE_5_GRAY_ACTIVE,
3876 EL_EMC_GATE_6_GRAY_ACTIVE,
3877 EL_EMC_GATE_7_GRAY_ACTIVE,
3878 EL_EMC_GATE_8_GRAY_ACTIVE,
3880 EL_DC_GATE_WHITE_GRAY,
3881 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3886 static int ep_amoeboid[] =
3898 static int ep_amoebalive[] =
3909 static int ep_has_editor_content[] =
3915 EL_SOKOBAN_FIELD_PLAYER,
3932 static int ep_can_turn_each_move[] =
3934 /* !!! do something with this one !!! */
3938 static int ep_can_grow[] =
3952 static int ep_active_bomb[] =
3955 EL_EM_DYNAMITE_ACTIVE,
3956 EL_DYNABOMB_PLAYER_1_ACTIVE,
3957 EL_DYNABOMB_PLAYER_2_ACTIVE,
3958 EL_DYNABOMB_PLAYER_3_ACTIVE,
3959 EL_DYNABOMB_PLAYER_4_ACTIVE,
3960 EL_SP_DISK_RED_ACTIVE,
3965 static int ep_inactive[] =
3975 EL_QUICKSAND_FAST_EMPTY,
3998 EL_GATE_1_GRAY_ACTIVE,
3999 EL_GATE_2_GRAY_ACTIVE,
4000 EL_GATE_3_GRAY_ACTIVE,
4001 EL_GATE_4_GRAY_ACTIVE,
4010 EL_EM_GATE_1_GRAY_ACTIVE,
4011 EL_EM_GATE_2_GRAY_ACTIVE,
4012 EL_EM_GATE_3_GRAY_ACTIVE,
4013 EL_EM_GATE_4_GRAY_ACTIVE,
4022 EL_EMC_GATE_5_GRAY_ACTIVE,
4023 EL_EMC_GATE_6_GRAY_ACTIVE,
4024 EL_EMC_GATE_7_GRAY_ACTIVE,
4025 EL_EMC_GATE_8_GRAY_ACTIVE,
4027 EL_DC_GATE_WHITE_GRAY,
4028 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4029 EL_DC_GATE_FAKE_GRAY,
4032 EL_INVISIBLE_STEELWALL,
4040 EL_WALL_EMERALD_YELLOW,
4041 EL_DYNABOMB_INCREASE_NUMBER,
4042 EL_DYNABOMB_INCREASE_SIZE,
4043 EL_DYNABOMB_INCREASE_POWER,
4047 EL_SOKOBAN_FIELD_EMPTY,
4048 EL_SOKOBAN_FIELD_FULL,
4049 EL_WALL_EMERALD_RED,
4050 EL_WALL_EMERALD_PURPLE,
4051 EL_ACID_POOL_TOPLEFT,
4052 EL_ACID_POOL_TOPRIGHT,
4053 EL_ACID_POOL_BOTTOMLEFT,
4054 EL_ACID_POOL_BOTTOM,
4055 EL_ACID_POOL_BOTTOMRIGHT,
4059 EL_BD_MAGIC_WALL_DEAD,
4061 EL_DC_MAGIC_WALL_DEAD,
4062 EL_AMOEBA_TO_DIAMOND,
4070 EL_SP_GRAVITY_PORT_RIGHT,
4071 EL_SP_GRAVITY_PORT_DOWN,
4072 EL_SP_GRAVITY_PORT_LEFT,
4073 EL_SP_GRAVITY_PORT_UP,
4074 EL_SP_PORT_HORIZONTAL,
4075 EL_SP_PORT_VERTICAL,
4086 EL_SP_HARDWARE_GRAY,
4087 EL_SP_HARDWARE_GREEN,
4088 EL_SP_HARDWARE_BLUE,
4090 EL_SP_HARDWARE_YELLOW,
4091 EL_SP_HARDWARE_BASE_1,
4092 EL_SP_HARDWARE_BASE_2,
4093 EL_SP_HARDWARE_BASE_3,
4094 EL_SP_HARDWARE_BASE_4,
4095 EL_SP_HARDWARE_BASE_5,
4096 EL_SP_HARDWARE_BASE_6,
4097 EL_SP_GRAVITY_ON_PORT_LEFT,
4098 EL_SP_GRAVITY_ON_PORT_RIGHT,
4099 EL_SP_GRAVITY_ON_PORT_UP,
4100 EL_SP_GRAVITY_ON_PORT_DOWN,
4101 EL_SP_GRAVITY_OFF_PORT_LEFT,
4102 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4103 EL_SP_GRAVITY_OFF_PORT_UP,
4104 EL_SP_GRAVITY_OFF_PORT_DOWN,
4105 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4106 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4107 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4108 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4109 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4110 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4111 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4112 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4113 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4114 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4115 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4116 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4117 EL_SIGN_EXCLAMATION,
4118 EL_SIGN_RADIOACTIVITY,
4125 EL_SIGN_ENTRY_FORBIDDEN,
4126 EL_SIGN_EMERGENCY_EXIT,
4134 EL_DC_STEELWALL_1_LEFT,
4135 EL_DC_STEELWALL_1_RIGHT,
4136 EL_DC_STEELWALL_1_TOP,
4137 EL_DC_STEELWALL_1_BOTTOM,
4138 EL_DC_STEELWALL_1_HORIZONTAL,
4139 EL_DC_STEELWALL_1_VERTICAL,
4140 EL_DC_STEELWALL_1_TOPLEFT,
4141 EL_DC_STEELWALL_1_TOPRIGHT,
4142 EL_DC_STEELWALL_1_BOTTOMLEFT,
4143 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4144 EL_DC_STEELWALL_1_TOPLEFT_2,
4145 EL_DC_STEELWALL_1_TOPRIGHT_2,
4146 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4147 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4148 EL_DC_STEELWALL_2_LEFT,
4149 EL_DC_STEELWALL_2_RIGHT,
4150 EL_DC_STEELWALL_2_TOP,
4151 EL_DC_STEELWALL_2_BOTTOM,
4152 EL_DC_STEELWALL_2_HORIZONTAL,
4153 EL_DC_STEELWALL_2_VERTICAL,
4154 EL_DC_STEELWALL_2_MIDDLE,
4155 EL_DC_STEELWALL_2_SINGLE,
4156 EL_STEELWALL_SLIPPERY,
4161 EL_EMC_WALL_SLIPPERY_1,
4162 EL_EMC_WALL_SLIPPERY_2,
4163 EL_EMC_WALL_SLIPPERY_3,
4164 EL_EMC_WALL_SLIPPERY_4,
4185 static int ep_em_slippery_wall[] =
4190 static int ep_gfx_crumbled[] =
4201 static int ep_editor_cascade_active[] =
4203 EL_INTERNAL_CASCADE_BD_ACTIVE,
4204 EL_INTERNAL_CASCADE_EM_ACTIVE,
4205 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4206 EL_INTERNAL_CASCADE_RND_ACTIVE,
4207 EL_INTERNAL_CASCADE_SB_ACTIVE,
4208 EL_INTERNAL_CASCADE_SP_ACTIVE,
4209 EL_INTERNAL_CASCADE_DC_ACTIVE,
4210 EL_INTERNAL_CASCADE_DX_ACTIVE,
4211 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4212 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4213 EL_INTERNAL_CASCADE_CE_ACTIVE,
4214 EL_INTERNAL_CASCADE_GE_ACTIVE,
4215 EL_INTERNAL_CASCADE_REF_ACTIVE,
4216 EL_INTERNAL_CASCADE_USER_ACTIVE,
4217 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4222 static int ep_editor_cascade_inactive[] =
4224 EL_INTERNAL_CASCADE_BD,
4225 EL_INTERNAL_CASCADE_EM,
4226 EL_INTERNAL_CASCADE_EMC,
4227 EL_INTERNAL_CASCADE_RND,
4228 EL_INTERNAL_CASCADE_SB,
4229 EL_INTERNAL_CASCADE_SP,
4230 EL_INTERNAL_CASCADE_DC,
4231 EL_INTERNAL_CASCADE_DX,
4232 EL_INTERNAL_CASCADE_CHARS,
4233 EL_INTERNAL_CASCADE_STEEL_CHARS,
4234 EL_INTERNAL_CASCADE_CE,
4235 EL_INTERNAL_CASCADE_GE,
4236 EL_INTERNAL_CASCADE_REF,
4237 EL_INTERNAL_CASCADE_USER,
4238 EL_INTERNAL_CASCADE_DYNAMIC,
4243 static int ep_obsolete[] =
4247 EL_EM_KEY_1_FILE_OBSOLETE,
4248 EL_EM_KEY_2_FILE_OBSOLETE,
4249 EL_EM_KEY_3_FILE_OBSOLETE,
4250 EL_EM_KEY_4_FILE_OBSOLETE,
4251 EL_ENVELOPE_OBSOLETE,
4260 } element_properties[] =
4262 { ep_diggable, EP_DIGGABLE },
4263 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4264 { ep_dont_run_into, EP_DONT_RUN_INTO },
4265 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4266 { ep_dont_touch, EP_DONT_TOUCH },
4267 { ep_indestructible, EP_INDESTRUCTIBLE },
4268 { ep_slippery, EP_SLIPPERY },
4269 { ep_can_change, EP_CAN_CHANGE },
4270 { ep_can_move, EP_CAN_MOVE },
4271 { ep_can_fall, EP_CAN_FALL },
4272 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4273 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4274 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4275 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4276 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4277 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4278 { ep_walkable_over, EP_WALKABLE_OVER },
4279 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4280 { ep_walkable_under, EP_WALKABLE_UNDER },
4281 { ep_passable_over, EP_PASSABLE_OVER },
4282 { ep_passable_inside, EP_PASSABLE_INSIDE },
4283 { ep_passable_under, EP_PASSABLE_UNDER },
4284 { ep_droppable, EP_DROPPABLE },
4285 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4286 { ep_pushable, EP_PUSHABLE },
4287 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4288 { ep_protected, EP_PROTECTED },
4289 { ep_throwable, EP_THROWABLE },
4290 { ep_can_explode, EP_CAN_EXPLODE },
4291 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4293 { ep_player, EP_PLAYER },
4294 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4295 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4296 { ep_switchable, EP_SWITCHABLE },
4297 { ep_bd_element, EP_BD_ELEMENT },
4298 { ep_sp_element, EP_SP_ELEMENT },
4299 { ep_sb_element, EP_SB_ELEMENT },
4301 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4302 { ep_food_penguin, EP_FOOD_PENGUIN },
4303 { ep_food_pig, EP_FOOD_PIG },
4304 { ep_historic_wall, EP_HISTORIC_WALL },
4305 { ep_historic_solid, EP_HISTORIC_SOLID },
4306 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4307 { ep_belt, EP_BELT },
4308 { ep_belt_active, EP_BELT_ACTIVE },
4309 { ep_belt_switch, EP_BELT_SWITCH },
4310 { ep_tube, EP_TUBE },
4311 { ep_acid_pool, EP_ACID_POOL },
4312 { ep_keygate, EP_KEYGATE },
4313 { ep_amoeboid, EP_AMOEBOID },
4314 { ep_amoebalive, EP_AMOEBALIVE },
4315 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4316 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4317 { ep_can_grow, EP_CAN_GROW },
4318 { ep_active_bomb, EP_ACTIVE_BOMB },
4319 { ep_inactive, EP_INACTIVE },
4321 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4323 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4325 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4326 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4328 { ep_obsolete, EP_OBSOLETE },
4335 /* always start with reliable default values (element has no properties) */
4336 /* (but never initialize clipboard elements after the very first time) */
4337 /* (to be able to use clipboard elements between several levels) */
4338 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4339 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4340 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4341 SET_PROPERTY(i, j, FALSE);
4343 /* set all base element properties from above array definitions */
4344 for (i = 0; element_properties[i].elements != NULL; i++)
4345 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4346 SET_PROPERTY((element_properties[i].elements)[j],
4347 element_properties[i].property, TRUE);
4349 /* copy properties to some elements that are only stored in level file */
4350 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4351 for (j = 0; copy_properties[j][0] != -1; j++)
4352 if (HAS_PROPERTY(copy_properties[j][0], i))
4353 for (k = 1; k <= 4; k++)
4354 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4356 /* set static element properties that are not listed in array definitions */
4357 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4358 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4360 clipboard_elements_initialized = TRUE;
4363 void InitElementPropertiesEngine(int engine_version)
4365 static int no_wall_properties[] =
4368 EP_COLLECTIBLE_ONLY,
4370 EP_DONT_COLLIDE_WITH,
4373 EP_CAN_SMASH_PLAYER,
4374 EP_CAN_SMASH_ENEMIES,
4375 EP_CAN_SMASH_EVERYTHING,
4380 EP_FOOD_DARK_YAMYAM,
4396 /* important: after initialization in InitElementPropertiesStatic(), the
4397 elements are not again initialized to a default value; therefore all
4398 changes have to make sure that they leave the element with a defined
4399 property (which means that conditional property changes must be set to
4400 a reliable default value before) */
4402 /* resolve group elements */
4403 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4404 ResolveGroupElement(EL_GROUP_START + i);
4406 /* set all special, combined or engine dependent element properties */
4407 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4409 /* do not change (already initialized) clipboard elements here */
4410 if (IS_CLIPBOARD_ELEMENT(i))
4413 /* ---------- INACTIVE ------------------------------------------------- */
4414 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4415 i <= EL_CHAR_END) ||
4416 (i >= EL_STEEL_CHAR_START &&
4417 i <= EL_STEEL_CHAR_END)));
4419 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4420 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4421 IS_WALKABLE_INSIDE(i) ||
4422 IS_WALKABLE_UNDER(i)));
4424 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4425 IS_PASSABLE_INSIDE(i) ||
4426 IS_PASSABLE_UNDER(i)));
4428 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4429 IS_PASSABLE_OVER(i)));
4431 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4432 IS_PASSABLE_INSIDE(i)));
4434 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4435 IS_PASSABLE_UNDER(i)));
4437 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4440 /* ---------- COLLECTIBLE ---------------------------------------------- */
4441 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4445 /* ---------- SNAPPABLE ------------------------------------------------ */
4446 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4447 IS_COLLECTIBLE(i) ||
4451 /* ---------- WALL ----------------------------------------------------- */
4452 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4454 for (j = 0; no_wall_properties[j] != -1; j++)
4455 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4456 i >= EL_FIRST_RUNTIME_UNREAL)
4457 SET_PROPERTY(i, EP_WALL, FALSE);
4459 if (IS_HISTORIC_WALL(i))
4460 SET_PROPERTY(i, EP_WALL, TRUE);
4462 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4463 if (engine_version < VERSION_IDENT(2,2,0,0))
4464 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4466 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4468 !IS_COLLECTIBLE(i)));
4470 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4471 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4472 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4474 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4475 IS_INDESTRUCTIBLE(i)));
4477 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4479 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4480 else if (engine_version < VERSION_IDENT(2,2,0,0))
4481 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4483 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4487 if (IS_CUSTOM_ELEMENT(i))
4489 /* these are additional properties which are initially false when set */
4491 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4493 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4494 if (DONT_COLLIDE_WITH(i))
4495 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4497 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4498 if (CAN_SMASH_EVERYTHING(i))
4499 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4500 if (CAN_SMASH_ENEMIES(i))
4501 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4504 /* ---------- CAN_SMASH ------------------------------------------------ */
4505 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4506 CAN_SMASH_ENEMIES(i) ||
4507 CAN_SMASH_EVERYTHING(i)));
4509 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4510 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4511 EXPLODES_BY_FIRE(i)));
4513 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4514 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4515 EXPLODES_SMASHED(i)));
4517 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4518 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4519 EXPLODES_IMPACT(i)));
4521 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4522 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4524 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4525 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4526 i == EL_BLACK_ORB));
4528 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4529 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4531 IS_CUSTOM_ELEMENT(i)));
4533 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4534 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4535 i == EL_SP_ELECTRON));
4537 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4538 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4539 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4540 getMoveIntoAcidProperty(&level, i));
4542 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4543 if (MAYBE_DONT_COLLIDE_WITH(i))
4544 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4545 getDontCollideWithProperty(&level, i));
4547 /* ---------- SP_PORT -------------------------------------------------- */
4548 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4549 IS_PASSABLE_INSIDE(i)));
4551 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4552 for (j = 0; j < level.num_android_clone_elements; j++)
4553 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4555 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4557 /* ---------- CAN_CHANGE ----------------------------------------------- */
4558 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4559 for (j = 0; j < element_info[i].num_change_pages; j++)
4560 if (element_info[i].change_page[j].can_change)
4561 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4563 /* ---------- HAS_ACTION ----------------------------------------------- */
4564 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4565 for (j = 0; j < element_info[i].num_change_pages; j++)
4566 if (element_info[i].change_page[j].has_action)
4567 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4569 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4570 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4573 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4574 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4575 element_info[i].crumbled[ACTION_DEFAULT] !=
4576 element_info[i].graphic[ACTION_DEFAULT]);
4578 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4579 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4580 IS_EDITOR_CASCADE_INACTIVE(i)));
4583 /* dynamically adjust element properties according to game engine version */
4585 static int ep_em_slippery_wall[] =
4590 EL_EXPANDABLE_WALL_HORIZONTAL,
4591 EL_EXPANDABLE_WALL_VERTICAL,
4592 EL_EXPANDABLE_WALL_ANY,
4593 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4594 EL_EXPANDABLE_STEELWALL_VERTICAL,
4595 EL_EXPANDABLE_STEELWALL_ANY,
4596 EL_EXPANDABLE_STEELWALL_GROWING,
4600 static int ep_em_explodes_by_fire[] =
4603 EL_EM_DYNAMITE_ACTIVE,
4608 /* special EM style gems behaviour */
4609 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4610 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4611 level.em_slippery_gems);
4613 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4614 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4615 (level.em_slippery_gems &&
4616 engine_version > VERSION_IDENT(2,0,1,0)));
4618 /* special EM style explosion behaviour regarding chain reactions */
4619 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4620 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4621 level.em_explodes_by_fire);
4624 /* this is needed because some graphics depend on element properties */
4625 if (game_status == GAME_MODE_PLAYING)
4626 InitElementGraphicInfo();
4629 void InitElementPropertiesAfterLoading(int engine_version)
4633 /* set some other uninitialized values of custom elements in older levels */
4634 if (engine_version < VERSION_IDENT(3,1,0,0))
4636 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4638 int element = EL_CUSTOM_START + i;
4640 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4642 element_info[element].explosion_delay = 17;
4643 element_info[element].ignition_delay = 8;
4648 void InitElementPropertiesGfxElement()
4652 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4654 struct ElementInfo *ei = &element_info[i];
4656 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4660 static void InitGlobal()
4665 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4667 /* check if element_name_info entry defined for each element in "main.h" */
4668 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4669 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4671 element_info[i].token_name = element_name_info[i].token_name;
4672 element_info[i].class_name = element_name_info[i].class_name;
4673 element_info[i].editor_description= element_name_info[i].editor_description;
4676 /* create hash from image config list */
4677 image_config_hash = newSetupFileHash();
4678 for (i = 0; image_config[i].token != NULL; i++)
4679 setHashEntry(image_config_hash,
4680 image_config[i].token,
4681 image_config[i].value);
4683 /* create hash from element token list */
4684 element_token_hash = newSetupFileHash();
4685 for (i = 0; element_name_info[i].token_name != NULL; i++)
4686 setHashEntry(element_token_hash,
4687 element_name_info[i].token_name,
4690 /* create hash from graphic token list */
4691 graphic_token_hash = newSetupFileHash();
4692 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4693 if (strSuffix(image_config[i].value, ".png") ||
4694 strSuffix(image_config[i].value, ".pcx") ||
4695 strSuffix(image_config[i].value, ".wav") ||
4696 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4697 setHashEntry(graphic_token_hash,
4698 image_config[i].token,
4699 int2str(graphic++, 0));
4701 /* create hash from font token list */
4702 font_token_hash = newSetupFileHash();
4703 for (i = 0; font_info[i].token_name != NULL; i++)
4704 setHashEntry(font_token_hash,
4705 font_info[i].token_name,
4708 /* set default filenames for all cloned graphics in static configuration */
4709 for (i = 0; image_config[i].token != NULL; i++)
4711 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4713 char *token = image_config[i].token;
4714 char *token_clone_from = getStringCat2(token, ".clone_from");
4715 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4717 if (token_cloned != NULL)
4719 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4721 if (value_cloned != NULL)
4723 /* set default filename in static configuration */
4724 image_config[i].value = value_cloned;
4726 /* set default filename in image config hash */
4727 setHashEntry(image_config_hash, token, value_cloned);
4731 free(token_clone_from);
4735 /* always start with reliable default values (all elements) */
4736 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4737 ActiveElement[i] = i;
4739 /* now add all entries that have an active state (active elements) */
4740 for (i = 0; element_with_active_state[i].element != -1; i++)
4742 int element = element_with_active_state[i].element;
4743 int element_active = element_with_active_state[i].element_active;
4745 ActiveElement[element] = element_active;
4748 /* always start with reliable default values (all buttons) */
4749 for (i = 0; i < NUM_IMAGE_FILES; i++)
4750 ActiveButton[i] = i;
4752 /* now add all entries that have an active state (active buttons) */
4753 for (i = 0; button_with_active_state[i].button != -1; i++)
4755 int button = button_with_active_state[i].button;
4756 int button_active = button_with_active_state[i].button_active;
4758 ActiveButton[button] = button_active;
4761 /* always start with reliable default values (all fonts) */
4762 for (i = 0; i < NUM_FONTS; i++)
4765 /* now add all entries that have an active state (active fonts) */
4766 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4768 int font = font_with_active_state[i].font_nr;
4769 int font_active = font_with_active_state[i].font_nr_active;
4771 ActiveFont[font] = font_active;
4774 global.autoplay_leveldir = NULL;
4775 global.convert_leveldir = NULL;
4776 global.create_images_dir = NULL;
4778 global.frames_per_second = 0;
4780 global.border_status = GAME_MODE_LOADING;
4781 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4783 global.use_envelope_request = FALSE;
4786 void Execute_Command(char *command)
4790 if (strEqual(command, "print graphicsinfo.conf"))
4792 Print("# You can configure additional/alternative image files here.\n");
4793 Print("# (The entries below are default and therefore commented out.)\n");
4795 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4797 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4800 for (i = 0; image_config[i].token != NULL; i++)
4801 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4802 image_config[i].value));
4806 else if (strEqual(command, "print soundsinfo.conf"))
4808 Print("# You can configure additional/alternative sound files here.\n");
4809 Print("# (The entries below are default and therefore commented out.)\n");
4811 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4813 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4816 for (i = 0; sound_config[i].token != NULL; i++)
4817 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4818 sound_config[i].value));
4822 else if (strEqual(command, "print musicinfo.conf"))
4824 Print("# You can configure additional/alternative music files here.\n");
4825 Print("# (The entries below are default and therefore commented out.)\n");
4827 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4829 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4832 for (i = 0; music_config[i].token != NULL; i++)
4833 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4834 music_config[i].value));
4838 else if (strEqual(command, "print editorsetup.conf"))
4840 Print("# You can configure your personal editor element list here.\n");
4841 Print("# (The entries below are default and therefore commented out.)\n");
4844 /* this is needed to be able to check element list for cascade elements */
4845 InitElementPropertiesStatic();
4846 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4848 PrintEditorElementList();
4852 else if (strEqual(command, "print helpanim.conf"))
4854 Print("# You can configure different element help animations here.\n");
4855 Print("# (The entries below are default and therefore commented out.)\n");
4858 for (i = 0; helpanim_config[i].token != NULL; i++)
4860 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4861 helpanim_config[i].value));
4863 if (strEqual(helpanim_config[i].token, "end"))
4869 else if (strEqual(command, "print helptext.conf"))
4871 Print("# You can configure different element help text here.\n");
4872 Print("# (The entries below are default and therefore commented out.)\n");
4875 for (i = 0; helptext_config[i].token != NULL; i++)
4876 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4877 helptext_config[i].value));
4881 else if (strPrefix(command, "dump level "))
4883 char *filename = &command[11];
4885 if (!fileExists(filename))
4886 Error(ERR_EXIT, "cannot open file '%s'", filename);
4888 LoadLevelFromFilename(&level, filename);
4893 else if (strPrefix(command, "dump tape "))
4895 char *filename = &command[10];
4897 if (!fileExists(filename))
4898 Error(ERR_EXIT, "cannot open file '%s'", filename);
4900 LoadTapeFromFilename(filename);
4905 else if (strPrefix(command, "autotest ") ||
4906 strPrefix(command, "autoplay ") ||
4907 strPrefix(command, "autoffwd ") ||
4908 strPrefix(command, "autowarp "))
4910 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4912 global.autoplay_mode =
4913 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
4914 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
4915 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
4916 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
4917 AUTOPLAY_MODE_NONE);
4919 while (*str_ptr != '\0') /* continue parsing string */
4921 /* cut leading whitespace from string, replace it by string terminator */
4922 while (*str_ptr == ' ' || *str_ptr == '\t')
4925 if (*str_ptr == '\0') /* end of string reached */
4928 if (global.autoplay_leveldir == NULL) /* read level set string */
4930 global.autoplay_leveldir = str_ptr;
4931 global.autoplay_all = TRUE; /* default: play all tapes */
4933 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4934 global.autoplay_level[i] = FALSE;
4936 else /* read level number string */
4938 int level_nr = atoi(str_ptr); /* get level_nr value */
4940 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4941 global.autoplay_level[level_nr] = TRUE;
4943 global.autoplay_all = FALSE;
4946 /* advance string pointer to the next whitespace (or end of string) */
4947 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4951 else if (strPrefix(command, "convert "))
4953 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4954 char *str_ptr = strchr(str_copy, ' ');
4956 global.convert_leveldir = str_copy;
4957 global.convert_level_nr = -1;
4959 if (str_ptr != NULL) /* level number follows */
4961 *str_ptr++ = '\0'; /* terminate leveldir string */
4962 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4965 else if (strPrefix(command, "create images "))
4967 global.create_images_dir = getStringCopy(&command[14]);
4969 if (access(global.create_images_dir, W_OK) != 0)
4970 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4971 global.create_images_dir);
4973 else if (strPrefix(command, "create CE image "))
4975 CreateCustomElementImages(&command[16]);
4981 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4985 static void InitSetup()
4987 LoadSetup(); /* global setup info */
4989 /* set some options from setup file */
4991 if (setup.options.verbose)
4992 options.verbose = TRUE;
4995 static void InitGameInfo()
4997 game.restart_level = FALSE;
5000 static void InitPlayerInfo()
5004 /* choose default local player */
5005 local_player = &stored_player[0];
5007 for (i = 0; i < MAX_PLAYERS; i++)
5008 stored_player[i].connected = FALSE;
5010 local_player->connected = TRUE;
5013 static void InitArtworkInfo()
5018 static char *get_string_in_brackets(char *string)
5020 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5022 sprintf(string_in_brackets, "[%s]", string);
5024 return string_in_brackets;
5027 static char *get_level_id_suffix(int id_nr)
5029 char *id_suffix = checked_malloc(1 + 3 + 1);
5031 if (id_nr < 0 || id_nr > 999)
5034 sprintf(id_suffix, ".%03d", id_nr);
5039 static void InitArtworkConfig()
5041 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5043 NUM_GLOBAL_ANIM_TOKENS + 1];
5044 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5045 NUM_GLOBAL_ANIM_TOKENS + 1];
5046 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5047 NUM_GLOBAL_ANIM_TOKENS + 1];
5048 static char *action_id_suffix[NUM_ACTIONS + 1];
5049 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5050 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5051 static char *level_id_suffix[MAX_LEVELS + 1];
5052 static char *dummy[1] = { NULL };
5053 static char *ignore_generic_tokens[] =
5059 static char **ignore_image_tokens;
5060 static char **ignore_sound_tokens;
5061 static char **ignore_music_tokens;
5062 int num_ignore_generic_tokens;
5063 int num_ignore_image_tokens;
5064 int num_ignore_sound_tokens;
5065 int num_ignore_music_tokens;
5068 /* dynamically determine list of generic tokens to be ignored */
5069 num_ignore_generic_tokens = 0;
5070 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5071 num_ignore_generic_tokens++;
5073 /* dynamically determine list of image tokens to be ignored */
5074 num_ignore_image_tokens = num_ignore_generic_tokens;
5075 for (i = 0; image_config_vars[i].token != NULL; i++)
5076 num_ignore_image_tokens++;
5077 ignore_image_tokens =
5078 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5079 for (i = 0; i < num_ignore_generic_tokens; i++)
5080 ignore_image_tokens[i] = ignore_generic_tokens[i];
5081 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5082 ignore_image_tokens[num_ignore_generic_tokens + i] =
5083 image_config_vars[i].token;
5084 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5086 /* dynamically determine list of sound tokens to be ignored */
5087 num_ignore_sound_tokens = num_ignore_generic_tokens;
5088 ignore_sound_tokens =
5089 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5090 for (i = 0; i < num_ignore_generic_tokens; i++)
5091 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5092 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5094 /* dynamically determine list of music tokens to be ignored */
5095 num_ignore_music_tokens = num_ignore_generic_tokens;
5096 ignore_music_tokens =
5097 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5098 for (i = 0; i < num_ignore_generic_tokens; i++)
5099 ignore_music_tokens[i] = ignore_generic_tokens[i];
5100 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5102 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5103 image_id_prefix[i] = element_info[i].token_name;
5104 for (i = 0; i < NUM_FONTS; i++)
5105 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5106 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5107 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5108 global_anim_info[i].token_name;
5109 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5111 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5112 sound_id_prefix[i] = element_info[i].token_name;
5113 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5114 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5115 get_string_in_brackets(element_info[i].class_name);
5116 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5117 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5118 global_anim_info[i].token_name;
5119 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5121 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5122 music_id_prefix[i] = music_prefix_info[i].prefix;
5123 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5124 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5125 global_anim_info[i].token_name;
5126 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5128 for (i = 0; i < NUM_ACTIONS; i++)
5129 action_id_suffix[i] = element_action_info[i].suffix;
5130 action_id_suffix[NUM_ACTIONS] = NULL;
5132 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5133 direction_id_suffix[i] = element_direction_info[i].suffix;
5134 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5136 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5137 special_id_suffix[i] = special_suffix_info[i].suffix;
5138 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5140 for (i = 0; i < MAX_LEVELS; i++)
5141 level_id_suffix[i] = get_level_id_suffix(i);
5142 level_id_suffix[MAX_LEVELS] = NULL;
5144 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5145 image_id_prefix, action_id_suffix, direction_id_suffix,
5146 special_id_suffix, ignore_image_tokens);
5147 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5148 sound_id_prefix, action_id_suffix, dummy,
5149 special_id_suffix, ignore_sound_tokens);
5150 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5151 music_id_prefix, action_id_suffix, special_id_suffix,
5152 level_id_suffix, ignore_music_tokens);
5155 static void InitMixer()
5162 void InitGfxBuffers()
5164 static int win_xsize_last = -1;
5165 static int win_ysize_last = -1;
5167 /* create additional image buffers for double-buffering and cross-fading */
5169 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5171 /* used to temporarily store the backbuffer -- only re-create if changed */
5172 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5173 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5175 win_xsize_last = WIN_XSIZE;
5176 win_ysize_last = WIN_YSIZE;
5179 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5180 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5181 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5182 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5184 /* initialize screen properties */
5185 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5186 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5188 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5189 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5190 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5191 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5192 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5193 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5195 /* required if door size definitions have changed */
5196 InitGraphicCompatibilityInfo_Doors();
5198 InitGfxBuffers_EM();
5199 InitGfxBuffers_SP();
5204 struct GraphicInfo *graphic_info_last = graphic_info;
5205 char *filename_font_initial = NULL;
5206 char *filename_anim_initial = NULL;
5207 Bitmap *bitmap_font_initial = NULL;
5211 /* determine settings for initial font (for displaying startup messages) */
5212 for (i = 0; image_config[i].token != NULL; i++)
5214 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5216 char font_token[128];
5219 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5220 len_font_token = strlen(font_token);
5222 if (strEqual(image_config[i].token, font_token))
5223 filename_font_initial = image_config[i].value;
5224 else if (strlen(image_config[i].token) > len_font_token &&
5225 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5227 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5228 font_initial[j].src_x = atoi(image_config[i].value);
5229 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5230 font_initial[j].src_y = atoi(image_config[i].value);
5231 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5232 font_initial[j].width = atoi(image_config[i].value);
5233 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5234 font_initial[j].height = atoi(image_config[i].value);
5239 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5241 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5242 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5245 if (filename_font_initial == NULL) /* should not happen */
5246 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5249 InitGfxCustomArtworkInfo();
5250 InitGfxOtherSettings();
5252 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5254 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5255 font_initial[j].bitmap = bitmap_font_initial;
5257 InitFontGraphicInfo();
5259 font_height = getFontHeight(FC_RED);
5261 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5262 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5263 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5266 DrawInitText("Loading graphics", 120, FC_GREEN);
5268 /* initialize settings for busy animation with default values */
5269 int parameter[NUM_GFX_ARGS];
5270 for (i = 0; i < NUM_GFX_ARGS; i++)
5271 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5272 image_config_suffix[i].token,
5273 image_config_suffix[i].type);
5275 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5276 int len_anim_token = strlen(anim_token);
5278 /* read settings for busy animation from default custom artwork config */
5279 char *gfx_config_filename = getPath3(options.graphics_directory,
5281 GRAPHICSINFO_FILENAME);
5283 if (fileExists(gfx_config_filename))
5285 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5287 if (setup_file_hash)
5289 char *filename = getHashEntry(setup_file_hash, anim_token);
5293 filename_anim_initial = getStringCopy(filename);
5295 for (j = 0; image_config_suffix[j].token != NULL; j++)
5297 int type = image_config_suffix[j].type;
5298 char *suffix = image_config_suffix[j].token;
5299 char *token = getStringCat2(anim_token, suffix);
5300 char *value = getHashEntry(setup_file_hash, token);
5302 checked_free(token);
5305 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5309 freeSetupFileHash(setup_file_hash);
5313 if (filename_anim_initial == NULL)
5315 /* read settings for busy animation from static default artwork config */
5316 for (i = 0; image_config[i].token != NULL; i++)
5318 if (strEqual(image_config[i].token, anim_token))
5319 filename_anim_initial = getStringCopy(image_config[i].value);
5320 else if (strlen(image_config[i].token) > len_anim_token &&
5321 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5323 for (j = 0; image_config_suffix[j].token != NULL; j++)
5325 if (strEqual(&image_config[i].token[len_anim_token],
5326 image_config_suffix[j].token))
5328 get_graphic_parameter_value(image_config[i].value,
5329 image_config_suffix[j].token,
5330 image_config_suffix[j].type);
5336 if (filename_anim_initial == NULL) /* should not happen */
5337 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5339 anim_initial.bitmaps =
5340 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5342 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5343 LoadCustomImage(filename_anim_initial);
5345 checked_free(filename_anim_initial);
5347 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5349 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5351 graphic_info = graphic_info_last;
5353 init.busy.width = anim_initial.width;
5354 init.busy.height = anim_initial.height;
5356 InitMenuDesignSettings_Static();
5358 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5359 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5360 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5362 gfx.fade_border_source_status = global.border_status;
5363 gfx.fade_border_target_status = global.border_status;
5364 gfx.masked_border_bitmap_ptr = backbuffer;
5366 /* use copy of busy animation to prevent change while reloading artwork */
5370 void InitGfxBackground()
5372 fieldbuffer = bitmap_db_field;
5373 SetDrawtoField(DRAW_TO_BACKBUFFER);
5375 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5377 redraw_mask = REDRAW_ALL;
5380 static void InitLevelInfo()
5382 LoadLevelInfo(); /* global level info */
5383 LoadLevelSetup_LastSeries(); /* last played series info */
5384 LoadLevelSetup_SeriesInfo(); /* last played level info */
5386 if (global.autoplay_leveldir &&
5387 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5389 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5390 global.autoplay_leveldir);
5391 if (leveldir_current == NULL)
5392 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5396 static void InitLevelArtworkInfo()
5398 LoadLevelArtworkInfo();
5401 static void InitImages()
5403 print_timestamp_init("InitImages");
5406 printf("::: leveldir_current->identifier == '%s'\n",
5407 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5408 printf("::: leveldir_current->graphics_path == '%s'\n",
5409 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5410 printf("::: leveldir_current->graphics_set == '%s'\n",
5411 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5412 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5413 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5416 setLevelArtworkDir(artwork.gfx_first);
5419 printf("::: leveldir_current->identifier == '%s'\n",
5420 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5421 printf("::: leveldir_current->graphics_path == '%s'\n",
5422 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5423 printf("::: leveldir_current->graphics_set == '%s'\n",
5424 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5425 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5426 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5430 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5431 leveldir_current->identifier,
5432 artwork.gfx_current_identifier,
5433 artwork.gfx_current->identifier,
5434 leveldir_current->graphics_set,
5435 leveldir_current->graphics_path);
5438 UPDATE_BUSY_STATE();
5440 ReloadCustomImages();
5441 print_timestamp_time("ReloadCustomImages");
5443 UPDATE_BUSY_STATE();
5445 LoadCustomElementDescriptions();
5446 print_timestamp_time("LoadCustomElementDescriptions");
5448 UPDATE_BUSY_STATE();
5450 LoadMenuDesignSettings();
5451 print_timestamp_time("LoadMenuDesignSettings");
5453 UPDATE_BUSY_STATE();
5455 ReinitializeGraphics();
5456 print_timestamp_time("ReinitializeGraphics");
5458 UPDATE_BUSY_STATE();
5460 print_timestamp_done("InitImages");
5463 static void InitSound(char *identifier)
5465 print_timestamp_init("InitSound");
5467 if (identifier == NULL)
5468 identifier = artwork.snd_current->identifier;
5470 /* set artwork path to send it to the sound server process */
5471 setLevelArtworkDir(artwork.snd_first);
5473 InitReloadCustomSounds(identifier);
5474 print_timestamp_time("InitReloadCustomSounds");
5476 ReinitializeSounds();
5477 print_timestamp_time("ReinitializeSounds");
5479 print_timestamp_done("InitSound");
5482 static void InitMusic(char *identifier)
5484 print_timestamp_init("InitMusic");
5486 if (identifier == NULL)
5487 identifier = artwork.mus_current->identifier;
5489 /* set artwork path to send it to the sound server process */
5490 setLevelArtworkDir(artwork.mus_first);
5492 InitReloadCustomMusic(identifier);
5493 print_timestamp_time("InitReloadCustomMusic");
5495 ReinitializeMusic();
5496 print_timestamp_time("ReinitializeMusic");
5498 print_timestamp_done("InitMusic");
5501 static void InitArtworkDone()
5503 InitGlobalAnimations();
5506 void InitNetworkServer()
5508 #if defined(NETWORK_AVALIABLE)
5512 if (!options.network)
5515 #if defined(NETWORK_AVALIABLE)
5516 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5518 if (!ConnectToServer(options.server_host, options.server_port))
5519 Error(ERR_EXIT, "cannot connect to network game server");
5521 SendToServer_PlayerName(setup.player_name);
5522 SendToServer_ProtocolVersion();
5525 SendToServer_NrWanted(nr_wanted);
5529 static boolean CheckArtworkConfigForCustomElements(char *filename)
5531 SetupFileHash *setup_file_hash;
5532 boolean redefined_ce_found = FALSE;
5534 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5536 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5538 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5540 char *token = HASH_ITERATION_TOKEN(itr);
5542 if (strPrefix(token, "custom_"))
5544 redefined_ce_found = TRUE;
5549 END_HASH_ITERATION(setup_file_hash, itr)
5551 freeSetupFileHash(setup_file_hash);
5554 return redefined_ce_found;
5557 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5559 char *filename_base, *filename_local;
5560 boolean redefined_ce_found = FALSE;
5562 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5565 printf("::: leveldir_current->identifier == '%s'\n",
5566 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5567 printf("::: leveldir_current->graphics_path == '%s'\n",
5568 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5569 printf("::: leveldir_current->graphics_set == '%s'\n",
5570 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5571 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5572 leveldir_current == NULL ? "[NULL]" :
5573 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5576 /* first look for special artwork configured in level series config */
5577 filename_base = getCustomArtworkLevelConfigFilename(type);
5580 printf("::: filename_base == '%s'\n", filename_base);
5583 if (fileExists(filename_base))
5584 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5586 filename_local = getCustomArtworkConfigFilename(type);
5589 printf("::: filename_local == '%s'\n", filename_local);
5592 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5593 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5596 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5599 return redefined_ce_found;
5602 static void InitOverrideArtwork()
5604 boolean redefined_ce_found = FALSE;
5606 /* to check if this level set redefines any CEs, do not use overriding */
5607 gfx.override_level_graphics = FALSE;
5608 gfx.override_level_sounds = FALSE;
5609 gfx.override_level_music = FALSE;
5611 /* now check if this level set has definitions for custom elements */
5612 if (setup.override_level_graphics == AUTO ||
5613 setup.override_level_sounds == AUTO ||
5614 setup.override_level_music == AUTO)
5615 redefined_ce_found =
5616 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5617 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5618 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5621 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5624 if (redefined_ce_found)
5626 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5627 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5628 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5629 gfx.override_level_music = (setup.override_level_music == TRUE);
5633 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5634 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5635 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5636 gfx.override_level_music = (setup.override_level_music != FALSE);
5640 printf("::: => %d, %d, %d\n",
5641 gfx.override_level_graphics,
5642 gfx.override_level_sounds,
5643 gfx.override_level_music);
5647 static char *getNewArtworkIdentifier(int type)
5649 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5650 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5651 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5652 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5653 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5654 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5655 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5656 char *leveldir_identifier = leveldir_current->identifier;
5657 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5658 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5659 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5660 char *artwork_current_identifier;
5661 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5663 /* leveldir_current may be invalid (level group, parent link) */
5664 if (!validLevelSeries(leveldir_current))
5667 /* 1st step: determine artwork set to be activated in descending order:
5668 --------------------------------------------------------------------
5669 1. setup artwork (when configured to override everything else)
5670 2. artwork set configured in "levelinfo.conf" of current level set
5671 (artwork in level directory will have priority when loading later)
5672 3. artwork in level directory (stored in artwork sub-directory)
5673 4. setup artwork (currently configured in setup menu) */
5675 if (setup_override_artwork)
5676 artwork_current_identifier = setup_artwork_set;
5677 else if (leveldir_artwork_set != NULL)
5678 artwork_current_identifier = leveldir_artwork_set;
5679 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5680 artwork_current_identifier = leveldir_identifier;
5682 artwork_current_identifier = setup_artwork_set;
5685 /* 2nd step: check if it is really needed to reload artwork set
5686 ------------------------------------------------------------ */
5688 /* ---------- reload if level set and also artwork set has changed ------- */
5689 if (leveldir_current_identifier[type] != leveldir_identifier &&
5690 (last_has_level_artwork_set[type] || has_level_artwork_set))
5691 artwork_new_identifier = artwork_current_identifier;
5693 leveldir_current_identifier[type] = leveldir_identifier;
5694 last_has_level_artwork_set[type] = has_level_artwork_set;
5696 /* ---------- reload if "override artwork" setting has changed ----------- */
5697 if (last_override_level_artwork[type] != setup_override_artwork)
5698 artwork_new_identifier = artwork_current_identifier;
5700 last_override_level_artwork[type] = setup_override_artwork;
5702 /* ---------- reload if current artwork identifier has changed ----------- */
5703 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5704 artwork_current_identifier))
5705 artwork_new_identifier = artwork_current_identifier;
5707 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5709 /* ---------- do not reload directly after starting ---------------------- */
5710 if (!initialized[type])
5711 artwork_new_identifier = NULL;
5713 initialized[type] = TRUE;
5715 return artwork_new_identifier;
5718 void ReloadCustomArtwork(int force_reload)
5720 int last_game_status = game_status; /* save current game status */
5721 char *gfx_new_identifier;
5722 char *snd_new_identifier;
5723 char *mus_new_identifier;
5724 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5725 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5726 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5727 boolean reload_needed;
5729 InitOverrideArtwork();
5731 force_reload_gfx |= AdjustGraphicsForEMC();
5733 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5734 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5735 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5737 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5738 snd_new_identifier != NULL || force_reload_snd ||
5739 mus_new_identifier != NULL || force_reload_mus);
5744 print_timestamp_init("ReloadCustomArtwork");
5746 SetGameStatus(GAME_MODE_LOADING);
5748 FadeOut(REDRAW_ALL);
5750 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5751 print_timestamp_time("ClearRectangle");
5755 if (gfx_new_identifier != NULL || force_reload_gfx)
5758 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5759 artwork.gfx_current_identifier,
5761 artwork.gfx_current->identifier,
5762 leveldir_current->graphics_set);
5766 print_timestamp_time("InitImages");
5769 if (snd_new_identifier != NULL || force_reload_snd)
5771 InitSound(snd_new_identifier);
5772 print_timestamp_time("InitSound");
5775 if (mus_new_identifier != NULL || force_reload_mus)
5777 InitMusic(mus_new_identifier);
5778 print_timestamp_time("InitMusic");
5783 SetGameStatus(last_game_status); /* restore current game status */
5785 init_last = init; /* switch to new busy animation */
5787 FadeOut(REDRAW_ALL);
5789 RedrawGlobalBorder();
5791 /* force redraw of (open or closed) door graphics */
5792 SetDoorState(DOOR_OPEN_ALL);
5793 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5795 FadeSetEnterScreen();
5796 FadeSkipNextFadeOut();
5798 print_timestamp_done("ReloadCustomArtwork");
5800 LimitScreenUpdates(FALSE);
5803 void KeyboardAutoRepeatOffUnlessAutoplay()
5805 if (global.autoplay_leveldir == NULL)
5806 KeyboardAutoRepeatOff();
5809 void DisplayExitMessage(char *format, va_list ap)
5811 // check if draw buffer and fonts for exit message are already available
5812 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5815 int font_1 = FC_RED;
5816 int font_2 = FC_YELLOW;
5817 int font_3 = FC_BLUE;
5818 int font_width = getFontWidth(font_2);
5819 int font_height = getFontHeight(font_2);
5822 int sxsize = WIN_XSIZE - 2 * sx;
5823 int sysize = WIN_YSIZE - 2 * sy;
5824 int line_length = sxsize / font_width;
5825 int max_lines = sysize / font_height;
5826 int num_lines_printed;
5830 gfx.sxsize = sxsize;
5831 gfx.sysize = sysize;
5835 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5837 DrawTextSCentered(sy, font_1, "Fatal error:");
5838 sy += 3 * font_height;;
5841 DrawTextBufferVA(sx, sy, format, ap, font_2,
5842 line_length, line_length, max_lines,
5843 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5844 sy += (num_lines_printed + 3) * font_height;
5846 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5847 sy += 3 * font_height;
5850 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5851 line_length, line_length, max_lines,
5852 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5854 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5856 redraw_mask = REDRAW_ALL;
5858 /* force drawing exit message even if screen updates are currently limited */
5859 LimitScreenUpdates(FALSE);
5863 /* deactivate toons on error message screen */
5864 setup.toons = FALSE;
5866 WaitForEventToContinue();
5870 /* ========================================================================= */
5872 /* ========================================================================= */
5876 print_timestamp_init("OpenAll");
5878 SetGameStatus(GAME_MODE_LOADING);
5882 InitGlobal(); /* initialize some global variables */
5884 print_timestamp_time("[init global stuff]");
5888 print_timestamp_time("[init setup/config stuff (1)]");
5890 if (options.execute_command)
5891 Execute_Command(options.execute_command);
5893 if (options.serveronly)
5895 #if defined(PLATFORM_UNIX)
5896 NetworkServer(options.server_port, options.serveronly);
5898 Error(ERR_WARN, "networking only supported in Unix version");
5901 exit(0); /* never reached, server loops forever */
5905 print_timestamp_time("[init setup/config stuff (2)]");
5907 print_timestamp_time("[init setup/config stuff (3)]");
5908 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5909 print_timestamp_time("[init setup/config stuff (4)]");
5910 InitArtworkConfig(); /* needed before forking sound child process */
5911 print_timestamp_time("[init setup/config stuff (5)]");
5913 print_timestamp_time("[init setup/config stuff (6)]");
5915 InitRND(NEW_RANDOMIZE);
5916 InitSimpleRandom(NEW_RANDOMIZE);
5920 print_timestamp_time("[init setup/config stuff]");
5923 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5925 InitEventFilter(FilterEvents);
5927 print_timestamp_time("[init video stuff]");
5929 InitElementPropertiesStatic();
5930 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5931 InitElementPropertiesGfxElement();
5933 print_timestamp_time("[init element properties stuff]");
5937 print_timestamp_time("InitGfx");
5940 print_timestamp_time("InitLevelInfo");
5942 InitLevelArtworkInfo();
5943 print_timestamp_time("InitLevelArtworkInfo");
5945 InitOverrideArtwork(); /* needs to know current level directory */
5946 print_timestamp_time("InitOverrideArtwork");
5948 InitImages(); /* needs to know current level directory */
5949 print_timestamp_time("InitImages");
5951 InitSound(NULL); /* needs to know current level directory */
5952 print_timestamp_time("InitSound");
5954 InitMusic(NULL); /* needs to know current level directory */
5955 print_timestamp_time("InitMusic");
5959 InitGfxBackground();
5964 if (global.autoplay_leveldir)
5969 else if (global.convert_leveldir)
5974 else if (global.create_images_dir)
5976 CreateLevelSketchImages();
5980 SetGameStatus(GAME_MODE_MAIN);
5982 FadeSetEnterScreen();
5983 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5984 FadeSkipNextFadeOut();
5986 print_timestamp_time("[post-artwork]");
5988 print_timestamp_done("OpenAll");
5992 InitNetworkServer();
5995 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5997 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5998 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5999 #if defined(PLATFORM_ANDROID)
6000 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6001 SDL_AndroidGetInternalStoragePath());
6002 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6003 SDL_AndroidGetExternalStoragePath());
6004 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6005 (SDL_AndroidGetExternalStorageState() ==
6006 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
6007 SDL_AndroidGetExternalStorageState() ==
6008 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
6013 void CloseAllAndExit(int exit_value)
6018 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6025 #if defined(TARGET_SDL)
6026 #if defined(TARGET_SDL2)
6028 // set a flag to tell the network server thread to quit and wait for it
6029 // using SDL_WaitThread()
6031 if (network_server) /* terminate network server */
6032 SDL_KillThread(server_thread);
6036 CloseVideoDisplay();
6037 ClosePlatformDependentStuff();
6039 if (exit_value != 0)
6041 /* fall back to default level set (current set may have caused an error) */
6042 SaveLevelSetup_LastSeries_Deactivate();
6044 /* tell user where to find error log file which may contain more details */
6045 // (error notification now directly displayed on screen inside R'n'D
6046 // NotifyUserAboutErrorFile(); /* currently only works for Windows */