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 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 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 images from dynamic configuration (may be elements or other) */
209 for (i = 0; i < num_property_mappings; i++)
210 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
211 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
213 /* initialize special images from above list (non-element images) */
214 for (i = 0; special_graphics[i] > -1; i++)
215 InitElementSmallImagesScaledUp(special_graphics[i]);
216 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
218 print_timestamp_done("InitElementSmallImages");
221 void InitScaledImages()
225 /* scale normal images from static configuration, if not already scaled */
226 for (i = 0; i < NUM_IMAGE_FILES; i++)
227 ScaleImage(i, graphic_info[i].scale_up_factor);
230 void InitBitmapPointers()
232 int num_images = getImageListSize();
235 // standard size bitmap may have changed -- update default bitmap pointer
236 for (i = 0; i < num_images; i++)
237 if (graphic_info[i].bitmaps)
238 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
241 void InitImageTextures()
245 FreeAllImageTextures();
247 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
248 CreateImageTextures(i);
250 for (i = 0; i < MAX_NUM_TOONS; i++)
251 CreateImageTextures(IMG_TOON_1 + i);
253 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
255 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
257 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
259 int graphic = global_anim_info[i].graphic[j][k];
261 if (graphic == IMG_UNDEFINED)
264 CreateImageTextures(graphic);
271 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
272 void SetBitmaps_EM(Bitmap **em_bitmap)
274 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
275 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
280 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
281 void SetBitmaps_SP(Bitmap **sp_bitmap)
283 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
287 static int getFontBitmapID(int font_nr)
291 /* (special case: do not use special font for GAME_MODE_LOADING) */
292 if (game_status >= GAME_MODE_TITLE_INITIAL &&
293 game_status <= GAME_MODE_PSEUDO_PREVIEW)
294 special = game_status;
295 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
296 special = GFX_SPECIAL_ARG_MAIN;
299 return font_info[font_nr].special_bitmap_id[special];
304 static int getFontFromToken(char *token)
306 char *value = getHashEntry(font_token_hash, token);
311 /* if font not found, use reliable default value */
312 return FONT_INITIAL_1;
315 void InitFontGraphicInfo()
317 static struct FontBitmapInfo *font_bitmap_info = NULL;
318 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
319 int num_property_mappings = getImageListPropertyMappingSize();
320 int num_font_bitmaps = NUM_FONTS;
323 if (graphic_info == NULL) /* still at startup phase */
325 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
326 getFontBitmapID, getFontFromToken);
331 /* ---------- initialize font graphic definitions ---------- */
333 /* always start with reliable default values (normal font graphics) */
334 for (i = 0; i < NUM_FONTS; i++)
335 font_info[i].graphic = IMG_FONT_INITIAL_1;
337 /* initialize normal font/graphic mapping from static configuration */
338 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
340 int font_nr = font_to_graphic[i].font_nr;
341 int special = font_to_graphic[i].special;
342 int graphic = font_to_graphic[i].graphic;
347 font_info[font_nr].graphic = graphic;
350 /* always start with reliable default values (special font graphics) */
351 for (i = 0; i < NUM_FONTS; i++)
353 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
355 font_info[i].special_graphic[j] = font_info[i].graphic;
356 font_info[i].special_bitmap_id[j] = i;
360 /* initialize special font/graphic mapping from static configuration */
361 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
363 int font_nr = font_to_graphic[i].font_nr;
364 int special = font_to_graphic[i].special;
365 int graphic = font_to_graphic[i].graphic;
366 int base_graphic = font2baseimg(font_nr);
368 if (IS_SPECIAL_GFX_ARG(special))
370 boolean base_redefined =
371 getImageListEntryFromImageID(base_graphic)->redefined;
372 boolean special_redefined =
373 getImageListEntryFromImageID(graphic)->redefined;
374 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
376 /* if the base font ("font.title_1", for example) has been redefined,
377 but not the special font ("font.title_1.LEVELS", for example), do not
378 use an existing (in this case considered obsolete) special font
379 anymore, but use the automatically determined default font */
380 /* special case: cloned special fonts must be explicitly redefined,
381 but are not automatically redefined by redefining base font */
382 if (base_redefined && !special_redefined && !special_cloned)
385 font_info[font_nr].special_graphic[special] = graphic;
386 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
391 /* initialize special font/graphic mapping from dynamic configuration */
392 for (i = 0; i < num_property_mappings; i++)
394 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
395 int special = property_mapping[i].ext3_index;
396 int graphic = property_mapping[i].artwork_index;
401 if (IS_SPECIAL_GFX_ARG(special))
403 font_info[font_nr].special_graphic[special] = graphic;
404 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
409 /* correct special font/graphic mapping for cloned fonts for downwards
410 compatibility of PREVIEW fonts -- this is only needed for implicit
411 redefinition of special font by redefined base font, and only if other
412 fonts are cloned from this special font (like in the "Zelda" level set) */
413 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
415 int font_nr = font_to_graphic[i].font_nr;
416 int special = font_to_graphic[i].special;
417 int graphic = font_to_graphic[i].graphic;
419 if (IS_SPECIAL_GFX_ARG(special))
421 boolean special_redefined =
422 getImageListEntryFromImageID(graphic)->redefined;
423 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
425 if (special_cloned && !special_redefined)
429 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
431 int font_nr2 = font_to_graphic[j].font_nr;
432 int special2 = font_to_graphic[j].special;
433 int graphic2 = font_to_graphic[j].graphic;
435 if (IS_SPECIAL_GFX_ARG(special2) &&
436 graphic2 == graphic_info[graphic].clone_from)
438 font_info[font_nr].special_graphic[special] =
439 font_info[font_nr2].special_graphic[special2];
440 font_info[font_nr].special_bitmap_id[special] =
441 font_info[font_nr2].special_bitmap_id[special2];
448 /* reset non-redefined ".active" font graphics if normal font is redefined */
449 /* (this different treatment is needed because normal and active fonts are
450 independently defined ("active" is not a property of font definitions!) */
451 for (i = 0; i < NUM_FONTS; i++)
453 int font_nr_base = i;
454 int font_nr_active = FONT_ACTIVE(font_nr_base);
456 /* check only those fonts with exist as normal and ".active" variant */
457 if (font_nr_base != font_nr_active)
459 int base_graphic = font_info[font_nr_base].graphic;
460 int active_graphic = font_info[font_nr_active].graphic;
461 boolean base_redefined =
462 getImageListEntryFromImageID(base_graphic)->redefined;
463 boolean active_redefined =
464 getImageListEntryFromImageID(active_graphic)->redefined;
466 /* if the base font ("font.menu_1", for example) has been redefined,
467 but not the active font ("font.menu_1.active", for example), do not
468 use an existing (in this case considered obsolete) active font
469 anymore, but use the automatically determined default font */
470 if (base_redefined && !active_redefined)
471 font_info[font_nr_active].graphic = base_graphic;
473 /* now also check each "special" font (which may be the same as above) */
474 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
476 int base_graphic = font_info[font_nr_base].special_graphic[j];
477 int active_graphic = font_info[font_nr_active].special_graphic[j];
478 boolean base_redefined =
479 getImageListEntryFromImageID(base_graphic)->redefined;
480 boolean active_redefined =
481 getImageListEntryFromImageID(active_graphic)->redefined;
483 /* same as above, but check special graphic definitions, for example:
484 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
485 if (base_redefined && !active_redefined)
487 font_info[font_nr_active].special_graphic[j] =
488 font_info[font_nr_base].special_graphic[j];
489 font_info[font_nr_active].special_bitmap_id[j] =
490 font_info[font_nr_base].special_bitmap_id[j];
496 /* ---------- initialize font bitmap array ---------- */
498 if (font_bitmap_info != NULL)
499 FreeFontInfo(font_bitmap_info);
502 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
504 /* ---------- initialize font bitmap definitions ---------- */
506 for (i = 0; i < NUM_FONTS; i++)
508 if (i < NUM_INITIAL_FONTS)
510 font_bitmap_info[i] = font_initial[i];
514 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
516 int font_bitmap_id = font_info[i].special_bitmap_id[j];
517 int graphic = font_info[i].special_graphic[j];
519 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
520 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
522 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
523 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
526 /* copy font relevant information from graphics information */
527 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
528 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
529 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
530 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
531 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
533 font_bitmap_info[font_bitmap_id].draw_xoffset =
534 graphic_info[graphic].draw_xoffset;
535 font_bitmap_info[font_bitmap_id].draw_yoffset =
536 graphic_info[graphic].draw_yoffset;
538 font_bitmap_info[font_bitmap_id].num_chars =
539 graphic_info[graphic].anim_frames;
540 font_bitmap_info[font_bitmap_id].num_chars_per_line =
541 graphic_info[graphic].anim_frames_per_line;
545 InitFontInfo(font_bitmap_info, num_font_bitmaps,
546 getFontBitmapID, getFontFromToken);
549 void InitGlobalAnimGraphicInfo()
551 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
552 int num_property_mappings = getImageListPropertyMappingSize();
555 if (graphic_info == NULL) /* still at startup phase */
558 /* always start with reliable default values (no global animations) */
559 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
560 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
561 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
562 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
564 /* initialize global animation definitions from static configuration */
565 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
567 int j = GLOBAL_ANIM_ID_PART_BASE;
568 int k = GFX_SPECIAL_ARG_DEFAULT;
570 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
573 /* initialize global animation definitions from dynamic configuration */
574 for (i = 0; i < num_property_mappings; i++)
576 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
577 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
578 int special = property_mapping[i].ext3_index;
579 int graphic = property_mapping[i].artwork_index;
581 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
584 /* set animation part to base part, if not specified */
585 if (!IS_GLOBAL_ANIM_PART(part_nr))
586 part_nr = GLOBAL_ANIM_ID_PART_BASE;
588 /* set animation screen to default, if not specified */
589 if (!IS_SPECIAL_GFX_ARG(special))
590 special = GFX_SPECIAL_ARG_DEFAULT;
592 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
596 printf("::: InitGlobalAnimGraphicInfo\n");
598 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
599 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
600 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
601 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
602 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
603 printf("::: - anim %d, part %d, mode %d => %d\n",
604 i, j, k, global_anim_info[i].graphic[j][k]);
608 void InitGlobalAnimSoundInfo()
610 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
611 int num_property_mappings = getSoundListPropertyMappingSize();
614 /* always start with reliable default values (no global animation sounds) */
615 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
616 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
617 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
618 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
620 /* initialize global animation sound definitions from dynamic configuration */
621 for (i = 0; i < num_property_mappings; i++)
623 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
624 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
625 int special = property_mapping[i].ext3_index;
626 int sound = property_mapping[i].artwork_index;
628 // sound uses control definition; map it to position of graphic (artwork)
629 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
631 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
634 /* set animation part to base part, if not specified */
635 if (!IS_GLOBAL_ANIM_PART(part_nr))
636 part_nr = GLOBAL_ANIM_ID_PART_BASE;
638 /* set animation screen to default, if not specified */
639 if (!IS_SPECIAL_GFX_ARG(special))
640 special = GFX_SPECIAL_ARG_DEFAULT;
642 global_anim_info[anim_nr].sound[part_nr][special] = sound;
646 printf("::: InitGlobalAnimSoundInfo\n");
648 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
649 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
650 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
651 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
652 printf("::: - anim %d, part %d, mode %d => %d\n",
653 i, j, k, global_anim_info[i].sound[j][k]);
657 void InitGlobalAnimMusicInfo()
659 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
660 int num_property_mappings = getMusicListPropertyMappingSize();
663 /* always start with reliable default values (no global animation music) */
664 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
665 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
666 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
667 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
669 /* initialize global animation music definitions from dynamic configuration */
670 for (i = 0; i < num_property_mappings; i++)
672 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
673 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
674 int special = property_mapping[i].ext2_index;
675 int music = property_mapping[i].artwork_index;
677 // music uses control definition; map it to position of graphic (artwork)
678 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
680 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
683 /* set animation part to base part, if not specified */
684 if (!IS_GLOBAL_ANIM_PART(part_nr))
685 part_nr = GLOBAL_ANIM_ID_PART_BASE;
687 /* set animation screen to default, if not specified */
688 if (!IS_SPECIAL_GFX_ARG(special))
689 special = GFX_SPECIAL_ARG_DEFAULT;
691 global_anim_info[anim_nr].music[part_nr][special] = music;
695 printf("::: InitGlobalAnimMusicInfo\n");
697 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
698 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
699 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
700 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
701 printf("::: - anim %d, part %d, mode %d => %d\n",
702 i, j, k, global_anim_info[i].music[j][k]);
706 void InitElementGraphicInfo()
708 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
709 int num_property_mappings = getImageListPropertyMappingSize();
712 if (graphic_info == NULL) /* still at startup phase */
715 /* set values to -1 to identify later as "uninitialized" values */
716 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
718 for (act = 0; act < NUM_ACTIONS; act++)
720 element_info[i].graphic[act] = -1;
721 element_info[i].crumbled[act] = -1;
723 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
725 element_info[i].direction_graphic[act][dir] = -1;
726 element_info[i].direction_crumbled[act][dir] = -1;
733 /* initialize normal element/graphic mapping from static configuration */
734 for (i = 0; element_to_graphic[i].element > -1; i++)
736 int element = element_to_graphic[i].element;
737 int action = element_to_graphic[i].action;
738 int direction = element_to_graphic[i].direction;
739 boolean crumbled = element_to_graphic[i].crumbled;
740 int graphic = element_to_graphic[i].graphic;
741 int base_graphic = el2baseimg(element);
743 if (graphic_info[graphic].bitmap == NULL)
746 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
749 boolean base_redefined =
750 getImageListEntryFromImageID(base_graphic)->redefined;
751 boolean act_dir_redefined =
752 getImageListEntryFromImageID(graphic)->redefined;
754 /* if the base graphic ("emerald", for example) has been redefined,
755 but not the action graphic ("emerald.falling", for example), do not
756 use an existing (in this case considered obsolete) action graphic
757 anymore, but use the automatically determined default graphic */
758 if (base_redefined && !act_dir_redefined)
763 action = ACTION_DEFAULT;
768 element_info[element].direction_crumbled[action][direction] = graphic;
770 element_info[element].crumbled[action] = graphic;
775 element_info[element].direction_graphic[action][direction] = graphic;
777 element_info[element].graphic[action] = graphic;
781 /* initialize normal element/graphic mapping from dynamic configuration */
782 for (i = 0; i < num_property_mappings; i++)
784 int element = property_mapping[i].base_index;
785 int action = property_mapping[i].ext1_index;
786 int direction = property_mapping[i].ext2_index;
787 int special = property_mapping[i].ext3_index;
788 int graphic = property_mapping[i].artwork_index;
789 boolean crumbled = FALSE;
791 if (special == GFX_SPECIAL_ARG_CRUMBLED)
797 if (graphic_info[graphic].bitmap == NULL)
800 if (element >= MAX_NUM_ELEMENTS || special != -1)
804 action = ACTION_DEFAULT;
809 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
810 element_info[element].direction_crumbled[action][dir] = -1;
813 element_info[element].direction_crumbled[action][direction] = graphic;
815 element_info[element].crumbled[action] = graphic;
820 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
821 element_info[element].direction_graphic[action][dir] = -1;
824 element_info[element].direction_graphic[action][direction] = graphic;
826 element_info[element].graphic[action] = graphic;
830 /* now copy all graphics that are defined to be cloned from other graphics */
831 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
833 int graphic = element_info[i].graphic[ACTION_DEFAULT];
834 int crumbled_like, diggable_like;
839 crumbled_like = graphic_info[graphic].crumbled_like;
840 diggable_like = graphic_info[graphic].diggable_like;
842 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
844 for (act = 0; act < NUM_ACTIONS; act++)
845 element_info[i].crumbled[act] =
846 element_info[crumbled_like].crumbled[act];
847 for (act = 0; act < NUM_ACTIONS; act++)
848 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
849 element_info[i].direction_crumbled[act][dir] =
850 element_info[crumbled_like].direction_crumbled[act][dir];
853 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
855 element_info[i].graphic[ACTION_DIGGING] =
856 element_info[diggable_like].graphic[ACTION_DIGGING];
857 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
858 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
859 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
863 /* set hardcoded definitions for some runtime elements without graphic */
864 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
866 /* set hardcoded definitions for some internal elements without graphic */
867 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
869 if (IS_EDITOR_CASCADE_INACTIVE(i))
870 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
871 else if (IS_EDITOR_CASCADE_ACTIVE(i))
872 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
875 /* now set all undefined/invalid graphics to -1 to set to default after it */
876 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
878 for (act = 0; act < NUM_ACTIONS; act++)
882 graphic = element_info[i].graphic[act];
883 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
884 element_info[i].graphic[act] = -1;
886 graphic = element_info[i].crumbled[act];
887 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
888 element_info[i].crumbled[act] = -1;
890 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
892 graphic = element_info[i].direction_graphic[act][dir];
893 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
894 element_info[i].direction_graphic[act][dir] = -1;
896 graphic = element_info[i].direction_crumbled[act][dir];
897 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
898 element_info[i].direction_crumbled[act][dir] = -1;
905 /* adjust graphics with 2nd tile for movement according to direction
906 (do this before correcting '-1' values to minimize calculations) */
907 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
909 for (act = 0; act < NUM_ACTIONS; act++)
911 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
913 int graphic = element_info[i].direction_graphic[act][dir];
914 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
916 if (act == ACTION_FALLING) /* special case */
917 graphic = element_info[i].graphic[act];
920 graphic_info[graphic].double_movement &&
921 graphic_info[graphic].swap_double_tiles != 0)
923 struct GraphicInfo *g = &graphic_info[graphic];
924 int src_x_front = g->src_x;
925 int src_y_front = g->src_y;
926 int src_x_back = g->src_x + g->offset2_x;
927 int src_y_back = g->src_y + g->offset2_y;
928 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
930 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
931 src_y_front < src_y_back);
932 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
933 boolean swap_movement_tiles_autodetected =
934 (!frames_are_ordered_diagonally &&
935 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
936 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
937 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
938 (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 getFixedGraphicSourceExt(graphic, 0, &dummy,
946 &src_x_back, &src_y_back, TRUE);
948 /* set frontside tile coordinates to backside tile coordinates */
949 g->src_x = src_x_back;
950 g->src_y = src_y_back;
952 /* invert tile offset to point to new backside tile coordinates */
956 /* do not swap front and backside tiles again after correction */
957 g->swap_double_tiles = 0;
966 /* now set all '-1' values to element specific default values */
967 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
969 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
970 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
971 int default_direction_graphic[NUM_DIRECTIONS_FULL];
972 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
974 if (default_graphic == -1)
975 default_graphic = IMG_UNKNOWN;
977 if (default_crumbled == -1)
978 default_crumbled = default_graphic;
980 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
982 default_direction_graphic[dir] =
983 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
984 default_direction_crumbled[dir] =
985 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
987 if (default_direction_graphic[dir] == -1)
988 default_direction_graphic[dir] = default_graphic;
990 if (default_direction_crumbled[dir] == -1)
991 default_direction_crumbled[dir] = default_direction_graphic[dir];
994 for (act = 0; act < NUM_ACTIONS; act++)
996 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
997 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
998 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
999 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1000 act == ACTION_TURNING_FROM_RIGHT ||
1001 act == ACTION_TURNING_FROM_UP ||
1002 act == ACTION_TURNING_FROM_DOWN);
1004 /* generic default action graphic (defined by "[default]" directive) */
1005 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1006 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1007 int default_remove_graphic = IMG_EMPTY;
1009 if (act_remove && default_action_graphic != -1)
1010 default_remove_graphic = default_action_graphic;
1012 /* look for special default action graphic (classic game specific) */
1013 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1014 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1015 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1016 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1017 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1018 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1020 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1021 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1022 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1023 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1024 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1025 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1027 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1028 /* !!! make this better !!! */
1029 if (i == EL_EMPTY_SPACE)
1031 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1032 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1035 if (default_action_graphic == -1)
1036 default_action_graphic = default_graphic;
1038 if (default_action_crumbled == -1)
1039 default_action_crumbled = default_action_graphic;
1041 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1043 /* use action graphic as the default direction graphic, if undefined */
1044 int default_action_direction_graphic = element_info[i].graphic[act];
1045 int default_action_direction_crumbled = element_info[i].crumbled[act];
1047 /* no graphic for current action -- use default direction graphic */
1048 if (default_action_direction_graphic == -1)
1049 default_action_direction_graphic =
1050 (act_remove ? default_remove_graphic :
1052 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1053 default_action_graphic != default_graphic ?
1054 default_action_graphic :
1055 default_direction_graphic[dir]);
1057 if (element_info[i].direction_graphic[act][dir] == -1)
1058 element_info[i].direction_graphic[act][dir] =
1059 default_action_direction_graphic;
1061 if (default_action_direction_crumbled == -1)
1062 default_action_direction_crumbled =
1063 element_info[i].direction_graphic[act][dir];
1065 if (element_info[i].direction_crumbled[act][dir] == -1)
1066 element_info[i].direction_crumbled[act][dir] =
1067 default_action_direction_crumbled;
1070 /* no graphic for this specific action -- use default action graphic */
1071 if (element_info[i].graphic[act] == -1)
1072 element_info[i].graphic[act] =
1073 (act_remove ? default_remove_graphic :
1074 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1075 default_action_graphic);
1077 if (element_info[i].crumbled[act] == -1)
1078 element_info[i].crumbled[act] = element_info[i].graphic[act];
1082 UPDATE_BUSY_STATE();
1085 void InitElementSpecialGraphicInfo()
1087 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1088 int num_property_mappings = getImageListPropertyMappingSize();
1091 /* always start with reliable default values */
1092 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1093 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1094 element_info[i].special_graphic[j] =
1095 element_info[i].graphic[ACTION_DEFAULT];
1097 /* initialize special element/graphic mapping from static configuration */
1098 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1100 int element = element_to_special_graphic[i].element;
1101 int special = element_to_special_graphic[i].special;
1102 int graphic = element_to_special_graphic[i].graphic;
1103 int base_graphic = el2baseimg(element);
1104 boolean base_redefined =
1105 getImageListEntryFromImageID(base_graphic)->redefined;
1106 boolean special_redefined =
1107 getImageListEntryFromImageID(graphic)->redefined;
1109 /* if the base graphic ("emerald", for example) has been redefined,
1110 but not the special graphic ("emerald.EDITOR", for example), do not
1111 use an existing (in this case considered obsolete) special graphic
1112 anymore, but use the automatically created (down-scaled) graphic */
1113 if (base_redefined && !special_redefined)
1116 element_info[element].special_graphic[special] = graphic;
1119 /* initialize special element/graphic mapping from dynamic configuration */
1120 for (i = 0; i < num_property_mappings; i++)
1122 int element = property_mapping[i].base_index;
1123 int action = property_mapping[i].ext1_index;
1124 int direction = property_mapping[i].ext2_index;
1125 int special = property_mapping[i].ext3_index;
1126 int graphic = property_mapping[i].artwork_index;
1128 /* for action ".active", replace element with active element, if exists */
1129 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1131 element = ELEMENT_ACTIVE(element);
1135 if (element >= MAX_NUM_ELEMENTS)
1138 /* do not change special graphic if action or direction was specified */
1139 if (action != -1 || direction != -1)
1142 if (IS_SPECIAL_GFX_ARG(special))
1143 element_info[element].special_graphic[special] = graphic;
1146 /* now set all undefined/invalid graphics to default */
1147 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1148 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1149 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1150 element_info[i].special_graphic[j] =
1151 element_info[i].graphic[ACTION_DEFAULT];
1154 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1156 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1157 return get_parameter_value(value_raw, suffix, type);
1159 if (strEqual(value_raw, ARG_UNDEFINED))
1160 return ARG_UNDEFINED_VALUE;
1162 if (type == TYPE_ELEMENT)
1164 char *value = getHashEntry(element_token_hash, value_raw);
1168 Error(ERR_INFO_LINE, "-");
1169 Error(ERR_INFO, "warning: error found in config file:");
1170 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1171 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1172 Error(ERR_INFO, "custom graphic rejected for this element/action");
1173 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1174 Error(ERR_INFO_LINE, "-");
1177 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1179 else if (type == TYPE_GRAPHIC)
1181 char *value = getHashEntry(graphic_token_hash, value_raw);
1182 int fallback_graphic = IMG_CHAR_EXCLAM;
1186 Error(ERR_INFO_LINE, "-");
1187 Error(ERR_INFO, "warning: error found in config file:");
1188 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1189 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1190 Error(ERR_INFO, "custom graphic rejected for this element/action");
1191 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1192 Error(ERR_INFO_LINE, "-");
1195 return (value != NULL ? atoi(value) : fallback_graphic);
1201 static int get_scaled_graphic_width(int graphic)
1203 int original_width = getOriginalImageWidthFromImageID(graphic);
1204 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1206 return original_width * scale_up_factor;
1209 static int get_scaled_graphic_height(int graphic)
1211 int original_height = getOriginalImageHeightFromImageID(graphic);
1212 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1214 return original_height * scale_up_factor;
1217 static void set_graphic_parameters_ext(int graphic, int *parameter,
1218 Bitmap **src_bitmaps)
1220 struct GraphicInfo *g = &graphic_info[graphic];
1221 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1222 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1223 int anim_frames_per_line = 1;
1225 /* always start with reliable default values */
1226 g->src_image_width = 0;
1227 g->src_image_height = 0;
1230 g->width = TILEX; /* default for element graphics */
1231 g->height = TILEY; /* default for element graphics */
1232 g->offset_x = 0; /* one or both of these values ... */
1233 g->offset_y = 0; /* ... will be corrected later */
1234 g->offset2_x = 0; /* one or both of these values ... */
1235 g->offset2_y = 0; /* ... will be corrected later */
1236 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1237 g->crumbled_like = -1; /* do not use clone element */
1238 g->diggable_like = -1; /* do not use clone element */
1239 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1240 g->scale_up_factor = 1; /* default: no scaling up */
1241 g->tile_size = TILESIZE; /* default: standard tile size */
1242 g->clone_from = -1; /* do not use clone graphic */
1243 g->init_delay_fixed = 0;
1244 g->init_delay_random = 0;
1245 g->anim_delay_fixed = 0;
1246 g->anim_delay_random = 0;
1247 g->post_delay_fixed = 0;
1248 g->post_delay_random = 0;
1250 g->fade_mode = FADE_MODE_DEFAULT;
1254 g->align = ALIGN_CENTER; /* default for title screens */
1255 g->valign = VALIGN_MIDDLE; /* default for title screens */
1256 g->sort_priority = 0; /* default for title screens */
1258 g->style = STYLE_DEFAULT;
1260 g->bitmaps = src_bitmaps;
1261 g->bitmap = src_bitmap;
1263 /* optional zoom factor for scaling up the image to a larger size */
1264 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1265 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1266 if (g->scale_up_factor < 1)
1267 g->scale_up_factor = 1; /* no scaling */
1269 /* optional tile size for using non-standard image size */
1270 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1272 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1275 // CHECK: should tile sizes less than standard tile size be allowed?
1276 if (g->tile_size < TILESIZE)
1277 g->tile_size = TILESIZE; /* standard tile size */
1280 // when setting tile size, also set width and height accordingly
1281 g->width = g->tile_size;
1282 g->height = g->tile_size;
1285 if (g->use_image_size)
1287 /* set new default bitmap size (with scaling, but without small images) */
1288 g->width = get_scaled_graphic_width(graphic);
1289 g->height = get_scaled_graphic_height(graphic);
1292 /* optional width and height of each animation frame */
1293 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1294 g->width = parameter[GFX_ARG_WIDTH];
1295 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1296 g->height = parameter[GFX_ARG_HEIGHT];
1298 /* optional x and y tile position of animation frame sequence */
1299 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1300 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1301 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1302 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1304 /* optional x and y pixel position of animation frame sequence */
1305 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1306 g->src_x = parameter[GFX_ARG_X];
1307 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1308 g->src_y = parameter[GFX_ARG_Y];
1314 Error(ERR_INFO_LINE, "-");
1315 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1316 g->width, getTokenFromImageID(graphic), TILEX);
1317 Error(ERR_INFO_LINE, "-");
1319 g->width = TILEX; /* will be checked to be inside bitmap later */
1324 Error(ERR_INFO_LINE, "-");
1325 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1326 g->height, getTokenFromImageID(graphic), TILEY);
1327 Error(ERR_INFO_LINE, "-");
1329 g->height = TILEY; /* will be checked to be inside bitmap later */
1335 /* get final bitmap size (with scaling, but without small images) */
1336 int src_image_width = get_scaled_graphic_width(graphic);
1337 int src_image_height = get_scaled_graphic_height(graphic);
1339 if (src_image_width == 0 || src_image_height == 0)
1341 /* only happens when loaded outside artwork system (like "global.busy") */
1342 src_image_width = src_bitmap->width;
1343 src_image_height = src_bitmap->height;
1346 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1348 anim_frames_per_row = src_image_width / g->tile_size;
1349 anim_frames_per_col = src_image_height / g->tile_size;
1353 anim_frames_per_row = src_image_width / g->width;
1354 anim_frames_per_col = src_image_height / g->height;
1357 g->src_image_width = src_image_width;
1358 g->src_image_height = src_image_height;
1361 /* correct x or y offset dependent of vertical or horizontal frame order */
1362 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1364 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1365 parameter[GFX_ARG_OFFSET] : g->height);
1366 anim_frames_per_line = anim_frames_per_col;
1368 else /* frames are ordered horizontally */
1370 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1371 parameter[GFX_ARG_OFFSET] : g->width);
1372 anim_frames_per_line = anim_frames_per_row;
1375 /* optionally, the x and y offset of frames can be specified directly */
1376 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1377 g->offset_x = parameter[GFX_ARG_XOFFSET];
1378 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1379 g->offset_y = parameter[GFX_ARG_YOFFSET];
1381 /* optionally, moving animations may have separate start and end graphics */
1382 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1384 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1385 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1387 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1388 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1389 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1390 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1391 else /* frames are ordered horizontally */
1392 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1393 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1395 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1396 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1397 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1398 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1399 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1401 /* optionally, the second movement tile can be specified as start tile */
1402 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1403 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1405 /* automatically determine correct number of frames, if not defined */
1406 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1407 g->anim_frames = parameter[GFX_ARG_FRAMES];
1408 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1409 g->anim_frames = anim_frames_per_row;
1410 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1411 g->anim_frames = anim_frames_per_col;
1415 if (g->anim_frames == 0) /* frames must be at least 1 */
1418 g->anim_frames_per_line =
1419 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1420 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1422 g->anim_delay = parameter[GFX_ARG_DELAY];
1423 if (g->anim_delay == 0) /* delay must be at least 1 */
1426 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1428 /* automatically determine correct start frame, if not defined */
1429 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1430 g->anim_start_frame = 0;
1431 else if (g->anim_mode & ANIM_REVERSE)
1432 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1434 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1436 /* animation synchronized with global frame counter, not move position */
1437 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1439 /* optional element for cloning crumble graphics */
1440 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1441 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1443 /* optional element for cloning digging graphics */
1444 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1445 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1447 /* optional border size for "crumbling" diggable graphics */
1448 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1449 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1451 /* used for global animations and player "boring" and "sleeping" actions */
1452 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1453 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1454 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1455 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1456 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1457 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1458 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1459 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1460 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1461 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1462 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1463 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1465 /* used for toon animations and global animations */
1466 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1467 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1468 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1469 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1470 g->direction = parameter[GFX_ARG_DIRECTION];
1471 g->position = parameter[GFX_ARG_POSITION];
1472 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1473 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1475 /* this is only used for drawing font characters */
1476 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1477 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1479 /* this is only used for drawing envelope graphics */
1480 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1482 /* used for toon animations and global animations */
1483 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1484 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1486 /* optional graphic for cloning all graphics settings */
1487 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1488 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1490 /* optional settings for drawing title screens and title messages */
1491 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1492 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1493 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1494 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1495 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1496 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1497 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1498 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1499 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1500 g->align = parameter[GFX_ARG_ALIGN];
1501 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1502 g->valign = parameter[GFX_ARG_VALIGN];
1503 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1504 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1506 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1507 g->class = parameter[GFX_ARG_CLASS];
1508 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1509 g->style = parameter[GFX_ARG_STYLE];
1511 /* this is only used for drawing menu buttons and text */
1512 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1513 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1514 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1515 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1518 static void set_graphic_parameters(int graphic)
1520 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1521 char **parameter_raw = image->parameter;
1522 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1523 int parameter[NUM_GFX_ARGS];
1526 /* if fallback to default artwork is done, also use the default parameters */
1527 if (image->fallback_to_default)
1528 parameter_raw = image->default_parameter;
1530 /* get integer values from string parameters */
1531 for (i = 0; i < NUM_GFX_ARGS; i++)
1532 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1533 image_config_suffix[i].token,
1534 image_config_suffix[i].type);
1536 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1538 UPDATE_BUSY_STATE();
1541 static void set_cloned_graphic_parameters(int graphic)
1543 int fallback_graphic = IMG_CHAR_EXCLAM;
1544 int max_num_images = getImageListSize();
1545 int clone_graphic = graphic_info[graphic].clone_from;
1546 int num_references_followed = 1;
1548 while (graphic_info[clone_graphic].clone_from != -1 &&
1549 num_references_followed < max_num_images)
1551 clone_graphic = graphic_info[clone_graphic].clone_from;
1553 num_references_followed++;
1556 if (num_references_followed >= max_num_images)
1558 Error(ERR_INFO_LINE, "-");
1559 Error(ERR_INFO, "warning: error found in config file:");
1560 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1561 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1562 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1563 Error(ERR_INFO, "custom graphic rejected for this element/action");
1565 if (graphic == fallback_graphic)
1566 Error(ERR_EXIT, "no fallback graphic available");
1568 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1569 Error(ERR_INFO_LINE, "-");
1571 graphic_info[graphic] = graphic_info[fallback_graphic];
1575 graphic_info[graphic] = graphic_info[clone_graphic];
1576 graphic_info[graphic].clone_from = clone_graphic;
1580 static void InitGraphicInfo()
1582 int fallback_graphic = IMG_CHAR_EXCLAM;
1583 int num_images = getImageListSize();
1586 /* use image size as default values for width and height for these images */
1587 static int full_size_graphics[] =
1590 IMG_GLOBAL_BORDER_MAIN,
1591 IMG_GLOBAL_BORDER_SCORES,
1592 IMG_GLOBAL_BORDER_EDITOR,
1593 IMG_GLOBAL_BORDER_PLAYING,
1596 IMG_BACKGROUND_ENVELOPE_1,
1597 IMG_BACKGROUND_ENVELOPE_2,
1598 IMG_BACKGROUND_ENVELOPE_3,
1599 IMG_BACKGROUND_ENVELOPE_4,
1600 IMG_BACKGROUND_REQUEST,
1603 IMG_BACKGROUND_TITLE_INITIAL,
1604 IMG_BACKGROUND_TITLE,
1605 IMG_BACKGROUND_MAIN,
1606 IMG_BACKGROUND_LEVELS,
1607 IMG_BACKGROUND_LEVELNR,
1608 IMG_BACKGROUND_SCORES,
1609 IMG_BACKGROUND_EDITOR,
1610 IMG_BACKGROUND_INFO,
1611 IMG_BACKGROUND_INFO_ELEMENTS,
1612 IMG_BACKGROUND_INFO_MUSIC,
1613 IMG_BACKGROUND_INFO_CREDITS,
1614 IMG_BACKGROUND_INFO_PROGRAM,
1615 IMG_BACKGROUND_INFO_VERSION,
1616 IMG_BACKGROUND_INFO_LEVELSET,
1617 IMG_BACKGROUND_SETUP,
1618 IMG_BACKGROUND_PLAYING,
1619 IMG_BACKGROUND_DOOR,
1620 IMG_BACKGROUND_TAPE,
1621 IMG_BACKGROUND_PANEL,
1622 IMG_BACKGROUND_PALETTE,
1623 IMG_BACKGROUND_TOOLBOX,
1625 IMG_TITLESCREEN_INITIAL_1,
1626 IMG_TITLESCREEN_INITIAL_2,
1627 IMG_TITLESCREEN_INITIAL_3,
1628 IMG_TITLESCREEN_INITIAL_4,
1629 IMG_TITLESCREEN_INITIAL_5,
1636 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1637 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1638 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1639 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1640 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1641 IMG_BACKGROUND_TITLEMESSAGE_1,
1642 IMG_BACKGROUND_TITLEMESSAGE_2,
1643 IMG_BACKGROUND_TITLEMESSAGE_3,
1644 IMG_BACKGROUND_TITLEMESSAGE_4,
1645 IMG_BACKGROUND_TITLEMESSAGE_5,
1650 checked_free(graphic_info);
1652 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1654 /* initialize "use_image_size" flag with default value */
1655 for (i = 0; i < num_images; i++)
1656 graphic_info[i].use_image_size = FALSE;
1658 /* initialize "use_image_size" flag from static configuration above */
1659 for (i = 0; full_size_graphics[i] != -1; i++)
1660 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1662 /* first set all graphic paramaters ... */
1663 for (i = 0; i < num_images; i++)
1664 set_graphic_parameters(i);
1666 /* ... then copy these parameters for cloned graphics */
1667 for (i = 0; i < num_images; i++)
1668 if (graphic_info[i].clone_from != -1)
1669 set_cloned_graphic_parameters(i);
1671 for (i = 0; i < num_images; i++)
1676 int first_frame, last_frame;
1677 int src_bitmap_width, src_bitmap_height;
1679 /* now check if no animation frames are outside of the loaded image */
1681 if (graphic_info[i].bitmap == NULL)
1682 continue; /* skip check for optional images that are undefined */
1684 /* get image size (this can differ from the standard element tile size!) */
1685 width = graphic_info[i].width;
1686 height = graphic_info[i].height;
1688 /* get final bitmap size (with scaling, but without small images) */
1689 src_bitmap_width = graphic_info[i].src_image_width;
1690 src_bitmap_height = graphic_info[i].src_image_height;
1692 /* check if first animation frame is inside specified bitmap */
1695 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1697 /* this avoids calculating wrong start position for out-of-bounds frame */
1698 src_x = graphic_info[i].src_x;
1699 src_y = graphic_info[i].src_y;
1701 if (src_x < 0 || src_y < 0 ||
1702 src_x + width > src_bitmap_width ||
1703 src_y + height > src_bitmap_height)
1705 Error(ERR_INFO_LINE, "-");
1706 Error(ERR_INFO, "warning: error found in config file:");
1707 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1708 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1709 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1711 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1712 src_x, src_y, src_bitmap_width, src_bitmap_height);
1713 Error(ERR_INFO, "custom graphic rejected for this element/action");
1715 if (i == fallback_graphic)
1716 Error(ERR_EXIT, "no fallback graphic available");
1718 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1719 Error(ERR_INFO_LINE, "-");
1721 graphic_info[i] = graphic_info[fallback_graphic];
1724 /* check if last animation frame is inside specified bitmap */
1726 last_frame = graphic_info[i].anim_frames - 1;
1727 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1729 if (src_x < 0 || src_y < 0 ||
1730 src_x + width > src_bitmap_width ||
1731 src_y + height > src_bitmap_height)
1733 Error(ERR_INFO_LINE, "-");
1734 Error(ERR_INFO, "warning: error found in config file:");
1735 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1736 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1737 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1739 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1740 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1741 Error(ERR_INFO, "::: %d, %d", width, height);
1742 Error(ERR_INFO, "custom graphic rejected for this element/action");
1744 if (i == fallback_graphic)
1745 Error(ERR_EXIT, "no fallback graphic available");
1747 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1748 Error(ERR_INFO_LINE, "-");
1750 graphic_info[i] = graphic_info[fallback_graphic];
1755 static void InitGraphicCompatibilityInfo()
1757 struct FileInfo *fi_global_door =
1758 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1759 int num_images = getImageListSize();
1762 /* the following compatibility handling is needed for the following case:
1763 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1764 graphics mainly used for door and panel graphics, like editor, tape and
1765 in-game buttons with hard-coded bitmap positions and button sizes; as
1766 these graphics now have individual definitions, redefining "global.door"
1767 to change all these graphics at once like before does not work anymore
1768 (because all those individual definitions still have their default values);
1769 to solve this, remap all those individual definitions that are not
1770 redefined to the new bitmap of "global.door" if it was redefined */
1772 /* special compatibility handling if image "global.door" was redefined */
1773 if (fi_global_door->redefined)
1775 for (i = 0; i < num_images; i++)
1777 struct FileInfo *fi = getImageListEntryFromImageID(i);
1779 /* process only those images that still use the default settings */
1782 /* process all images which default to same image as "global.door" */
1783 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1785 // printf("::: special treatment needed for token '%s'\n", fi->token);
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 */