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 "))
4909 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4911 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4912 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4913 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4915 while (*str_ptr != '\0') /* continue parsing string */
4917 /* cut leading whitespace from string, replace it by string terminator */
4918 while (*str_ptr == ' ' || *str_ptr == '\t')
4921 if (*str_ptr == '\0') /* end of string reached */
4924 if (global.autoplay_leveldir == NULL) /* read level set string */
4926 global.autoplay_leveldir = str_ptr;
4927 global.autoplay_all = TRUE; /* default: play all tapes */
4929 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4930 global.autoplay_level[i] = FALSE;
4932 else /* read level number string */
4934 int level_nr = atoi(str_ptr); /* get level_nr value */
4936 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4937 global.autoplay_level[level_nr] = TRUE;
4939 global.autoplay_all = FALSE;
4942 /* advance string pointer to the next whitespace (or end of string) */
4943 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4947 else if (strPrefix(command, "convert "))
4949 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4950 char *str_ptr = strchr(str_copy, ' ');
4952 global.convert_leveldir = str_copy;
4953 global.convert_level_nr = -1;
4955 if (str_ptr != NULL) /* level number follows */
4957 *str_ptr++ = '\0'; /* terminate leveldir string */
4958 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4961 else if (strPrefix(command, "create images "))
4963 global.create_images_dir = getStringCopy(&command[14]);
4965 if (access(global.create_images_dir, W_OK) != 0)
4966 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4967 global.create_images_dir);
4969 else if (strPrefix(command, "create CE image "))
4971 CreateCustomElementImages(&command[16]);
4977 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4981 static void InitSetup()
4983 LoadSetup(); /* global setup info */
4985 /* set some options from setup file */
4987 if (setup.options.verbose)
4988 options.verbose = TRUE;
4991 static void InitGameInfo()
4993 game.restart_level = FALSE;
4996 static void InitPlayerInfo()
5000 /* choose default local player */
5001 local_player = &stored_player[0];
5003 for (i = 0; i < MAX_PLAYERS; i++)
5004 stored_player[i].connected = FALSE;
5006 local_player->connected = TRUE;
5009 static void InitArtworkInfo()
5014 static char *get_string_in_brackets(char *string)
5016 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5018 sprintf(string_in_brackets, "[%s]", string);
5020 return string_in_brackets;
5023 static char *get_level_id_suffix(int id_nr)
5025 char *id_suffix = checked_malloc(1 + 3 + 1);
5027 if (id_nr < 0 || id_nr > 999)
5030 sprintf(id_suffix, ".%03d", id_nr);
5035 static void InitArtworkConfig()
5037 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5039 NUM_GLOBAL_ANIM_TOKENS + 1];
5040 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5041 NUM_GLOBAL_ANIM_TOKENS + 1];
5042 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5043 NUM_GLOBAL_ANIM_TOKENS + 1];
5044 static char *action_id_suffix[NUM_ACTIONS + 1];
5045 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5046 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5047 static char *level_id_suffix[MAX_LEVELS + 1];
5048 static char *dummy[1] = { NULL };
5049 static char *ignore_generic_tokens[] =
5055 static char **ignore_image_tokens;
5056 static char **ignore_sound_tokens;
5057 static char **ignore_music_tokens;
5058 int num_ignore_generic_tokens;
5059 int num_ignore_image_tokens;
5060 int num_ignore_sound_tokens;
5061 int num_ignore_music_tokens;
5064 /* dynamically determine list of generic tokens to be ignored */
5065 num_ignore_generic_tokens = 0;
5066 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5067 num_ignore_generic_tokens++;
5069 /* dynamically determine list of image tokens to be ignored */
5070 num_ignore_image_tokens = num_ignore_generic_tokens;
5071 for (i = 0; image_config_vars[i].token != NULL; i++)
5072 num_ignore_image_tokens++;
5073 ignore_image_tokens =
5074 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5075 for (i = 0; i < num_ignore_generic_tokens; i++)
5076 ignore_image_tokens[i] = ignore_generic_tokens[i];
5077 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5078 ignore_image_tokens[num_ignore_generic_tokens + i] =
5079 image_config_vars[i].token;
5080 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5082 /* dynamically determine list of sound tokens to be ignored */
5083 num_ignore_sound_tokens = num_ignore_generic_tokens;
5084 ignore_sound_tokens =
5085 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5086 for (i = 0; i < num_ignore_generic_tokens; i++)
5087 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5088 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5090 /* dynamically determine list of music tokens to be ignored */
5091 num_ignore_music_tokens = num_ignore_generic_tokens;
5092 ignore_music_tokens =
5093 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5094 for (i = 0; i < num_ignore_generic_tokens; i++)
5095 ignore_music_tokens[i] = ignore_generic_tokens[i];
5096 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5098 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5099 image_id_prefix[i] = element_info[i].token_name;
5100 for (i = 0; i < NUM_FONTS; i++)
5101 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5102 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5103 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5104 global_anim_info[i].token_name;
5105 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5107 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5108 sound_id_prefix[i] = element_info[i].token_name;
5109 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5110 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5111 get_string_in_brackets(element_info[i].class_name);
5112 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5113 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5114 global_anim_info[i].token_name;
5115 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5117 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5118 music_id_prefix[i] = music_prefix_info[i].prefix;
5119 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5120 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5121 global_anim_info[i].token_name;
5122 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5124 for (i = 0; i < NUM_ACTIONS; i++)
5125 action_id_suffix[i] = element_action_info[i].suffix;
5126 action_id_suffix[NUM_ACTIONS] = NULL;
5128 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5129 direction_id_suffix[i] = element_direction_info[i].suffix;
5130 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5132 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5133 special_id_suffix[i] = special_suffix_info[i].suffix;
5134 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5136 for (i = 0; i < MAX_LEVELS; i++)
5137 level_id_suffix[i] = get_level_id_suffix(i);
5138 level_id_suffix[MAX_LEVELS] = NULL;
5140 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5141 image_id_prefix, action_id_suffix, direction_id_suffix,
5142 special_id_suffix, ignore_image_tokens);
5143 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5144 sound_id_prefix, action_id_suffix, dummy,
5145 special_id_suffix, ignore_sound_tokens);
5146 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5147 music_id_prefix, action_id_suffix, special_id_suffix,
5148 level_id_suffix, ignore_music_tokens);
5151 static void InitMixer()
5158 void InitGfxBuffers()
5160 static int win_xsize_last = -1;
5161 static int win_ysize_last = -1;
5163 /* create additional image buffers for double-buffering and cross-fading */
5165 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5167 /* used to temporarily store the backbuffer -- only re-create if changed */
5168 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5169 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5171 win_xsize_last = WIN_XSIZE;
5172 win_ysize_last = WIN_YSIZE;
5175 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5176 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5177 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5178 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5180 /* initialize screen properties */
5181 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5182 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5184 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5185 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5186 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5187 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5188 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5189 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5191 /* required if door size definitions have changed */
5192 InitGraphicCompatibilityInfo_Doors();
5194 InitGfxBuffers_EM();
5195 InitGfxBuffers_SP();
5200 struct GraphicInfo *graphic_info_last = graphic_info;
5201 char *filename_font_initial = NULL;
5202 char *filename_anim_initial = NULL;
5203 Bitmap *bitmap_font_initial = NULL;
5207 /* determine settings for initial font (for displaying startup messages) */
5208 for (i = 0; image_config[i].token != NULL; i++)
5210 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5212 char font_token[128];
5215 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5216 len_font_token = strlen(font_token);
5218 if (strEqual(image_config[i].token, font_token))
5219 filename_font_initial = image_config[i].value;
5220 else if (strlen(image_config[i].token) > len_font_token &&
5221 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5223 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5224 font_initial[j].src_x = atoi(image_config[i].value);
5225 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5226 font_initial[j].src_y = atoi(image_config[i].value);
5227 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5228 font_initial[j].width = atoi(image_config[i].value);
5229 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5230 font_initial[j].height = atoi(image_config[i].value);
5235 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5237 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5238 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5241 if (filename_font_initial == NULL) /* should not happen */
5242 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5245 InitGfxCustomArtworkInfo();
5246 InitGfxOtherSettings();
5248 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5250 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5251 font_initial[j].bitmap = bitmap_font_initial;
5253 InitFontGraphicInfo();
5255 font_height = getFontHeight(FC_RED);
5257 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5258 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5259 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5262 DrawInitText("Loading graphics", 120, FC_GREEN);
5264 /* initialize settings for busy animation with default values */
5265 int parameter[NUM_GFX_ARGS];
5266 for (i = 0; i < NUM_GFX_ARGS; i++)
5267 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5268 image_config_suffix[i].token,
5269 image_config_suffix[i].type);
5271 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5272 int len_anim_token = strlen(anim_token);
5274 /* read settings for busy animation from default custom artwork config */
5275 char *gfx_config_filename = getPath3(options.graphics_directory,
5277 GRAPHICSINFO_FILENAME);
5279 if (fileExists(gfx_config_filename))
5281 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5283 if (setup_file_hash)
5285 char *filename = getHashEntry(setup_file_hash, anim_token);
5289 filename_anim_initial = getStringCopy(filename);
5291 for (j = 0; image_config_suffix[j].token != NULL; j++)
5293 int type = image_config_suffix[j].type;
5294 char *suffix = image_config_suffix[j].token;
5295 char *token = getStringCat2(anim_token, suffix);
5296 char *value = getHashEntry(setup_file_hash, token);
5298 checked_free(token);
5301 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5305 freeSetupFileHash(setup_file_hash);
5309 if (filename_anim_initial == NULL)
5311 /* read settings for busy animation from static default artwork config */
5312 for (i = 0; image_config[i].token != NULL; i++)
5314 if (strEqual(image_config[i].token, anim_token))
5315 filename_anim_initial = getStringCopy(image_config[i].value);
5316 else if (strlen(image_config[i].token) > len_anim_token &&
5317 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5319 for (j = 0; image_config_suffix[j].token != NULL; j++)
5321 if (strEqual(&image_config[i].token[len_anim_token],
5322 image_config_suffix[j].token))
5324 get_graphic_parameter_value(image_config[i].value,
5325 image_config_suffix[j].token,
5326 image_config_suffix[j].type);
5332 if (filename_anim_initial == NULL) /* should not happen */
5333 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5335 anim_initial.bitmaps =
5336 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5338 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5339 LoadCustomImage(filename_anim_initial);
5341 checked_free(filename_anim_initial);
5343 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5345 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5347 graphic_info = graphic_info_last;
5349 init.busy.width = anim_initial.width;
5350 init.busy.height = anim_initial.height;
5352 InitMenuDesignSettings_Static();
5354 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5355 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5356 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5358 gfx.fade_border_source_status = global.border_status;
5359 gfx.fade_border_target_status = global.border_status;
5360 gfx.masked_border_bitmap_ptr = backbuffer;
5362 /* use copy of busy animation to prevent change while reloading artwork */
5366 void InitGfxBackground()
5368 fieldbuffer = bitmap_db_field;
5369 SetDrawtoField(DRAW_TO_BACKBUFFER);
5371 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5373 redraw_mask = REDRAW_ALL;
5376 static void InitLevelInfo()
5378 LoadLevelInfo(); /* global level info */
5379 LoadLevelSetup_LastSeries(); /* last played series info */
5380 LoadLevelSetup_SeriesInfo(); /* last played level info */
5382 if (global.autoplay_leveldir &&
5383 global.autoplay_mode != AUTOPLAY_TEST)
5385 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5386 global.autoplay_leveldir);
5387 if (leveldir_current == NULL)
5388 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5392 static void InitLevelArtworkInfo()
5394 LoadLevelArtworkInfo();
5397 static void InitImages()
5399 print_timestamp_init("InitImages");
5402 printf("::: leveldir_current->identifier == '%s'\n",
5403 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5404 printf("::: leveldir_current->graphics_path == '%s'\n",
5405 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5406 printf("::: leveldir_current->graphics_set == '%s'\n",
5407 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5408 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5409 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5412 setLevelArtworkDir(artwork.gfx_first);
5415 printf("::: leveldir_current->identifier == '%s'\n",
5416 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5417 printf("::: leveldir_current->graphics_path == '%s'\n",
5418 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5419 printf("::: leveldir_current->graphics_set == '%s'\n",
5420 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5421 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5422 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5426 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5427 leveldir_current->identifier,
5428 artwork.gfx_current_identifier,
5429 artwork.gfx_current->identifier,
5430 leveldir_current->graphics_set,
5431 leveldir_current->graphics_path);
5434 UPDATE_BUSY_STATE();
5436 ReloadCustomImages();
5437 print_timestamp_time("ReloadCustomImages");
5439 UPDATE_BUSY_STATE();
5441 LoadCustomElementDescriptions();
5442 print_timestamp_time("LoadCustomElementDescriptions");
5444 UPDATE_BUSY_STATE();
5446 LoadMenuDesignSettings();
5447 print_timestamp_time("LoadMenuDesignSettings");
5449 UPDATE_BUSY_STATE();
5451 ReinitializeGraphics();
5452 print_timestamp_time("ReinitializeGraphics");
5454 UPDATE_BUSY_STATE();
5456 print_timestamp_done("InitImages");
5459 static void InitSound(char *identifier)
5461 print_timestamp_init("InitSound");
5463 if (identifier == NULL)
5464 identifier = artwork.snd_current->identifier;
5466 /* set artwork path to send it to the sound server process */
5467 setLevelArtworkDir(artwork.snd_first);
5469 InitReloadCustomSounds(identifier);
5470 print_timestamp_time("InitReloadCustomSounds");
5472 ReinitializeSounds();
5473 print_timestamp_time("ReinitializeSounds");
5475 print_timestamp_done("InitSound");
5478 static void InitMusic(char *identifier)
5480 print_timestamp_init("InitMusic");
5482 if (identifier == NULL)
5483 identifier = artwork.mus_current->identifier;
5485 /* set artwork path to send it to the sound server process */
5486 setLevelArtworkDir(artwork.mus_first);
5488 InitReloadCustomMusic(identifier);
5489 print_timestamp_time("InitReloadCustomMusic");
5491 ReinitializeMusic();
5492 print_timestamp_time("ReinitializeMusic");
5494 print_timestamp_done("InitMusic");
5497 static void InitArtworkDone()
5499 InitGlobalAnimations();
5502 void InitNetworkServer()
5504 #if defined(NETWORK_AVALIABLE)
5508 if (!options.network)
5511 #if defined(NETWORK_AVALIABLE)
5512 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5514 if (!ConnectToServer(options.server_host, options.server_port))
5515 Error(ERR_EXIT, "cannot connect to network game server");
5517 SendToServer_PlayerName(setup.player_name);
5518 SendToServer_ProtocolVersion();
5521 SendToServer_NrWanted(nr_wanted);
5525 static boolean CheckArtworkConfigForCustomElements(char *filename)
5527 SetupFileHash *setup_file_hash;
5528 boolean redefined_ce_found = FALSE;
5530 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5532 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5534 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5536 char *token = HASH_ITERATION_TOKEN(itr);
5538 if (strPrefix(token, "custom_"))
5540 redefined_ce_found = TRUE;
5545 END_HASH_ITERATION(setup_file_hash, itr)
5547 freeSetupFileHash(setup_file_hash);
5550 return redefined_ce_found;
5553 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5555 char *filename_base, *filename_local;
5556 boolean redefined_ce_found = FALSE;
5558 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5561 printf("::: leveldir_current->identifier == '%s'\n",
5562 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5563 printf("::: leveldir_current->graphics_path == '%s'\n",
5564 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5565 printf("::: leveldir_current->graphics_set == '%s'\n",
5566 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5567 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5568 leveldir_current == NULL ? "[NULL]" :
5569 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5572 /* first look for special artwork configured in level series config */
5573 filename_base = getCustomArtworkLevelConfigFilename(type);
5576 printf("::: filename_base == '%s'\n", filename_base);
5579 if (fileExists(filename_base))
5580 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5582 filename_local = getCustomArtworkConfigFilename(type);
5585 printf("::: filename_local == '%s'\n", filename_local);
5588 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5589 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5592 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5595 return redefined_ce_found;
5598 static void InitOverrideArtwork()
5600 boolean redefined_ce_found = FALSE;
5602 /* to check if this level set redefines any CEs, do not use overriding */
5603 gfx.override_level_graphics = FALSE;
5604 gfx.override_level_sounds = FALSE;
5605 gfx.override_level_music = FALSE;
5607 /* now check if this level set has definitions for custom elements */
5608 if (setup.override_level_graphics == AUTO ||
5609 setup.override_level_sounds == AUTO ||
5610 setup.override_level_music == AUTO)
5611 redefined_ce_found =
5612 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5613 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5614 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5617 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5620 if (redefined_ce_found)
5622 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5623 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5624 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5625 gfx.override_level_music = (setup.override_level_music == TRUE);
5629 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5630 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5631 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5632 gfx.override_level_music = (setup.override_level_music != FALSE);
5636 printf("::: => %d, %d, %d\n",
5637 gfx.override_level_graphics,
5638 gfx.override_level_sounds,
5639 gfx.override_level_music);
5643 static char *getNewArtworkIdentifier(int type)
5645 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5646 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5647 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5648 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5649 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5650 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5651 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5652 char *leveldir_identifier = leveldir_current->identifier;
5653 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5654 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5655 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5656 char *artwork_current_identifier;
5657 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5659 /* leveldir_current may be invalid (level group, parent link) */
5660 if (!validLevelSeries(leveldir_current))
5663 /* 1st step: determine artwork set to be activated in descending order:
5664 --------------------------------------------------------------------
5665 1. setup artwork (when configured to override everything else)
5666 2. artwork set configured in "levelinfo.conf" of current level set
5667 (artwork in level directory will have priority when loading later)
5668 3. artwork in level directory (stored in artwork sub-directory)
5669 4. setup artwork (currently configured in setup menu) */
5671 if (setup_override_artwork)
5672 artwork_current_identifier = setup_artwork_set;
5673 else if (leveldir_artwork_set != NULL)
5674 artwork_current_identifier = leveldir_artwork_set;
5675 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5676 artwork_current_identifier = leveldir_identifier;
5678 artwork_current_identifier = setup_artwork_set;
5681 /* 2nd step: check if it is really needed to reload artwork set
5682 ------------------------------------------------------------ */
5684 /* ---------- reload if level set and also artwork set has changed ------- */
5685 if (leveldir_current_identifier[type] != leveldir_identifier &&
5686 (last_has_level_artwork_set[type] || has_level_artwork_set))
5687 artwork_new_identifier = artwork_current_identifier;
5689 leveldir_current_identifier[type] = leveldir_identifier;
5690 last_has_level_artwork_set[type] = has_level_artwork_set;
5692 /* ---------- reload if "override artwork" setting has changed ----------- */
5693 if (last_override_level_artwork[type] != setup_override_artwork)
5694 artwork_new_identifier = artwork_current_identifier;
5696 last_override_level_artwork[type] = setup_override_artwork;
5698 /* ---------- reload if current artwork identifier has changed ----------- */
5699 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5700 artwork_current_identifier))
5701 artwork_new_identifier = artwork_current_identifier;
5703 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5705 /* ---------- do not reload directly after starting ---------------------- */
5706 if (!initialized[type])
5707 artwork_new_identifier = NULL;
5709 initialized[type] = TRUE;
5711 return artwork_new_identifier;
5714 void ReloadCustomArtwork(int force_reload)
5716 int last_game_status = game_status; /* save current game status */
5717 char *gfx_new_identifier;
5718 char *snd_new_identifier;
5719 char *mus_new_identifier;
5720 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5721 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5722 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5723 boolean reload_needed;
5725 InitOverrideArtwork();
5727 force_reload_gfx |= AdjustGraphicsForEMC();
5729 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5730 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5731 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5733 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5734 snd_new_identifier != NULL || force_reload_snd ||
5735 mus_new_identifier != NULL || force_reload_mus);
5740 print_timestamp_init("ReloadCustomArtwork");
5742 SetGameStatus(GAME_MODE_LOADING);
5744 FadeOut(REDRAW_ALL);
5746 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5747 print_timestamp_time("ClearRectangle");
5751 if (gfx_new_identifier != NULL || force_reload_gfx)
5754 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5755 artwork.gfx_current_identifier,
5757 artwork.gfx_current->identifier,
5758 leveldir_current->graphics_set);
5762 print_timestamp_time("InitImages");
5765 if (snd_new_identifier != NULL || force_reload_snd)
5767 InitSound(snd_new_identifier);
5768 print_timestamp_time("InitSound");
5771 if (mus_new_identifier != NULL || force_reload_mus)
5773 InitMusic(mus_new_identifier);
5774 print_timestamp_time("InitMusic");
5779 SetGameStatus(last_game_status); /* restore current game status */
5781 init_last = init; /* switch to new busy animation */
5783 FadeOut(REDRAW_ALL);
5785 RedrawGlobalBorder();
5787 /* force redraw of (open or closed) door graphics */
5788 SetDoorState(DOOR_OPEN_ALL);
5789 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5791 FadeSetEnterScreen();
5792 FadeSkipNextFadeOut();
5794 print_timestamp_done("ReloadCustomArtwork");
5796 LimitScreenUpdates(FALSE);
5799 void KeyboardAutoRepeatOffUnlessAutoplay()
5801 if (global.autoplay_leveldir == NULL)
5802 KeyboardAutoRepeatOff();
5805 void DisplayExitMessage(char *format, va_list ap)
5807 // check if draw buffer and fonts for exit message are already available
5808 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5811 int font_1 = FC_RED;
5812 int font_2 = FC_YELLOW;
5813 int font_3 = FC_BLUE;
5814 int font_width = getFontWidth(font_2);
5815 int font_height = getFontHeight(font_2);
5818 int sxsize = WIN_XSIZE - 2 * sx;
5819 int sysize = WIN_YSIZE - 2 * sy;
5820 int line_length = sxsize / font_width;
5821 int max_lines = sysize / font_height;
5822 int num_lines_printed;
5826 gfx.sxsize = sxsize;
5827 gfx.sysize = sysize;
5831 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5833 DrawTextSCentered(sy, font_1, "Fatal error:");
5834 sy += 3 * font_height;;
5837 DrawTextBufferVA(sx, sy, format, ap, font_2,
5838 line_length, line_length, max_lines,
5839 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5840 sy += (num_lines_printed + 3) * font_height;
5842 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5843 sy += 3 * font_height;
5846 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5847 line_length, line_length, max_lines,
5848 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5850 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5852 redraw_mask = REDRAW_ALL;
5854 /* force drawing exit message even if screen updates are currently limited */
5855 LimitScreenUpdates(FALSE);
5859 /* deactivate toons on error message screen */
5860 setup.toons = FALSE;
5862 WaitForEventToContinue();
5866 /* ========================================================================= */
5868 /* ========================================================================= */
5872 print_timestamp_init("OpenAll");
5874 SetGameStatus(GAME_MODE_LOADING);
5878 InitGlobal(); /* initialize some global variables */
5880 print_timestamp_time("[init global stuff]");
5884 print_timestamp_time("[init setup/config stuff (1)]");
5886 if (options.execute_command)
5887 Execute_Command(options.execute_command);
5889 if (options.serveronly)
5891 #if defined(PLATFORM_UNIX)
5892 NetworkServer(options.server_port, options.serveronly);
5894 Error(ERR_WARN, "networking only supported in Unix version");
5897 exit(0); /* never reached, server loops forever */
5901 print_timestamp_time("[init setup/config stuff (2)]");
5903 print_timestamp_time("[init setup/config stuff (3)]");
5904 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5905 print_timestamp_time("[init setup/config stuff (4)]");
5906 InitArtworkConfig(); /* needed before forking sound child process */
5907 print_timestamp_time("[init setup/config stuff (5)]");
5909 print_timestamp_time("[init setup/config stuff (6)]");
5911 InitRND(NEW_RANDOMIZE);
5912 InitSimpleRandom(NEW_RANDOMIZE);
5916 print_timestamp_time("[init setup/config stuff]");
5919 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5921 InitEventFilter(FilterEvents);
5923 print_timestamp_time("[init video stuff]");
5925 InitElementPropertiesStatic();
5926 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5927 InitElementPropertiesGfxElement();
5929 print_timestamp_time("[init element properties stuff]");
5933 print_timestamp_time("InitGfx");
5936 print_timestamp_time("InitLevelInfo");
5938 InitLevelArtworkInfo();
5939 print_timestamp_time("InitLevelArtworkInfo");
5941 InitOverrideArtwork(); /* needs to know current level directory */
5942 print_timestamp_time("InitOverrideArtwork");
5944 InitImages(); /* needs to know current level directory */
5945 print_timestamp_time("InitImages");
5947 InitSound(NULL); /* needs to know current level directory */
5948 print_timestamp_time("InitSound");
5950 InitMusic(NULL); /* needs to know current level directory */
5951 print_timestamp_time("InitMusic");
5955 InitGfxBackground();
5960 if (global.autoplay_leveldir)
5965 else if (global.convert_leveldir)
5970 else if (global.create_images_dir)
5972 CreateLevelSketchImages();
5976 SetGameStatus(GAME_MODE_MAIN);
5978 FadeSetEnterScreen();
5979 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5980 FadeSkipNextFadeOut();
5982 print_timestamp_time("[post-artwork]");
5984 print_timestamp_done("OpenAll");
5988 InitNetworkServer();
5991 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5993 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5994 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5995 #if defined(PLATFORM_ANDROID)
5996 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5997 SDL_AndroidGetInternalStoragePath());
5998 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5999 SDL_AndroidGetExternalStoragePath());
6000 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6001 (SDL_AndroidGetExternalStorageState() ==
6002 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
6003 SDL_AndroidGetExternalStorageState() ==
6004 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
6009 void CloseAllAndExit(int exit_value)
6014 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6021 #if defined(TARGET_SDL)
6022 #if defined(TARGET_SDL2)
6024 // set a flag to tell the network server thread to quit and wait for it
6025 // using SDL_WaitThread()
6027 if (network_server) /* terminate network server */
6028 SDL_KillThread(server_thread);
6032 CloseVideoDisplay();
6033 ClosePlatformDependentStuff();
6035 if (exit_value != 0)
6037 /* fall back to default level set (current set may have caused an error) */
6038 SaveLevelSetup_LastSeries_Deactivate();
6040 /* tell user where to find error log file which may contain more details */
6041 // (error notification now directly displayed on screen inside R'n'D
6042 // NotifyUserAboutErrorFile(); /* currently only works for Windows */