1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #include "conf_e2g.c" /* include auto-generated data structure definitions */
28 #include "conf_esg.c" /* include auto-generated data structure definitions */
29 #include "conf_e2s.c" /* include auto-generated data structure definitions */
30 #include "conf_fnt.c" /* include auto-generated data structure definitions */
31 #include "conf_g2s.c" /* include auto-generated data structure definitions */
32 #include "conf_g2m.c" /* include auto-generated data structure definitions */
33 #include "conf_act.c" /* include auto-generated data structure definitions */
36 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41 static struct GraphicInfo anim_initial;
43 static int copy_properties[][5] =
47 EL_BUG_LEFT, EL_BUG_RIGHT,
48 EL_BUG_UP, EL_BUG_DOWN
52 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
53 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
57 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
58 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
62 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
63 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
67 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
68 EL_PACMAN_UP, EL_PACMAN_DOWN
72 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
73 EL_YAMYAM_UP, EL_YAMYAM_DOWN
77 EL_MOLE_LEFT, EL_MOLE_RIGHT,
78 EL_MOLE_UP, EL_MOLE_DOWN
89 struct GraphicInfo *graphic_info_last = graphic_info;
91 static unsigned int action_delay = 0;
92 unsigned int action_delay_value = GameFrameDelay;
93 int sync_frame = FrameCounter;
96 if (game_status != GAME_MODE_LOADING)
99 if (anim_initial.bitmap == NULL || window == NULL)
102 if (!DelayReached(&action_delay, action_delay_value))
105 if (init_last.busy.x == -1)
106 init_last.busy.x = WIN_XSIZE / 2;
107 if (init_last.busy.y == -1)
108 init_last.busy.y = WIN_YSIZE / 2;
110 x = ALIGNED_TEXT_XPOS(&init_last.busy);
111 y = ALIGNED_TEXT_YPOS(&init_last.busy);
113 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
115 if (sync_frame % anim_initial.anim_delay == 0)
119 int width = graphic_info[graphic].width;
120 int height = graphic_info[graphic].height;
121 int frame = getGraphicAnimationFrame(graphic, sync_frame);
123 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
124 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
127 graphic_info = graphic_info_last;
134 FreeLevelEditorGadgets();
143 static boolean gadgets_initialized = FALSE;
145 if (gadgets_initialized)
148 CreateLevelEditorGadgets();
152 CreateScreenGadgets();
154 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
156 gadgets_initialized = TRUE;
159 inline static void InitElementSmallImagesScaledUp(int graphic)
161 struct GraphicInfo *g = &graphic_info[graphic];
163 // create small and game tile sized bitmaps (and scale up, if needed)
164 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
167 void InitElementSmallImages()
169 print_timestamp_init("InitElementSmallImages");
171 static int special_graphics[] =
185 IMG_EDITOR_ELEMENT_BORDER,
186 IMG_EDITOR_ELEMENT_BORDER_INPUT,
187 IMG_EDITOR_CASCADE_LIST,
188 IMG_EDITOR_CASCADE_LIST_ACTIVE,
191 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
192 int num_property_mappings = getImageListPropertyMappingSize();
195 print_timestamp_time("getImageListPropertyMapping/Size");
197 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
198 /* initialize normal element images from static configuration */
199 for (i = 0; element_to_graphic[i].element > -1; i++)
200 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
201 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
203 /* initialize special element images from static configuration */
204 for (i = 0; element_to_special_graphic[i].element > -1; i++)
205 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
206 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
208 /* initialize element images from dynamic configuration */
209 for (i = 0; i < num_property_mappings; i++)
210 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
211 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
212 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
214 /* initialize special non-element images from above list */
215 for (i = 0; special_graphics[i] > -1; i++)
216 InitElementSmallImagesScaledUp(special_graphics[i]);
217 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
219 print_timestamp_done("InitElementSmallImages");
222 void InitScaledImages()
226 /* scale normal images from static configuration, if not already scaled */
227 for (i = 0; i < NUM_IMAGE_FILES; i++)
228 ScaleImage(i, graphic_info[i].scale_up_factor);
231 void InitBitmapPointers()
233 int num_images = getImageListSize();
236 // standard size bitmap may have changed -- update default bitmap pointer
237 for (i = 0; i < num_images; i++)
238 if (graphic_info[i].bitmaps)
239 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
242 void InitImageTextures()
246 FreeAllImageTextures();
248 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
249 CreateImageTextures(i);
251 for (i = 0; i < MAX_NUM_TOONS; i++)
252 CreateImageTextures(IMG_TOON_1 + i);
254 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
256 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
258 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
260 int graphic = global_anim_info[i].graphic[j][k];
262 if (graphic == IMG_UNDEFINED)
265 CreateImageTextures(graphic);
272 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
273 void SetBitmaps_EM(Bitmap **em_bitmap)
275 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
276 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
281 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
282 void SetBitmaps_SP(Bitmap **sp_bitmap)
284 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
288 static int getFontBitmapID(int font_nr)
292 /* (special case: do not use special font for GAME_MODE_LOADING) */
293 if (game_status >= GAME_MODE_TITLE_INITIAL &&
294 game_status <= GAME_MODE_PSEUDO_PREVIEW)
295 special = game_status;
296 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
297 special = GFX_SPECIAL_ARG_MAIN;
300 return font_info[font_nr].special_bitmap_id[special];
305 static int getFontFromToken(char *token)
307 char *value = getHashEntry(font_token_hash, token);
312 /* if font not found, use reliable default value */
313 return FONT_INITIAL_1;
316 void InitFontGraphicInfo()
318 static struct FontBitmapInfo *font_bitmap_info = NULL;
319 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
320 int num_property_mappings = getImageListPropertyMappingSize();
321 int num_font_bitmaps = NUM_FONTS;
324 if (graphic_info == NULL) /* still at startup phase */
326 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
327 getFontBitmapID, getFontFromToken);
332 /* ---------- initialize font graphic definitions ---------- */
334 /* always start with reliable default values (normal font graphics) */
335 for (i = 0; i < NUM_FONTS; i++)
336 font_info[i].graphic = IMG_FONT_INITIAL_1;
338 /* initialize normal font/graphic mapping from static configuration */
339 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
341 int font_nr = font_to_graphic[i].font_nr;
342 int special = font_to_graphic[i].special;
343 int graphic = font_to_graphic[i].graphic;
348 font_info[font_nr].graphic = graphic;
351 /* always start with reliable default values (special font graphics) */
352 for (i = 0; i < NUM_FONTS; i++)
354 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
356 font_info[i].special_graphic[j] = font_info[i].graphic;
357 font_info[i].special_bitmap_id[j] = i;
361 /* initialize special font/graphic mapping from static configuration */
362 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
364 int font_nr = font_to_graphic[i].font_nr;
365 int special = font_to_graphic[i].special;
366 int graphic = font_to_graphic[i].graphic;
367 int base_graphic = font2baseimg(font_nr);
369 if (IS_SPECIAL_GFX_ARG(special))
371 boolean base_redefined =
372 getImageListEntryFromImageID(base_graphic)->redefined;
373 boolean special_redefined =
374 getImageListEntryFromImageID(graphic)->redefined;
375 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
377 /* if the base font ("font.title_1", for example) has been redefined,
378 but not the special font ("font.title_1.LEVELS", for example), do not
379 use an existing (in this case considered obsolete) special font
380 anymore, but use the automatically determined default font */
381 /* special case: cloned special fonts must be explicitly redefined,
382 but are not automatically redefined by redefining base font */
383 if (base_redefined && !special_redefined && !special_cloned)
386 font_info[font_nr].special_graphic[special] = graphic;
387 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
392 /* initialize special font/graphic mapping from dynamic configuration */
393 for (i = 0; i < num_property_mappings; i++)
395 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
396 int special = property_mapping[i].ext3_index;
397 int graphic = property_mapping[i].artwork_index;
402 if (IS_SPECIAL_GFX_ARG(special))
404 font_info[font_nr].special_graphic[special] = graphic;
405 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
410 /* correct special font/graphic mapping for cloned fonts for downwards
411 compatibility of PREVIEW fonts -- this is only needed for implicit
412 redefinition of special font by redefined base font, and only if other
413 fonts are cloned from this special font (like in the "Zelda" level set) */
414 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
416 int font_nr = font_to_graphic[i].font_nr;
417 int special = font_to_graphic[i].special;
418 int graphic = font_to_graphic[i].graphic;
420 if (IS_SPECIAL_GFX_ARG(special))
422 boolean special_redefined =
423 getImageListEntryFromImageID(graphic)->redefined;
424 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
426 if (special_cloned && !special_redefined)
430 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
432 int font_nr2 = font_to_graphic[j].font_nr;
433 int special2 = font_to_graphic[j].special;
434 int graphic2 = font_to_graphic[j].graphic;
436 if (IS_SPECIAL_GFX_ARG(special2) &&
437 graphic2 == graphic_info[graphic].clone_from)
439 font_info[font_nr].special_graphic[special] =
440 font_info[font_nr2].special_graphic[special2];
441 font_info[font_nr].special_bitmap_id[special] =
442 font_info[font_nr2].special_bitmap_id[special2];
449 /* reset non-redefined ".active" font graphics if normal font is redefined */
450 /* (this different treatment is needed because normal and active fonts are
451 independently defined ("active" is not a property of font definitions!) */
452 for (i = 0; i < NUM_FONTS; i++)
454 int font_nr_base = i;
455 int font_nr_active = FONT_ACTIVE(font_nr_base);
457 /* check only those fonts with exist as normal and ".active" variant */
458 if (font_nr_base != font_nr_active)
460 int base_graphic = font_info[font_nr_base].graphic;
461 int active_graphic = font_info[font_nr_active].graphic;
462 boolean base_redefined =
463 getImageListEntryFromImageID(base_graphic)->redefined;
464 boolean active_redefined =
465 getImageListEntryFromImageID(active_graphic)->redefined;
467 /* if the base font ("font.menu_1", for example) has been redefined,
468 but not the active font ("font.menu_1.active", for example), do not
469 use an existing (in this case considered obsolete) active font
470 anymore, but use the automatically determined default font */
471 if (base_redefined && !active_redefined)
472 font_info[font_nr_active].graphic = base_graphic;
474 /* now also check each "special" font (which may be the same as above) */
475 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
477 int base_graphic = font_info[font_nr_base].special_graphic[j];
478 int active_graphic = font_info[font_nr_active].special_graphic[j];
479 boolean base_redefined =
480 getImageListEntryFromImageID(base_graphic)->redefined;
481 boolean active_redefined =
482 getImageListEntryFromImageID(active_graphic)->redefined;
484 /* same as above, but check special graphic definitions, for example:
485 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
486 if (base_redefined && !active_redefined)
488 font_info[font_nr_active].special_graphic[j] =
489 font_info[font_nr_base].special_graphic[j];
490 font_info[font_nr_active].special_bitmap_id[j] =
491 font_info[font_nr_base].special_bitmap_id[j];
497 /* ---------- initialize font bitmap array ---------- */
499 if (font_bitmap_info != NULL)
500 FreeFontInfo(font_bitmap_info);
503 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
505 /* ---------- initialize font bitmap definitions ---------- */
507 for (i = 0; i < NUM_FONTS; i++)
509 if (i < NUM_INITIAL_FONTS)
511 font_bitmap_info[i] = font_initial[i];
515 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
517 int font_bitmap_id = font_info[i].special_bitmap_id[j];
518 int graphic = font_info[i].special_graphic[j];
520 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
521 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
523 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
524 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
527 /* copy font relevant information from graphics information */
528 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
529 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
530 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
531 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
532 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
534 font_bitmap_info[font_bitmap_id].draw_xoffset =
535 graphic_info[graphic].draw_xoffset;
536 font_bitmap_info[font_bitmap_id].draw_yoffset =
537 graphic_info[graphic].draw_yoffset;
539 font_bitmap_info[font_bitmap_id].num_chars =
540 graphic_info[graphic].anim_frames;
541 font_bitmap_info[font_bitmap_id].num_chars_per_line =
542 graphic_info[graphic].anim_frames_per_line;
546 InitFontInfo(font_bitmap_info, num_font_bitmaps,
547 getFontBitmapID, getFontFromToken);
550 void InitGlobalAnimGraphicInfo()
552 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
553 int num_property_mappings = getImageListPropertyMappingSize();
556 if (graphic_info == NULL) /* still at startup phase */
559 /* always start with reliable default values (no global animations) */
560 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
561 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
562 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
563 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
565 /* initialize global animation definitions from static configuration */
566 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
568 int j = GLOBAL_ANIM_ID_PART_BASE;
569 int k = GFX_SPECIAL_ARG_DEFAULT;
571 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
574 /* initialize global animation definitions from dynamic configuration */
575 for (i = 0; i < num_property_mappings; i++)
577 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
578 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
579 int special = property_mapping[i].ext3_index;
580 int graphic = property_mapping[i].artwork_index;
582 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
585 /* set animation part to base part, if not specified */
586 if (!IS_GLOBAL_ANIM_PART(part_nr))
587 part_nr = GLOBAL_ANIM_ID_PART_BASE;
589 /* set animation screen to default, if not specified */
590 if (!IS_SPECIAL_GFX_ARG(special))
591 special = GFX_SPECIAL_ARG_DEFAULT;
593 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
597 printf("::: InitGlobalAnimGraphicInfo\n");
599 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
600 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
601 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
602 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
603 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
604 printf("::: - anim %d, part %d, mode %d => %d\n",
605 i, j, k, global_anim_info[i].graphic[j][k]);
609 void InitGlobalAnimSoundInfo()
611 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
612 int num_property_mappings = getSoundListPropertyMappingSize();
615 /* always start with reliable default values (no global animation sounds) */
616 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
617 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
618 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
619 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
621 /* initialize global animation sound definitions from dynamic configuration */
622 for (i = 0; i < num_property_mappings; i++)
624 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
625 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
626 int special = property_mapping[i].ext3_index;
627 int sound = property_mapping[i].artwork_index;
629 // sound uses control definition; map it to position of graphic (artwork)
630 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
632 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
635 /* set animation part to base part, if not specified */
636 if (!IS_GLOBAL_ANIM_PART(part_nr))
637 part_nr = GLOBAL_ANIM_ID_PART_BASE;
639 /* set animation screen to default, if not specified */
640 if (!IS_SPECIAL_GFX_ARG(special))
641 special = GFX_SPECIAL_ARG_DEFAULT;
643 global_anim_info[anim_nr].sound[part_nr][special] = sound;
647 printf("::: InitGlobalAnimSoundInfo\n");
649 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
650 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
651 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
652 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
653 printf("::: - anim %d, part %d, mode %d => %d\n",
654 i, j, k, global_anim_info[i].sound[j][k]);
658 void InitGlobalAnimMusicInfo()
660 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
661 int num_property_mappings = getMusicListPropertyMappingSize();
664 /* always start with reliable default values (no global animation music) */
665 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
666 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
667 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
668 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
670 /* initialize global animation music definitions from dynamic configuration */
671 for (i = 0; i < num_property_mappings; i++)
673 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
674 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
675 int special = property_mapping[i].ext2_index;
676 int music = property_mapping[i].artwork_index;
678 // music uses control definition; map it to position of graphic (artwork)
679 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
681 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
684 /* set animation part to base part, if not specified */
685 if (!IS_GLOBAL_ANIM_PART(part_nr))
686 part_nr = GLOBAL_ANIM_ID_PART_BASE;
688 /* set animation screen to default, if not specified */
689 if (!IS_SPECIAL_GFX_ARG(special))
690 special = GFX_SPECIAL_ARG_DEFAULT;
692 global_anim_info[anim_nr].music[part_nr][special] = music;
696 printf("::: InitGlobalAnimMusicInfo\n");
698 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
699 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
700 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
701 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
702 printf("::: - anim %d, part %d, mode %d => %d\n",
703 i, j, k, global_anim_info[i].music[j][k]);
707 void InitElementGraphicInfo()
709 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
710 int num_property_mappings = getImageListPropertyMappingSize();
713 if (graphic_info == NULL) /* still at startup phase */
716 /* set values to -1 to identify later as "uninitialized" values */
717 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
719 for (act = 0; act < NUM_ACTIONS; act++)
721 element_info[i].graphic[act] = -1;
722 element_info[i].crumbled[act] = -1;
724 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
726 element_info[i].direction_graphic[act][dir] = -1;
727 element_info[i].direction_crumbled[act][dir] = -1;
734 /* initialize normal element/graphic mapping from static configuration */
735 for (i = 0; element_to_graphic[i].element > -1; i++)
737 int element = element_to_graphic[i].element;
738 int action = element_to_graphic[i].action;
739 int direction = element_to_graphic[i].direction;
740 boolean crumbled = element_to_graphic[i].crumbled;
741 int graphic = element_to_graphic[i].graphic;
742 int base_graphic = el2baseimg(element);
744 if (graphic_info[graphic].bitmap == NULL)
747 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
750 boolean base_redefined =
751 getImageListEntryFromImageID(base_graphic)->redefined;
752 boolean act_dir_redefined =
753 getImageListEntryFromImageID(graphic)->redefined;
755 /* if the base graphic ("emerald", for example) has been redefined,
756 but not the action graphic ("emerald.falling", for example), do not
757 use an existing (in this case considered obsolete) action graphic
758 anymore, but use the automatically determined default graphic */
759 if (base_redefined && !act_dir_redefined)
764 action = ACTION_DEFAULT;
769 element_info[element].direction_crumbled[action][direction] = graphic;
771 element_info[element].crumbled[action] = graphic;
776 element_info[element].direction_graphic[action][direction] = graphic;
778 element_info[element].graphic[action] = graphic;
782 /* initialize normal element/graphic mapping from dynamic configuration */
783 for (i = 0; i < num_property_mappings; i++)
785 int element = property_mapping[i].base_index;
786 int action = property_mapping[i].ext1_index;
787 int direction = property_mapping[i].ext2_index;
788 int special = property_mapping[i].ext3_index;
789 int graphic = property_mapping[i].artwork_index;
790 boolean crumbled = FALSE;
792 if (special == GFX_SPECIAL_ARG_CRUMBLED)
798 if (graphic_info[graphic].bitmap == NULL)
801 if (element >= MAX_NUM_ELEMENTS || special != -1)
805 action = ACTION_DEFAULT;
810 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
811 element_info[element].direction_crumbled[action][dir] = -1;
814 element_info[element].direction_crumbled[action][direction] = graphic;
816 element_info[element].crumbled[action] = graphic;
821 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
822 element_info[element].direction_graphic[action][dir] = -1;
825 element_info[element].direction_graphic[action][direction] = graphic;
827 element_info[element].graphic[action] = graphic;
831 /* now copy all graphics that are defined to be cloned from other graphics */
832 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
834 int graphic = element_info[i].graphic[ACTION_DEFAULT];
835 int crumbled_like, diggable_like;
840 crumbled_like = graphic_info[graphic].crumbled_like;
841 diggable_like = graphic_info[graphic].diggable_like;
843 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
845 for (act = 0; act < NUM_ACTIONS; act++)
846 element_info[i].crumbled[act] =
847 element_info[crumbled_like].crumbled[act];
848 for (act = 0; act < NUM_ACTIONS; act++)
849 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
850 element_info[i].direction_crumbled[act][dir] =
851 element_info[crumbled_like].direction_crumbled[act][dir];
854 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
856 element_info[i].graphic[ACTION_DIGGING] =
857 element_info[diggable_like].graphic[ACTION_DIGGING];
858 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
859 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
860 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
864 /* set hardcoded definitions for some runtime elements without graphic */
865 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
867 /* set hardcoded definitions for some internal elements without graphic */
868 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
870 if (IS_EDITOR_CASCADE_INACTIVE(i))
871 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
872 else if (IS_EDITOR_CASCADE_ACTIVE(i))
873 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
876 /* now set all undefined/invalid graphics to -1 to set to default after it */
877 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
879 for (act = 0; act < NUM_ACTIONS; act++)
883 graphic = element_info[i].graphic[act];
884 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
885 element_info[i].graphic[act] = -1;
887 graphic = element_info[i].crumbled[act];
888 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
889 element_info[i].crumbled[act] = -1;
891 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
893 graphic = element_info[i].direction_graphic[act][dir];
894 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
895 element_info[i].direction_graphic[act][dir] = -1;
897 graphic = element_info[i].direction_crumbled[act][dir];
898 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
899 element_info[i].direction_crumbled[act][dir] = -1;
906 /* adjust graphics with 2nd tile for movement according to direction
907 (do this before correcting '-1' values to minimize calculations) */
908 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
910 for (act = 0; act < NUM_ACTIONS; act++)
912 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
914 int graphic = element_info[i].direction_graphic[act][dir];
915 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
917 if (act == ACTION_FALLING) /* special case */
918 graphic = element_info[i].graphic[act];
921 graphic_info[graphic].double_movement &&
922 graphic_info[graphic].swap_double_tiles != 0)
924 struct GraphicInfo *g = &graphic_info[graphic];
925 int src_x_front = g->src_x;
926 int src_y_front = g->src_y;
927 int src_x_back = g->src_x + g->offset2_x;
928 int src_y_back = g->src_y + g->offset2_y;
929 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
931 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
932 src_y_front < src_y_back);
933 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
934 boolean swap_movement_tiles_autodetected =
935 (!frames_are_ordered_diagonally &&
936 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
937 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
938 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
939 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
941 /* swap frontside and backside graphic tile coordinates, if needed */
942 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
944 /* get current (wrong) backside tile coordinates */
945 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
947 /* set frontside tile coordinates to backside tile coordinates */
948 g->src_x = src_x_back;
949 g->src_y = src_y_back;
951 /* invert tile offset to point to new backside tile coordinates */
955 /* do not swap front and backside tiles again after correction */
956 g->swap_double_tiles = 0;
965 /* now set all '-1' values to element specific default values */
966 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
968 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
969 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
970 int default_direction_graphic[NUM_DIRECTIONS_FULL];
971 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
973 if (default_graphic == -1)
974 default_graphic = IMG_UNKNOWN;
976 if (default_crumbled == -1)
977 default_crumbled = default_graphic;
979 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
981 default_direction_graphic[dir] =
982 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
983 default_direction_crumbled[dir] =
984 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
986 if (default_direction_graphic[dir] == -1)
987 default_direction_graphic[dir] = default_graphic;
989 if (default_direction_crumbled[dir] == -1)
990 default_direction_crumbled[dir] = default_direction_graphic[dir];
993 for (act = 0; act < NUM_ACTIONS; act++)
995 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
996 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
997 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
998 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
999 act == ACTION_TURNING_FROM_RIGHT ||
1000 act == ACTION_TURNING_FROM_UP ||
1001 act == ACTION_TURNING_FROM_DOWN);
1003 /* generic default action graphic (defined by "[default]" directive) */
1004 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1005 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1006 int default_remove_graphic = IMG_EMPTY;
1008 if (act_remove && default_action_graphic != -1)
1009 default_remove_graphic = default_action_graphic;
1011 /* look for special default action graphic (classic game specific) */
1012 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1013 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1014 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1015 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1016 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1017 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1019 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1020 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1021 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1022 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1023 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1024 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1026 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1027 /* !!! make this better !!! */
1028 if (i == EL_EMPTY_SPACE)
1030 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1031 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1034 if (default_action_graphic == -1)
1035 default_action_graphic = default_graphic;
1037 if (default_action_crumbled == -1)
1038 default_action_crumbled = default_action_graphic;
1040 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1042 /* use action graphic as the default direction graphic, if undefined */
1043 int default_action_direction_graphic = element_info[i].graphic[act];
1044 int default_action_direction_crumbled = element_info[i].crumbled[act];
1046 /* no graphic for current action -- use default direction graphic */
1047 if (default_action_direction_graphic == -1)
1048 default_action_direction_graphic =
1049 (act_remove ? default_remove_graphic :
1051 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1052 default_action_graphic != default_graphic ?
1053 default_action_graphic :
1054 default_direction_graphic[dir]);
1056 if (element_info[i].direction_graphic[act][dir] == -1)
1057 element_info[i].direction_graphic[act][dir] =
1058 default_action_direction_graphic;
1060 if (default_action_direction_crumbled == -1)
1061 default_action_direction_crumbled =
1062 element_info[i].direction_graphic[act][dir];
1064 if (element_info[i].direction_crumbled[act][dir] == -1)
1065 element_info[i].direction_crumbled[act][dir] =
1066 default_action_direction_crumbled;
1069 /* no graphic for this specific action -- use default action graphic */
1070 if (element_info[i].graphic[act] == -1)
1071 element_info[i].graphic[act] =
1072 (act_remove ? default_remove_graphic :
1073 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1074 default_action_graphic);
1076 if (element_info[i].crumbled[act] == -1)
1077 element_info[i].crumbled[act] = element_info[i].graphic[act];
1081 UPDATE_BUSY_STATE();
1084 void InitElementSpecialGraphicInfo()
1086 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1087 int num_property_mappings = getImageListPropertyMappingSize();
1090 /* always start with reliable default values */
1091 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1092 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1093 element_info[i].special_graphic[j] =
1094 element_info[i].graphic[ACTION_DEFAULT];
1096 /* initialize special element/graphic mapping from static configuration */
1097 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1099 int element = element_to_special_graphic[i].element;
1100 int special = element_to_special_graphic[i].special;
1101 int graphic = element_to_special_graphic[i].graphic;
1102 int base_graphic = el2baseimg(element);
1103 boolean base_redefined =
1104 getImageListEntryFromImageID(base_graphic)->redefined;
1105 boolean special_redefined =
1106 getImageListEntryFromImageID(graphic)->redefined;
1108 /* if the base graphic ("emerald", for example) has been redefined,
1109 but not the special graphic ("emerald.EDITOR", for example), do not
1110 use an existing (in this case considered obsolete) special graphic
1111 anymore, but use the automatically created (down-scaled) graphic */
1112 if (base_redefined && !special_redefined)
1115 element_info[element].special_graphic[special] = graphic;
1118 /* initialize special element/graphic mapping from dynamic configuration */
1119 for (i = 0; i < num_property_mappings; i++)
1121 int element = property_mapping[i].base_index;
1122 int action = property_mapping[i].ext1_index;
1123 int direction = property_mapping[i].ext2_index;
1124 int special = property_mapping[i].ext3_index;
1125 int graphic = property_mapping[i].artwork_index;
1127 /* for action ".active", replace element with active element, if exists */
1128 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1130 element = ELEMENT_ACTIVE(element);
1134 if (element >= MAX_NUM_ELEMENTS)
1137 /* do not change special graphic if action or direction was specified */
1138 if (action != -1 || direction != -1)
1141 if (IS_SPECIAL_GFX_ARG(special))
1142 element_info[element].special_graphic[special] = graphic;
1145 /* now set all undefined/invalid graphics to default */
1146 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1147 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1148 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1149 element_info[i].special_graphic[j] =
1150 element_info[i].graphic[ACTION_DEFAULT];
1153 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1155 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1156 return get_parameter_value(value_raw, suffix, type);
1158 if (strEqual(value_raw, ARG_UNDEFINED))
1159 return ARG_UNDEFINED_VALUE;
1161 if (type == TYPE_ELEMENT)
1163 char *value = getHashEntry(element_token_hash, value_raw);
1167 Error(ERR_INFO_LINE, "-");
1168 Error(ERR_INFO, "warning: error found in config file:");
1169 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1170 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1171 Error(ERR_INFO, "custom graphic rejected for this element/action");
1172 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1173 Error(ERR_INFO_LINE, "-");
1176 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1178 else if (type == TYPE_GRAPHIC)
1180 char *value = getHashEntry(graphic_token_hash, value_raw);
1181 int fallback_graphic = IMG_CHAR_EXCLAM;
1185 Error(ERR_INFO_LINE, "-");
1186 Error(ERR_INFO, "warning: error found in config file:");
1187 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1188 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1189 Error(ERR_INFO, "custom graphic rejected for this element/action");
1190 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1191 Error(ERR_INFO_LINE, "-");
1194 return (value != NULL ? atoi(value) : fallback_graphic);
1200 static int get_scaled_graphic_width(int graphic)
1202 int original_width = getOriginalImageWidthFromImageID(graphic);
1203 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1205 return original_width * scale_up_factor;
1208 static int get_scaled_graphic_height(int graphic)
1210 int original_height = getOriginalImageHeightFromImageID(graphic);
1211 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1213 return original_height * scale_up_factor;
1216 static void set_graphic_parameters_ext(int graphic, int *parameter,
1217 Bitmap **src_bitmaps)
1219 struct GraphicInfo *g = &graphic_info[graphic];
1220 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1221 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1222 int anim_frames_per_line = 1;
1224 /* always start with reliable default values */
1225 g->src_image_width = 0;
1226 g->src_image_height = 0;
1229 g->width = TILEX; /* default for element graphics */
1230 g->height = TILEY; /* default for element graphics */
1231 g->offset_x = 0; /* one or both of these values ... */
1232 g->offset_y = 0; /* ... will be corrected later */
1233 g->offset2_x = 0; /* one or both of these values ... */
1234 g->offset2_y = 0; /* ... will be corrected later */
1235 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1236 g->crumbled_like = -1; /* do not use clone element */
1237 g->diggable_like = -1; /* do not use clone element */
1238 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1239 g->scale_up_factor = 1; /* default: no scaling up */
1240 g->tile_size = TILESIZE; /* default: standard tile size */
1241 g->clone_from = -1; /* do not use clone graphic */
1242 g->init_delay_fixed = 0;
1243 g->init_delay_random = 0;
1244 g->anim_delay_fixed = 0;
1245 g->anim_delay_random = 0;
1246 g->post_delay_fixed = 0;
1247 g->post_delay_random = 0;
1249 g->fade_mode = FADE_MODE_DEFAULT;
1253 g->align = ALIGN_CENTER; /* default for title screens */
1254 g->valign = VALIGN_MIDDLE; /* default for title screens */
1255 g->sort_priority = 0; /* default for title screens */
1257 g->style = STYLE_DEFAULT;
1259 g->bitmaps = src_bitmaps;
1260 g->bitmap = src_bitmap;
1262 /* optional zoom factor for scaling up the image to a larger size */
1263 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1264 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1265 if (g->scale_up_factor < 1)
1266 g->scale_up_factor = 1; /* no scaling */
1268 /* optional tile size for using non-standard image size */
1269 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1271 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1274 // CHECK: should tile sizes less than standard tile size be allowed?
1275 if (g->tile_size < TILESIZE)
1276 g->tile_size = TILESIZE; /* standard tile size */
1279 // when setting tile size, also set width and height accordingly
1280 g->width = g->tile_size;
1281 g->height = g->tile_size;
1284 if (g->use_image_size)
1286 /* set new default bitmap size (with scaling, but without small images) */
1287 g->width = get_scaled_graphic_width(graphic);
1288 g->height = get_scaled_graphic_height(graphic);
1291 /* optional width and height of each animation frame */
1292 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1293 g->width = parameter[GFX_ARG_WIDTH];
1294 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1295 g->height = parameter[GFX_ARG_HEIGHT];
1297 /* optional x and y tile position of animation frame sequence */
1298 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1299 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1300 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1301 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1303 /* optional x and y pixel position of animation frame sequence */
1304 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1305 g->src_x = parameter[GFX_ARG_X];
1306 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1307 g->src_y = parameter[GFX_ARG_Y];
1313 Error(ERR_INFO_LINE, "-");
1314 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1315 g->width, getTokenFromImageID(graphic), TILEX);
1316 Error(ERR_INFO_LINE, "-");
1318 g->width = TILEX; /* will be checked to be inside bitmap later */
1323 Error(ERR_INFO_LINE, "-");
1324 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1325 g->height, getTokenFromImageID(graphic), TILEY);
1326 Error(ERR_INFO_LINE, "-");
1328 g->height = TILEY; /* will be checked to be inside bitmap later */
1334 /* get final bitmap size (with scaling, but without small images) */
1335 int src_image_width = get_scaled_graphic_width(graphic);
1336 int src_image_height = get_scaled_graphic_height(graphic);
1338 if (src_image_width == 0 || src_image_height == 0)
1340 /* only happens when loaded outside artwork system (like "global.busy") */
1341 src_image_width = src_bitmap->width;
1342 src_image_height = src_bitmap->height;
1345 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1347 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1348 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1352 anim_frames_per_row = MAX(1, src_image_width / g->width);
1353 anim_frames_per_col = MAX(1, src_image_height / g->height);
1356 g->src_image_width = src_image_width;
1357 g->src_image_height = src_image_height;
1360 /* correct x or y offset dependent of vertical or horizontal frame order */
1361 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1363 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1364 parameter[GFX_ARG_OFFSET] : g->height);
1365 anim_frames_per_line = anim_frames_per_col;
1367 else /* frames are ordered horizontally */
1369 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1370 parameter[GFX_ARG_OFFSET] : g->width);
1371 anim_frames_per_line = anim_frames_per_row;
1374 /* optionally, the x and y offset of frames can be specified directly */
1375 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1376 g->offset_x = parameter[GFX_ARG_XOFFSET];
1377 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1378 g->offset_y = parameter[GFX_ARG_YOFFSET];
1380 /* optionally, moving animations may have separate start and end graphics */
1381 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1383 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1384 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1386 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1387 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1388 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1389 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1390 else /* frames are ordered horizontally */
1391 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1392 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1394 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1395 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1396 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1397 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1398 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1400 /* optionally, the second movement tile can be specified as start tile */
1401 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1402 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1404 /* automatically determine correct number of frames, if not defined */
1405 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1406 g->anim_frames = parameter[GFX_ARG_FRAMES];
1407 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1408 g->anim_frames = anim_frames_per_row;
1409 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1410 g->anim_frames = anim_frames_per_col;
1414 if (g->anim_frames == 0) /* frames must be at least 1 */
1417 g->anim_frames_per_line =
1418 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1419 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1421 g->anim_delay = parameter[GFX_ARG_DELAY];
1422 if (g->anim_delay == 0) /* delay must be at least 1 */
1425 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1427 /* automatically determine correct start frame, if not defined */
1428 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1429 g->anim_start_frame = 0;
1430 else if (g->anim_mode & ANIM_REVERSE)
1431 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1433 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1435 /* animation synchronized with global frame counter, not move position */
1436 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1438 /* optional element for cloning crumble graphics */
1439 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1440 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1442 /* optional element for cloning digging graphics */
1443 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1444 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1446 /* optional border size for "crumbling" diggable graphics */
1447 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1448 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1450 /* used for global animations and player "boring" and "sleeping" actions */
1451 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1452 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1453 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1454 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1455 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1456 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1457 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1458 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1459 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1460 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1461 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1462 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1464 /* used for toon animations and global animations */
1465 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1466 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1467 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1468 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1469 g->direction = parameter[GFX_ARG_DIRECTION];
1470 g->position = parameter[GFX_ARG_POSITION];
1471 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1472 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1474 /* this is only used for drawing font characters */
1475 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1476 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1478 /* this is only used for drawing envelope graphics */
1479 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1481 /* used for toon animations and global animations */
1482 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1483 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1485 /* optional graphic for cloning all graphics settings */
1486 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1487 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1489 /* optional settings for drawing title screens and title messages */
1490 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1491 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1492 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1493 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1494 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1495 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1496 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1497 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1498 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1499 g->align = parameter[GFX_ARG_ALIGN];
1500 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1501 g->valign = parameter[GFX_ARG_VALIGN];
1502 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1503 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1505 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1506 g->class = parameter[GFX_ARG_CLASS];
1507 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1508 g->style = parameter[GFX_ARG_STYLE];
1510 /* this is only used for drawing menu buttons and text */
1511 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1512 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1513 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1514 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1517 static void set_graphic_parameters(int graphic)
1519 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1520 char **parameter_raw = image->parameter;
1521 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1522 int parameter[NUM_GFX_ARGS];
1525 /* if fallback to default artwork is done, also use the default parameters */
1526 if (image->fallback_to_default)
1527 parameter_raw = image->default_parameter;
1529 /* get integer values from string parameters */
1530 for (i = 0; i < NUM_GFX_ARGS; i++)
1531 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1532 image_config_suffix[i].token,
1533 image_config_suffix[i].type);
1535 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1537 UPDATE_BUSY_STATE();
1540 static void set_cloned_graphic_parameters(int graphic)
1542 int fallback_graphic = IMG_CHAR_EXCLAM;
1543 int max_num_images = getImageListSize();
1544 int clone_graphic = graphic_info[graphic].clone_from;
1545 int num_references_followed = 1;
1547 while (graphic_info[clone_graphic].clone_from != -1 &&
1548 num_references_followed < max_num_images)
1550 clone_graphic = graphic_info[clone_graphic].clone_from;
1552 num_references_followed++;
1555 if (num_references_followed >= max_num_images)
1557 Error(ERR_INFO_LINE, "-");
1558 Error(ERR_INFO, "warning: error found in config file:");
1559 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1560 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1561 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1562 Error(ERR_INFO, "custom graphic rejected for this element/action");
1564 if (graphic == fallback_graphic)
1565 Error(ERR_EXIT, "no fallback graphic available");
1567 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1568 Error(ERR_INFO_LINE, "-");
1570 graphic_info[graphic] = graphic_info[fallback_graphic];
1574 graphic_info[graphic] = graphic_info[clone_graphic];
1575 graphic_info[graphic].clone_from = clone_graphic;
1579 static void InitGraphicInfo()
1581 int fallback_graphic = IMG_CHAR_EXCLAM;
1582 int num_images = getImageListSize();
1585 /* use image size as default values for width and height for these images */
1586 static int full_size_graphics[] =
1589 IMG_GLOBAL_BORDER_MAIN,
1590 IMG_GLOBAL_BORDER_SCORES,
1591 IMG_GLOBAL_BORDER_EDITOR,
1592 IMG_GLOBAL_BORDER_PLAYING,
1595 IMG_BACKGROUND_ENVELOPE_1,
1596 IMG_BACKGROUND_ENVELOPE_2,
1597 IMG_BACKGROUND_ENVELOPE_3,
1598 IMG_BACKGROUND_ENVELOPE_4,
1599 IMG_BACKGROUND_REQUEST,
1602 IMG_BACKGROUND_TITLE_INITIAL,
1603 IMG_BACKGROUND_TITLE,
1604 IMG_BACKGROUND_MAIN,
1605 IMG_BACKGROUND_LEVELS,
1606 IMG_BACKGROUND_LEVELNR,
1607 IMG_BACKGROUND_SCORES,
1608 IMG_BACKGROUND_EDITOR,
1609 IMG_BACKGROUND_INFO,
1610 IMG_BACKGROUND_INFO_ELEMENTS,
1611 IMG_BACKGROUND_INFO_MUSIC,
1612 IMG_BACKGROUND_INFO_CREDITS,
1613 IMG_BACKGROUND_INFO_PROGRAM,
1614 IMG_BACKGROUND_INFO_VERSION,
1615 IMG_BACKGROUND_INFO_LEVELSET,
1616 IMG_BACKGROUND_SETUP,
1617 IMG_BACKGROUND_PLAYING,
1618 IMG_BACKGROUND_DOOR,
1619 IMG_BACKGROUND_TAPE,
1620 IMG_BACKGROUND_PANEL,
1621 IMG_BACKGROUND_PALETTE,
1622 IMG_BACKGROUND_TOOLBOX,
1624 IMG_TITLESCREEN_INITIAL_1,
1625 IMG_TITLESCREEN_INITIAL_2,
1626 IMG_TITLESCREEN_INITIAL_3,
1627 IMG_TITLESCREEN_INITIAL_4,
1628 IMG_TITLESCREEN_INITIAL_5,
1635 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1636 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1637 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1638 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1639 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1640 IMG_BACKGROUND_TITLEMESSAGE_1,
1641 IMG_BACKGROUND_TITLEMESSAGE_2,
1642 IMG_BACKGROUND_TITLEMESSAGE_3,
1643 IMG_BACKGROUND_TITLEMESSAGE_4,
1644 IMG_BACKGROUND_TITLEMESSAGE_5,
1649 checked_free(graphic_info);
1651 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1653 /* initialize "use_image_size" flag with default value */
1654 for (i = 0; i < num_images; i++)
1655 graphic_info[i].use_image_size = FALSE;
1657 /* initialize "use_image_size" flag from static configuration above */
1658 for (i = 0; full_size_graphics[i] != -1; i++)
1659 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1661 /* first set all graphic paramaters ... */
1662 for (i = 0; i < num_images; i++)
1663 set_graphic_parameters(i);
1665 /* ... then copy these parameters for cloned graphics */
1666 for (i = 0; i < num_images; i++)
1667 if (graphic_info[i].clone_from != -1)
1668 set_cloned_graphic_parameters(i);
1670 for (i = 0; i < num_images; i++)
1675 int first_frame, last_frame;
1676 int src_bitmap_width, src_bitmap_height;
1678 /* now check if no animation frames are outside of the loaded image */
1680 if (graphic_info[i].bitmap == NULL)
1681 continue; /* skip check for optional images that are undefined */
1683 /* get image size (this can differ from the standard element tile size!) */
1684 width = graphic_info[i].width;
1685 height = graphic_info[i].height;
1687 /* get final bitmap size (with scaling, but without small images) */
1688 src_bitmap_width = graphic_info[i].src_image_width;
1689 src_bitmap_height = graphic_info[i].src_image_height;
1691 /* check if first animation frame is inside specified bitmap */
1694 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1696 /* this avoids calculating wrong start position for out-of-bounds frame */
1697 src_x = graphic_info[i].src_x;
1698 src_y = graphic_info[i].src_y;
1700 if (src_x < 0 || src_y < 0 ||
1701 src_x + width > src_bitmap_width ||
1702 src_y + height > src_bitmap_height)
1704 Error(ERR_INFO_LINE, "-");
1705 Error(ERR_INFO, "warning: error found in config file:");
1706 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1707 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1708 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1709 Error(ERR_INFO, "- frame size: %d, %d", width, height);
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);
1738 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1740 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1741 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1742 Error(ERR_INFO, "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].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1788 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1794 InitGraphicCompatibilityInfo_Doors();
1797 static void InitElementSoundInfo()
1799 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1800 int num_property_mappings = getSoundListPropertyMappingSize();
1803 /* set values to -1 to identify later as "uninitialized" values */
1804 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1805 for (act = 0; act < NUM_ACTIONS; act++)
1806 element_info[i].sound[act] = -1;
1808 /* initialize element/sound mapping from static configuration */
1809 for (i = 0; element_to_sound[i].element > -1; i++)
1811 int element = element_to_sound[i].element;
1812 int action = element_to_sound[i].action;
1813 int sound = element_to_sound[i].sound;
1814 boolean is_class = element_to_sound[i].is_class;
1817 action = ACTION_DEFAULT;
1820 element_info[element].sound[action] = sound;
1822 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1823 if (strEqual(element_info[j].class_name,
1824 element_info[element].class_name))
1825 element_info[j].sound[action] = sound;
1828 /* initialize element class/sound mapping from dynamic configuration */
1829 for (i = 0; i < num_property_mappings; i++)
1831 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1832 int action = property_mapping[i].ext1_index;
1833 int sound = property_mapping[i].artwork_index;
1835 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1839 action = ACTION_DEFAULT;
1841 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1842 if (strEqual(element_info[j].class_name,
1843 element_info[element_class].class_name))
1844 element_info[j].sound[action] = sound;
1847 /* initialize element/sound mapping from dynamic configuration */
1848 for (i = 0; i < num_property_mappings; i++)
1850 int element = property_mapping[i].base_index;
1851 int action = property_mapping[i].ext1_index;
1852 int sound = property_mapping[i].artwork_index;
1854 if (element >= MAX_NUM_ELEMENTS)
1858 action = ACTION_DEFAULT;
1860 element_info[element].sound[action] = sound;
1863 /* now set all '-1' values to element specific default values */
1864 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1866 for (act = 0; act < NUM_ACTIONS; act++)
1868 /* generic default action sound (defined by "[default]" directive) */
1869 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1871 /* look for special default action sound (classic game specific) */
1872 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1873 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1874 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1875 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1876 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1877 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1879 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1880 /* !!! make this better !!! */
1881 if (i == EL_EMPTY_SPACE)
1882 default_action_sound = element_info[EL_DEFAULT].sound[act];
1884 /* no sound for this specific action -- use default action sound */
1885 if (element_info[i].sound[act] == -1)
1886 element_info[i].sound[act] = default_action_sound;
1890 /* copy sound settings to some elements that are only stored in level file
1891 in native R'n'D levels, but are used by game engine in native EM levels */
1892 for (i = 0; copy_properties[i][0] != -1; i++)
1893 for (j = 1; j <= 4; j++)
1894 for (act = 0; act < NUM_ACTIONS; act++)
1895 element_info[copy_properties[i][j]].sound[act] =
1896 element_info[copy_properties[i][0]].sound[act];
1899 static void InitGameModeSoundInfo()
1903 /* set values to -1 to identify later as "uninitialized" values */
1904 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1907 /* initialize gamemode/sound mapping from static configuration */
1908 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1910 int gamemode = gamemode_to_sound[i].gamemode;
1911 int sound = gamemode_to_sound[i].sound;
1914 gamemode = GAME_MODE_DEFAULT;
1916 menu.sound[gamemode] = sound;
1919 /* now set all '-1' values to levelset specific default values */
1920 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1921 if (menu.sound[i] == -1)
1922 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1925 static void set_sound_parameters(int sound, char **parameter_raw)
1927 int parameter[NUM_SND_ARGS];
1930 /* get integer values from string parameters */
1931 for (i = 0; i < NUM_SND_ARGS; i++)
1933 get_parameter_value(parameter_raw[i],
1934 sound_config_suffix[i].token,
1935 sound_config_suffix[i].type);
1937 /* explicit loop mode setting in configuration overrides default value */
1938 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1939 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1941 /* sound volume to change the original volume when loading the sound file */
1942 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1944 /* sound priority to give certain sounds a higher or lower priority */
1945 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1948 static void InitSoundInfo()
1950 int *sound_effect_properties;
1951 int num_sounds = getSoundListSize();
1954 checked_free(sound_info);
1956 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1957 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1959 /* initialize sound effect for all elements to "no sound" */
1960 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1961 for (j = 0; j < NUM_ACTIONS; j++)
1962 element_info[i].sound[j] = SND_UNDEFINED;
1964 for (i = 0; i < num_sounds; i++)
1966 struct FileInfo *sound = getSoundListEntry(i);
1967 int len_effect_text = strlen(sound->token);
1969 sound_effect_properties[i] = ACTION_OTHER;
1970 sound_info[i].loop = FALSE; /* default: play sound only once */
1972 /* determine all loop sounds and identify certain sound classes */
1974 for (j = 0; element_action_info[j].suffix; j++)
1976 int len_action_text = strlen(element_action_info[j].suffix);
1978 if (len_action_text < len_effect_text &&
1979 strEqual(&sound->token[len_effect_text - len_action_text],
1980 element_action_info[j].suffix))
1982 sound_effect_properties[i] = element_action_info[j].value;
1983 sound_info[i].loop = element_action_info[j].is_loop_sound;
1989 /* associate elements and some selected sound actions */
1991 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1993 if (element_info[j].class_name)
1995 int len_class_text = strlen(element_info[j].class_name);
1997 if (len_class_text + 1 < len_effect_text &&
1998 strncmp(sound->token,
1999 element_info[j].class_name, len_class_text) == 0 &&
2000 sound->token[len_class_text] == '.')
2002 int sound_action_value = sound_effect_properties[i];
2004 element_info[j].sound[sound_action_value] = i;
2009 set_sound_parameters(i, sound->parameter);
2012 free(sound_effect_properties);
2015 static void InitGameModeMusicInfo()
2017 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2018 int num_property_mappings = getMusicListPropertyMappingSize();
2019 int default_levelset_music = -1;
2022 /* set values to -1 to identify later as "uninitialized" values */
2023 for (i = 0; i < MAX_LEVELS; i++)
2024 levelset.music[i] = -1;
2025 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2028 /* initialize gamemode/music mapping from static configuration */
2029 for (i = 0; gamemode_to_music[i].music > -1; i++)
2031 int gamemode = gamemode_to_music[i].gamemode;
2032 int music = gamemode_to_music[i].music;
2035 gamemode = GAME_MODE_DEFAULT;
2037 menu.music[gamemode] = music;
2040 /* initialize gamemode/music mapping from dynamic configuration */
2041 for (i = 0; i < num_property_mappings; i++)
2043 int prefix = property_mapping[i].base_index;
2044 int gamemode = property_mapping[i].ext2_index;
2045 int level = property_mapping[i].ext3_index;
2046 int music = property_mapping[i].artwork_index;
2048 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2052 gamemode = GAME_MODE_DEFAULT;
2054 /* level specific music only allowed for in-game music */
2055 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2056 gamemode = GAME_MODE_PLAYING;
2061 default_levelset_music = music;
2064 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2065 levelset.music[level] = music;
2066 if (gamemode != GAME_MODE_PLAYING)
2067 menu.music[gamemode] = music;
2070 /* now set all '-1' values to menu specific default values */
2071 /* (undefined values of "levelset.music[]" might stay at "-1" to
2072 allow dynamic selection of music files from music directory!) */
2073 for (i = 0; i < MAX_LEVELS; i++)
2074 if (levelset.music[i] == -1)
2075 levelset.music[i] = default_levelset_music;
2076 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2077 if (menu.music[i] == -1)
2078 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2081 static void set_music_parameters(int music, char **parameter_raw)
2083 int parameter[NUM_MUS_ARGS];
2086 /* get integer values from string parameters */
2087 for (i = 0; i < NUM_MUS_ARGS; i++)
2089 get_parameter_value(parameter_raw[i],
2090 music_config_suffix[i].token,
2091 music_config_suffix[i].type);
2093 /* explicit loop mode setting in configuration overrides default value */
2094 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2095 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2098 static void InitMusicInfo()
2100 int num_music = getMusicListSize();
2103 checked_free(music_info);
2105 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2107 for (i = 0; i < num_music; i++)
2109 struct FileInfo *music = getMusicListEntry(i);
2110 int len_music_text = strlen(music->token);
2112 music_info[i].loop = TRUE; /* default: play music in loop mode */
2114 /* determine all loop music */
2116 for (j = 0; music_prefix_info[j].prefix; j++)
2118 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2120 if (len_prefix_text < len_music_text &&
2121 strncmp(music->token,
2122 music_prefix_info[j].prefix, len_prefix_text) == 0)
2124 music_info[i].loop = music_prefix_info[j].is_loop_music;
2130 set_music_parameters(i, music->parameter);
2134 static void ReinitializeGraphics()
2136 print_timestamp_init("ReinitializeGraphics");
2138 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2140 InitGraphicInfo(); /* graphic properties mapping */
2141 print_timestamp_time("InitGraphicInfo");
2142 InitElementGraphicInfo(); /* element game graphic mapping */
2143 print_timestamp_time("InitElementGraphicInfo");
2144 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2145 print_timestamp_time("InitElementSpecialGraphicInfo");
2147 InitElementSmallImages(); /* scale elements to all needed sizes */
2148 print_timestamp_time("InitElementSmallImages");
2149 InitScaledImages(); /* scale all other images, if needed */
2150 print_timestamp_time("InitScaledImages");
2151 InitBitmapPointers(); /* set standard size bitmap pointers */
2152 print_timestamp_time("InitBitmapPointers");
2153 InitFontGraphicInfo(); /* initialize text drawing functions */
2154 print_timestamp_time("InitFontGraphicInfo");
2155 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2156 print_timestamp_time("InitGlobalAnimGraphicInfo");
2158 InitImageTextures(); /* create textures for certain images */
2159 print_timestamp_time("InitImageTextures");
2161 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2162 print_timestamp_time("InitGraphicInfo_EM");
2164 InitGraphicCompatibilityInfo();
2165 print_timestamp_time("InitGraphicCompatibilityInfo");
2167 SetMainBackgroundImage(IMG_BACKGROUND);
2168 print_timestamp_time("SetMainBackgroundImage");
2169 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2170 print_timestamp_time("SetDoorBackgroundImage");
2173 print_timestamp_time("InitGadgets");
2175 print_timestamp_time("InitDoors");
2177 print_timestamp_done("ReinitializeGraphics");
2180 static void ReinitializeSounds()
2182 InitSoundInfo(); /* sound properties mapping */
2183 InitElementSoundInfo(); /* element game sound mapping */
2184 InitGameModeSoundInfo(); /* game mode sound mapping */
2185 InitGlobalAnimSoundInfo(); /* global animation sound settings */
2187 InitPlayLevelSound(); /* internal game sound settings */
2190 static void ReinitializeMusic()
2192 InitMusicInfo(); /* music properties mapping */
2193 InitGameModeMusicInfo(); /* game mode music mapping */
2194 InitGlobalAnimMusicInfo(); /* global animation music settings */
2197 static int get_special_property_bit(int element, int property_bit_nr)
2199 struct PropertyBitInfo
2205 static struct PropertyBitInfo pb_can_move_into_acid[] =
2207 /* the player may be able fall into acid when gravity is activated */
2212 { EL_SP_MURPHY, 0 },
2213 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2215 /* all elements that can move may be able to also move into acid */
2218 { EL_BUG_RIGHT, 1 },
2221 { EL_SPACESHIP, 2 },
2222 { EL_SPACESHIP_LEFT, 2 },
2223 { EL_SPACESHIP_RIGHT, 2 },
2224 { EL_SPACESHIP_UP, 2 },
2225 { EL_SPACESHIP_DOWN, 2 },
2226 { EL_BD_BUTTERFLY, 3 },
2227 { EL_BD_BUTTERFLY_LEFT, 3 },
2228 { EL_BD_BUTTERFLY_RIGHT, 3 },
2229 { EL_BD_BUTTERFLY_UP, 3 },
2230 { EL_BD_BUTTERFLY_DOWN, 3 },
2231 { EL_BD_FIREFLY, 4 },
2232 { EL_BD_FIREFLY_LEFT, 4 },
2233 { EL_BD_FIREFLY_RIGHT, 4 },
2234 { EL_BD_FIREFLY_UP, 4 },
2235 { EL_BD_FIREFLY_DOWN, 4 },
2237 { EL_YAMYAM_LEFT, 5 },
2238 { EL_YAMYAM_RIGHT, 5 },
2239 { EL_YAMYAM_UP, 5 },
2240 { EL_YAMYAM_DOWN, 5 },
2241 { EL_DARK_YAMYAM, 6 },
2244 { EL_PACMAN_LEFT, 8 },
2245 { EL_PACMAN_RIGHT, 8 },
2246 { EL_PACMAN_UP, 8 },
2247 { EL_PACMAN_DOWN, 8 },
2249 { EL_MOLE_LEFT, 9 },
2250 { EL_MOLE_RIGHT, 9 },
2252 { EL_MOLE_DOWN, 9 },
2256 { EL_SATELLITE, 13 },
2257 { EL_SP_SNIKSNAK, 14 },
2258 { EL_SP_ELECTRON, 15 },
2261 { EL_EMC_ANDROID, 18 },
2266 static struct PropertyBitInfo pb_dont_collide_with[] =
2268 { EL_SP_SNIKSNAK, 0 },
2269 { EL_SP_ELECTRON, 1 },
2277 struct PropertyBitInfo *pb_info;
2280 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2281 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2286 struct PropertyBitInfo *pb_info = NULL;
2289 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2290 if (pb_definition[i].bit_nr == property_bit_nr)
2291 pb_info = pb_definition[i].pb_info;
2293 if (pb_info == NULL)
2296 for (i = 0; pb_info[i].element != -1; i++)
2297 if (pb_info[i].element == element)
2298 return pb_info[i].bit_nr;
2303 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2304 boolean property_value)
2306 int bit_nr = get_special_property_bit(element, property_bit_nr);
2311 *bitfield |= (1 << bit_nr);
2313 *bitfield &= ~(1 << bit_nr);
2317 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2319 int bit_nr = get_special_property_bit(element, property_bit_nr);
2322 return ((*bitfield & (1 << bit_nr)) != 0);
2327 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2329 static int group_nr;
2330 static struct ElementGroupInfo *group;
2331 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2334 if (actual_group == NULL) /* not yet initialized */
2337 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2339 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2340 group_element - EL_GROUP_START + 1);
2342 /* replace element which caused too deep recursion by question mark */
2343 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2348 if (recursion_depth == 0) /* initialization */
2350 group = actual_group;
2351 group_nr = GROUP_NR(group_element);
2353 group->num_elements_resolved = 0;
2354 group->choice_pos = 0;
2356 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2357 element_info[i].in_group[group_nr] = FALSE;
2360 for (i = 0; i < actual_group->num_elements; i++)
2362 int element = actual_group->element[i];
2364 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2367 if (IS_GROUP_ELEMENT(element))
2368 ResolveGroupElementExt(element, recursion_depth + 1);
2371 group->element_resolved[group->num_elements_resolved++] = element;
2372 element_info[element].in_group[group_nr] = TRUE;
2377 void ResolveGroupElement(int group_element)
2379 ResolveGroupElementExt(group_element, 0);
2382 void InitElementPropertiesStatic()
2384 static boolean clipboard_elements_initialized = FALSE;
2386 static int ep_diggable[] =
2391 EL_SP_BUGGY_BASE_ACTIVATING,
2394 EL_INVISIBLE_SAND_ACTIVE,
2397 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2398 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2403 EL_SP_BUGGY_BASE_ACTIVE,
2410 static int ep_collectible_only[] =
2432 EL_DYNABOMB_INCREASE_NUMBER,
2433 EL_DYNABOMB_INCREASE_SIZE,
2434 EL_DYNABOMB_INCREASE_POWER,
2452 /* !!! handle separately !!! */
2453 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2459 static int ep_dont_run_into[] =
2461 /* same elements as in 'ep_dont_touch' */
2467 /* same elements as in 'ep_dont_collide_with' */
2479 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2484 EL_SP_BUGGY_BASE_ACTIVE,
2491 static int ep_dont_collide_with[] =
2493 /* same elements as in 'ep_dont_touch' */
2510 static int ep_dont_touch[] =
2520 static int ep_indestructible[] =
2524 EL_ACID_POOL_TOPLEFT,
2525 EL_ACID_POOL_TOPRIGHT,
2526 EL_ACID_POOL_BOTTOMLEFT,
2527 EL_ACID_POOL_BOTTOM,
2528 EL_ACID_POOL_BOTTOMRIGHT,
2529 EL_SP_HARDWARE_GRAY,
2530 EL_SP_HARDWARE_GREEN,
2531 EL_SP_HARDWARE_BLUE,
2533 EL_SP_HARDWARE_YELLOW,
2534 EL_SP_HARDWARE_BASE_1,
2535 EL_SP_HARDWARE_BASE_2,
2536 EL_SP_HARDWARE_BASE_3,
2537 EL_SP_HARDWARE_BASE_4,
2538 EL_SP_HARDWARE_BASE_5,
2539 EL_SP_HARDWARE_BASE_6,
2540 EL_INVISIBLE_STEELWALL,
2541 EL_INVISIBLE_STEELWALL_ACTIVE,
2542 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2543 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2544 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2545 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2546 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2547 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2548 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2549 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2550 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2551 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2552 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2553 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2555 EL_LIGHT_SWITCH_ACTIVE,
2556 EL_SIGN_EXCLAMATION,
2557 EL_SIGN_RADIOACTIVITY,
2564 EL_SIGN_ENTRY_FORBIDDEN,
2565 EL_SIGN_EMERGENCY_EXIT,
2573 EL_STEEL_EXIT_CLOSED,
2575 EL_STEEL_EXIT_OPENING,
2576 EL_STEEL_EXIT_CLOSING,
2577 EL_EM_STEEL_EXIT_CLOSED,
2578 EL_EM_STEEL_EXIT_OPEN,
2579 EL_EM_STEEL_EXIT_OPENING,
2580 EL_EM_STEEL_EXIT_CLOSING,
2581 EL_DC_STEELWALL_1_LEFT,
2582 EL_DC_STEELWALL_1_RIGHT,
2583 EL_DC_STEELWALL_1_TOP,
2584 EL_DC_STEELWALL_1_BOTTOM,
2585 EL_DC_STEELWALL_1_HORIZONTAL,
2586 EL_DC_STEELWALL_1_VERTICAL,
2587 EL_DC_STEELWALL_1_TOPLEFT,
2588 EL_DC_STEELWALL_1_TOPRIGHT,
2589 EL_DC_STEELWALL_1_BOTTOMLEFT,
2590 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2591 EL_DC_STEELWALL_1_TOPLEFT_2,
2592 EL_DC_STEELWALL_1_TOPRIGHT_2,
2593 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2594 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2595 EL_DC_STEELWALL_2_LEFT,
2596 EL_DC_STEELWALL_2_RIGHT,
2597 EL_DC_STEELWALL_2_TOP,
2598 EL_DC_STEELWALL_2_BOTTOM,
2599 EL_DC_STEELWALL_2_HORIZONTAL,
2600 EL_DC_STEELWALL_2_VERTICAL,
2601 EL_DC_STEELWALL_2_MIDDLE,
2602 EL_DC_STEELWALL_2_SINGLE,
2603 EL_STEELWALL_SLIPPERY,
2617 EL_GATE_1_GRAY_ACTIVE,
2618 EL_GATE_2_GRAY_ACTIVE,
2619 EL_GATE_3_GRAY_ACTIVE,
2620 EL_GATE_4_GRAY_ACTIVE,
2629 EL_EM_GATE_1_GRAY_ACTIVE,
2630 EL_EM_GATE_2_GRAY_ACTIVE,
2631 EL_EM_GATE_3_GRAY_ACTIVE,
2632 EL_EM_GATE_4_GRAY_ACTIVE,
2641 EL_EMC_GATE_5_GRAY_ACTIVE,
2642 EL_EMC_GATE_6_GRAY_ACTIVE,
2643 EL_EMC_GATE_7_GRAY_ACTIVE,
2644 EL_EMC_GATE_8_GRAY_ACTIVE,
2646 EL_DC_GATE_WHITE_GRAY,
2647 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2648 EL_DC_GATE_FAKE_GRAY,
2650 EL_SWITCHGATE_OPENING,
2651 EL_SWITCHGATE_CLOSED,
2652 EL_SWITCHGATE_CLOSING,
2653 EL_DC_SWITCHGATE_SWITCH_UP,
2654 EL_DC_SWITCHGATE_SWITCH_DOWN,
2656 EL_TIMEGATE_OPENING,
2658 EL_TIMEGATE_CLOSING,
2659 EL_DC_TIMEGATE_SWITCH,
2660 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2664 EL_TUBE_VERTICAL_LEFT,
2665 EL_TUBE_VERTICAL_RIGHT,
2666 EL_TUBE_HORIZONTAL_UP,
2667 EL_TUBE_HORIZONTAL_DOWN,
2672 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2673 EL_EXPANDABLE_STEELWALL_VERTICAL,
2674 EL_EXPANDABLE_STEELWALL_ANY,
2679 static int ep_slippery[] =
2693 EL_ROBOT_WHEEL_ACTIVE,
2699 EL_ACID_POOL_TOPLEFT,
2700 EL_ACID_POOL_TOPRIGHT,
2710 EL_STEELWALL_SLIPPERY,
2713 EL_EMC_WALL_SLIPPERY_1,
2714 EL_EMC_WALL_SLIPPERY_2,
2715 EL_EMC_WALL_SLIPPERY_3,
2716 EL_EMC_WALL_SLIPPERY_4,
2718 EL_EMC_MAGIC_BALL_ACTIVE,
2723 static int ep_can_change[] =
2728 static int ep_can_move[] =
2730 /* same elements as in 'pb_can_move_into_acid' */
2753 static int ep_can_fall[] =
2767 EL_QUICKSAND_FAST_FULL,
2769 EL_BD_MAGIC_WALL_FULL,
2770 EL_DC_MAGIC_WALL_FULL,
2784 static int ep_can_smash_player[] =
2810 static int ep_can_smash_enemies[] =
2819 static int ep_can_smash_everything[] =
2828 static int ep_explodes_by_fire[] =
2830 /* same elements as in 'ep_explodes_impact' */
2835 /* same elements as in 'ep_explodes_smashed' */
2845 EL_EM_DYNAMITE_ACTIVE,
2846 EL_DYNABOMB_PLAYER_1_ACTIVE,
2847 EL_DYNABOMB_PLAYER_2_ACTIVE,
2848 EL_DYNABOMB_PLAYER_3_ACTIVE,
2849 EL_DYNABOMB_PLAYER_4_ACTIVE,
2850 EL_DYNABOMB_INCREASE_NUMBER,
2851 EL_DYNABOMB_INCREASE_SIZE,
2852 EL_DYNABOMB_INCREASE_POWER,
2853 EL_SP_DISK_RED_ACTIVE,
2867 static int ep_explodes_smashed[] =
2869 /* same elements as in 'ep_explodes_impact' */
2883 static int ep_explodes_impact[] =
2892 static int ep_walkable_over[] =
2896 EL_SOKOBAN_FIELD_EMPTY,
2903 EL_EM_STEEL_EXIT_OPEN,
2904 EL_EM_STEEL_EXIT_OPENING,
2913 EL_GATE_1_GRAY_ACTIVE,
2914 EL_GATE_2_GRAY_ACTIVE,
2915 EL_GATE_3_GRAY_ACTIVE,
2916 EL_GATE_4_GRAY_ACTIVE,
2924 static int ep_walkable_inside[] =
2929 EL_TUBE_VERTICAL_LEFT,
2930 EL_TUBE_VERTICAL_RIGHT,
2931 EL_TUBE_HORIZONTAL_UP,
2932 EL_TUBE_HORIZONTAL_DOWN,
2941 static int ep_walkable_under[] =
2946 static int ep_passable_over[] =
2956 EL_EM_GATE_1_GRAY_ACTIVE,
2957 EL_EM_GATE_2_GRAY_ACTIVE,
2958 EL_EM_GATE_3_GRAY_ACTIVE,
2959 EL_EM_GATE_4_GRAY_ACTIVE,
2968 EL_EMC_GATE_5_GRAY_ACTIVE,
2969 EL_EMC_GATE_6_GRAY_ACTIVE,
2970 EL_EMC_GATE_7_GRAY_ACTIVE,
2971 EL_EMC_GATE_8_GRAY_ACTIVE,
2973 EL_DC_GATE_WHITE_GRAY,
2974 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2981 static int ep_passable_inside[] =
2987 EL_SP_PORT_HORIZONTAL,
2988 EL_SP_PORT_VERTICAL,
2990 EL_SP_GRAVITY_PORT_LEFT,
2991 EL_SP_GRAVITY_PORT_RIGHT,
2992 EL_SP_GRAVITY_PORT_UP,
2993 EL_SP_GRAVITY_PORT_DOWN,
2994 EL_SP_GRAVITY_ON_PORT_LEFT,
2995 EL_SP_GRAVITY_ON_PORT_RIGHT,
2996 EL_SP_GRAVITY_ON_PORT_UP,
2997 EL_SP_GRAVITY_ON_PORT_DOWN,
2998 EL_SP_GRAVITY_OFF_PORT_LEFT,
2999 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3000 EL_SP_GRAVITY_OFF_PORT_UP,
3001 EL_SP_GRAVITY_OFF_PORT_DOWN,
3006 static int ep_passable_under[] =
3011 static int ep_droppable[] =
3016 static int ep_explodes_1x1_old[] =
3021 static int ep_pushable[] =
3033 EL_SOKOBAN_FIELD_FULL,
3042 static int ep_explodes_cross_old[] =
3047 static int ep_protected[] =
3049 /* same elements as in 'ep_walkable_inside' */
3053 EL_TUBE_VERTICAL_LEFT,
3054 EL_TUBE_VERTICAL_RIGHT,
3055 EL_TUBE_HORIZONTAL_UP,
3056 EL_TUBE_HORIZONTAL_DOWN,
3062 /* same elements as in 'ep_passable_over' */
3071 EL_EM_GATE_1_GRAY_ACTIVE,
3072 EL_EM_GATE_2_GRAY_ACTIVE,
3073 EL_EM_GATE_3_GRAY_ACTIVE,
3074 EL_EM_GATE_4_GRAY_ACTIVE,
3083 EL_EMC_GATE_5_GRAY_ACTIVE,
3084 EL_EMC_GATE_6_GRAY_ACTIVE,
3085 EL_EMC_GATE_7_GRAY_ACTIVE,
3086 EL_EMC_GATE_8_GRAY_ACTIVE,
3088 EL_DC_GATE_WHITE_GRAY,
3089 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3093 /* same elements as in 'ep_passable_inside' */
3098 EL_SP_PORT_HORIZONTAL,
3099 EL_SP_PORT_VERTICAL,
3101 EL_SP_GRAVITY_PORT_LEFT,
3102 EL_SP_GRAVITY_PORT_RIGHT,
3103 EL_SP_GRAVITY_PORT_UP,
3104 EL_SP_GRAVITY_PORT_DOWN,
3105 EL_SP_GRAVITY_ON_PORT_LEFT,
3106 EL_SP_GRAVITY_ON_PORT_RIGHT,
3107 EL_SP_GRAVITY_ON_PORT_UP,
3108 EL_SP_GRAVITY_ON_PORT_DOWN,
3109 EL_SP_GRAVITY_OFF_PORT_LEFT,
3110 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3111 EL_SP_GRAVITY_OFF_PORT_UP,
3112 EL_SP_GRAVITY_OFF_PORT_DOWN,
3117 static int ep_throwable[] =
3122 static int ep_can_explode[] =
3124 /* same elements as in 'ep_explodes_impact' */
3129 /* same elements as in 'ep_explodes_smashed' */
3135 /* elements that can explode by explosion or by dragonfire */
3139 EL_EM_DYNAMITE_ACTIVE,
3140 EL_DYNABOMB_PLAYER_1_ACTIVE,
3141 EL_DYNABOMB_PLAYER_2_ACTIVE,
3142 EL_DYNABOMB_PLAYER_3_ACTIVE,
3143 EL_DYNABOMB_PLAYER_4_ACTIVE,
3144 EL_DYNABOMB_INCREASE_NUMBER,
3145 EL_DYNABOMB_INCREASE_SIZE,
3146 EL_DYNABOMB_INCREASE_POWER,
3147 EL_SP_DISK_RED_ACTIVE,
3155 /* elements that can explode only by explosion */
3161 static int ep_gravity_reachable[] =
3167 EL_INVISIBLE_SAND_ACTIVE,
3172 EL_SP_PORT_HORIZONTAL,
3173 EL_SP_PORT_VERTICAL,
3175 EL_SP_GRAVITY_PORT_LEFT,
3176 EL_SP_GRAVITY_PORT_RIGHT,
3177 EL_SP_GRAVITY_PORT_UP,
3178 EL_SP_GRAVITY_PORT_DOWN,
3179 EL_SP_GRAVITY_ON_PORT_LEFT,
3180 EL_SP_GRAVITY_ON_PORT_RIGHT,
3181 EL_SP_GRAVITY_ON_PORT_UP,
3182 EL_SP_GRAVITY_ON_PORT_DOWN,
3183 EL_SP_GRAVITY_OFF_PORT_LEFT,
3184 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3185 EL_SP_GRAVITY_OFF_PORT_UP,
3186 EL_SP_GRAVITY_OFF_PORT_DOWN,
3192 static int ep_player[] =
3199 EL_SOKOBAN_FIELD_PLAYER,
3205 static int ep_can_pass_magic_wall[] =
3219 static int ep_can_pass_dc_magic_wall[] =
3235 static int ep_switchable[] =
3239 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3240 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3241 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3242 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3243 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3244 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3245 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3246 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3247 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3248 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3249 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3250 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3251 EL_SWITCHGATE_SWITCH_UP,
3252 EL_SWITCHGATE_SWITCH_DOWN,
3253 EL_DC_SWITCHGATE_SWITCH_UP,
3254 EL_DC_SWITCHGATE_SWITCH_DOWN,
3256 EL_LIGHT_SWITCH_ACTIVE,
3258 EL_DC_TIMEGATE_SWITCH,
3259 EL_BALLOON_SWITCH_LEFT,
3260 EL_BALLOON_SWITCH_RIGHT,
3261 EL_BALLOON_SWITCH_UP,
3262 EL_BALLOON_SWITCH_DOWN,
3263 EL_BALLOON_SWITCH_ANY,
3264 EL_BALLOON_SWITCH_NONE,
3267 EL_EMC_MAGIC_BALL_SWITCH,
3268 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3273 static int ep_bd_element[] =
3307 static int ep_sp_element[] =
3309 /* should always be valid */
3312 /* standard classic Supaplex elements */
3319 EL_SP_HARDWARE_GRAY,
3327 EL_SP_GRAVITY_PORT_RIGHT,
3328 EL_SP_GRAVITY_PORT_DOWN,
3329 EL_SP_GRAVITY_PORT_LEFT,
3330 EL_SP_GRAVITY_PORT_UP,
3335 EL_SP_PORT_VERTICAL,
3336 EL_SP_PORT_HORIZONTAL,
3342 EL_SP_HARDWARE_BASE_1,
3343 EL_SP_HARDWARE_GREEN,
3344 EL_SP_HARDWARE_BLUE,
3346 EL_SP_HARDWARE_YELLOW,
3347 EL_SP_HARDWARE_BASE_2,
3348 EL_SP_HARDWARE_BASE_3,
3349 EL_SP_HARDWARE_BASE_4,
3350 EL_SP_HARDWARE_BASE_5,
3351 EL_SP_HARDWARE_BASE_6,
3355 /* additional elements that appeared in newer Supaplex levels */
3358 /* additional gravity port elements (not switching, but setting gravity) */
3359 EL_SP_GRAVITY_ON_PORT_LEFT,
3360 EL_SP_GRAVITY_ON_PORT_RIGHT,
3361 EL_SP_GRAVITY_ON_PORT_UP,
3362 EL_SP_GRAVITY_ON_PORT_DOWN,
3363 EL_SP_GRAVITY_OFF_PORT_LEFT,
3364 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3365 EL_SP_GRAVITY_OFF_PORT_UP,
3366 EL_SP_GRAVITY_OFF_PORT_DOWN,
3368 /* more than one Murphy in a level results in an inactive clone */
3371 /* runtime Supaplex elements */
3372 EL_SP_DISK_RED_ACTIVE,
3373 EL_SP_TERMINAL_ACTIVE,
3374 EL_SP_BUGGY_BASE_ACTIVATING,
3375 EL_SP_BUGGY_BASE_ACTIVE,
3382 static int ep_sb_element[] =
3387 EL_SOKOBAN_FIELD_EMPTY,
3388 EL_SOKOBAN_FIELD_FULL,
3389 EL_SOKOBAN_FIELD_PLAYER,
3394 EL_INVISIBLE_STEELWALL,
3399 static int ep_gem[] =
3411 static int ep_food_dark_yamyam[] =
3439 static int ep_food_penguin[] =
3453 static int ep_food_pig[] =
3465 static int ep_historic_wall[] =
3476 EL_GATE_1_GRAY_ACTIVE,
3477 EL_GATE_2_GRAY_ACTIVE,
3478 EL_GATE_3_GRAY_ACTIVE,
3479 EL_GATE_4_GRAY_ACTIVE,
3488 EL_EM_GATE_1_GRAY_ACTIVE,
3489 EL_EM_GATE_2_GRAY_ACTIVE,
3490 EL_EM_GATE_3_GRAY_ACTIVE,
3491 EL_EM_GATE_4_GRAY_ACTIVE,
3498 EL_EXPANDABLE_WALL_HORIZONTAL,
3499 EL_EXPANDABLE_WALL_VERTICAL,
3500 EL_EXPANDABLE_WALL_ANY,
3501 EL_EXPANDABLE_WALL_GROWING,
3502 EL_BD_EXPANDABLE_WALL,
3509 EL_SP_HARDWARE_GRAY,
3510 EL_SP_HARDWARE_GREEN,
3511 EL_SP_HARDWARE_BLUE,
3513 EL_SP_HARDWARE_YELLOW,
3514 EL_SP_HARDWARE_BASE_1,
3515 EL_SP_HARDWARE_BASE_2,
3516 EL_SP_HARDWARE_BASE_3,
3517 EL_SP_HARDWARE_BASE_4,
3518 EL_SP_HARDWARE_BASE_5,
3519 EL_SP_HARDWARE_BASE_6,
3521 EL_SP_TERMINAL_ACTIVE,
3524 EL_INVISIBLE_STEELWALL,
3525 EL_INVISIBLE_STEELWALL_ACTIVE,
3527 EL_INVISIBLE_WALL_ACTIVE,
3528 EL_STEELWALL_SLIPPERY,
3545 static int ep_historic_solid[] =
3549 EL_EXPANDABLE_WALL_HORIZONTAL,
3550 EL_EXPANDABLE_WALL_VERTICAL,
3551 EL_EXPANDABLE_WALL_ANY,
3552 EL_BD_EXPANDABLE_WALL,
3565 EL_QUICKSAND_FILLING,
3566 EL_QUICKSAND_EMPTYING,
3568 EL_MAGIC_WALL_ACTIVE,
3569 EL_MAGIC_WALL_EMPTYING,
3570 EL_MAGIC_WALL_FILLING,
3574 EL_BD_MAGIC_WALL_ACTIVE,
3575 EL_BD_MAGIC_WALL_EMPTYING,
3576 EL_BD_MAGIC_WALL_FULL,
3577 EL_BD_MAGIC_WALL_FILLING,
3578 EL_BD_MAGIC_WALL_DEAD,
3587 EL_SP_TERMINAL_ACTIVE,
3591 EL_INVISIBLE_WALL_ACTIVE,
3592 EL_SWITCHGATE_SWITCH_UP,
3593 EL_SWITCHGATE_SWITCH_DOWN,
3594 EL_DC_SWITCHGATE_SWITCH_UP,
3595 EL_DC_SWITCHGATE_SWITCH_DOWN,
3597 EL_TIMEGATE_SWITCH_ACTIVE,
3598 EL_DC_TIMEGATE_SWITCH,
3599 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3611 /* the following elements are a direct copy of "indestructible" elements,
3612 except "EL_ACID", which is "indestructible", but not "solid"! */
3617 EL_ACID_POOL_TOPLEFT,
3618 EL_ACID_POOL_TOPRIGHT,
3619 EL_ACID_POOL_BOTTOMLEFT,
3620 EL_ACID_POOL_BOTTOM,
3621 EL_ACID_POOL_BOTTOMRIGHT,
3622 EL_SP_HARDWARE_GRAY,
3623 EL_SP_HARDWARE_GREEN,
3624 EL_SP_HARDWARE_BLUE,
3626 EL_SP_HARDWARE_YELLOW,
3627 EL_SP_HARDWARE_BASE_1,
3628 EL_SP_HARDWARE_BASE_2,
3629 EL_SP_HARDWARE_BASE_3,
3630 EL_SP_HARDWARE_BASE_4,
3631 EL_SP_HARDWARE_BASE_5,
3632 EL_SP_HARDWARE_BASE_6,
3633 EL_INVISIBLE_STEELWALL,
3634 EL_INVISIBLE_STEELWALL_ACTIVE,
3635 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3636 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3637 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3638 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3639 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3640 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3641 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3642 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3643 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3644 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3645 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3646 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3648 EL_LIGHT_SWITCH_ACTIVE,
3649 EL_SIGN_EXCLAMATION,
3650 EL_SIGN_RADIOACTIVITY,
3657 EL_SIGN_ENTRY_FORBIDDEN,
3658 EL_SIGN_EMERGENCY_EXIT,
3666 EL_STEEL_EXIT_CLOSED,
3668 EL_DC_STEELWALL_1_LEFT,
3669 EL_DC_STEELWALL_1_RIGHT,
3670 EL_DC_STEELWALL_1_TOP,
3671 EL_DC_STEELWALL_1_BOTTOM,
3672 EL_DC_STEELWALL_1_HORIZONTAL,
3673 EL_DC_STEELWALL_1_VERTICAL,
3674 EL_DC_STEELWALL_1_TOPLEFT,
3675 EL_DC_STEELWALL_1_TOPRIGHT,
3676 EL_DC_STEELWALL_1_BOTTOMLEFT,
3677 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3678 EL_DC_STEELWALL_1_TOPLEFT_2,
3679 EL_DC_STEELWALL_1_TOPRIGHT_2,
3680 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3681 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3682 EL_DC_STEELWALL_2_LEFT,
3683 EL_DC_STEELWALL_2_RIGHT,
3684 EL_DC_STEELWALL_2_TOP,
3685 EL_DC_STEELWALL_2_BOTTOM,
3686 EL_DC_STEELWALL_2_HORIZONTAL,
3687 EL_DC_STEELWALL_2_VERTICAL,
3688 EL_DC_STEELWALL_2_MIDDLE,
3689 EL_DC_STEELWALL_2_SINGLE,
3690 EL_STEELWALL_SLIPPERY,
3704 EL_GATE_1_GRAY_ACTIVE,
3705 EL_GATE_2_GRAY_ACTIVE,
3706 EL_GATE_3_GRAY_ACTIVE,
3707 EL_GATE_4_GRAY_ACTIVE,
3716 EL_EM_GATE_1_GRAY_ACTIVE,
3717 EL_EM_GATE_2_GRAY_ACTIVE,
3718 EL_EM_GATE_3_GRAY_ACTIVE,
3719 EL_EM_GATE_4_GRAY_ACTIVE,
3721 EL_SWITCHGATE_OPENING,
3722 EL_SWITCHGATE_CLOSED,
3723 EL_SWITCHGATE_CLOSING,
3725 EL_TIMEGATE_OPENING,
3727 EL_TIMEGATE_CLOSING,
3731 EL_TUBE_VERTICAL_LEFT,
3732 EL_TUBE_VERTICAL_RIGHT,
3733 EL_TUBE_HORIZONTAL_UP,
3734 EL_TUBE_HORIZONTAL_DOWN,
3743 static int ep_classic_enemy[] =
3760 static int ep_belt[] =
3762 EL_CONVEYOR_BELT_1_LEFT,
3763 EL_CONVEYOR_BELT_1_MIDDLE,
3764 EL_CONVEYOR_BELT_1_RIGHT,
3765 EL_CONVEYOR_BELT_2_LEFT,
3766 EL_CONVEYOR_BELT_2_MIDDLE,
3767 EL_CONVEYOR_BELT_2_RIGHT,
3768 EL_CONVEYOR_BELT_3_LEFT,
3769 EL_CONVEYOR_BELT_3_MIDDLE,
3770 EL_CONVEYOR_BELT_3_RIGHT,
3771 EL_CONVEYOR_BELT_4_LEFT,
3772 EL_CONVEYOR_BELT_4_MIDDLE,
3773 EL_CONVEYOR_BELT_4_RIGHT,
3778 static int ep_belt_active[] =
3780 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3781 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3782 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3783 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3784 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3785 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3786 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3787 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3788 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3789 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3790 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3791 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3796 static int ep_belt_switch[] =
3798 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3799 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3800 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3801 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3802 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3803 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3804 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3805 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3806 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3807 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3808 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3809 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3814 static int ep_tube[] =
3821 EL_TUBE_HORIZONTAL_UP,
3822 EL_TUBE_HORIZONTAL_DOWN,
3824 EL_TUBE_VERTICAL_LEFT,
3825 EL_TUBE_VERTICAL_RIGHT,
3831 static int ep_acid_pool[] =
3833 EL_ACID_POOL_TOPLEFT,
3834 EL_ACID_POOL_TOPRIGHT,
3835 EL_ACID_POOL_BOTTOMLEFT,
3836 EL_ACID_POOL_BOTTOM,
3837 EL_ACID_POOL_BOTTOMRIGHT,
3842 static int ep_keygate[] =
3852 EL_GATE_1_GRAY_ACTIVE,
3853 EL_GATE_2_GRAY_ACTIVE,
3854 EL_GATE_3_GRAY_ACTIVE,
3855 EL_GATE_4_GRAY_ACTIVE,
3864 EL_EM_GATE_1_GRAY_ACTIVE,
3865 EL_EM_GATE_2_GRAY_ACTIVE,
3866 EL_EM_GATE_3_GRAY_ACTIVE,
3867 EL_EM_GATE_4_GRAY_ACTIVE,
3876 EL_EMC_GATE_5_GRAY_ACTIVE,
3877 EL_EMC_GATE_6_GRAY_ACTIVE,
3878 EL_EMC_GATE_7_GRAY_ACTIVE,
3879 EL_EMC_GATE_8_GRAY_ACTIVE,
3881 EL_DC_GATE_WHITE_GRAY,
3882 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3887 static int ep_amoeboid[] =
3899 static int ep_amoebalive[] =
3910 static int ep_has_editor_content[] =
3916 EL_SOKOBAN_FIELD_PLAYER,
3933 static int ep_can_turn_each_move[] =
3935 /* !!! do something with this one !!! */
3939 static int ep_can_grow[] =
3953 static int ep_active_bomb[] =
3956 EL_EM_DYNAMITE_ACTIVE,
3957 EL_DYNABOMB_PLAYER_1_ACTIVE,
3958 EL_DYNABOMB_PLAYER_2_ACTIVE,
3959 EL_DYNABOMB_PLAYER_3_ACTIVE,
3960 EL_DYNABOMB_PLAYER_4_ACTIVE,
3961 EL_SP_DISK_RED_ACTIVE,
3966 static int ep_inactive[] =
3976 EL_QUICKSAND_FAST_EMPTY,
3999 EL_GATE_1_GRAY_ACTIVE,
4000 EL_GATE_2_GRAY_ACTIVE,
4001 EL_GATE_3_GRAY_ACTIVE,
4002 EL_GATE_4_GRAY_ACTIVE,
4011 EL_EM_GATE_1_GRAY_ACTIVE,
4012 EL_EM_GATE_2_GRAY_ACTIVE,
4013 EL_EM_GATE_3_GRAY_ACTIVE,
4014 EL_EM_GATE_4_GRAY_ACTIVE,
4023 EL_EMC_GATE_5_GRAY_ACTIVE,
4024 EL_EMC_GATE_6_GRAY_ACTIVE,
4025 EL_EMC_GATE_7_GRAY_ACTIVE,
4026 EL_EMC_GATE_8_GRAY_ACTIVE,
4028 EL_DC_GATE_WHITE_GRAY,
4029 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4030 EL_DC_GATE_FAKE_GRAY,
4033 EL_INVISIBLE_STEELWALL,
4041 EL_WALL_EMERALD_YELLOW,
4042 EL_DYNABOMB_INCREASE_NUMBER,
4043 EL_DYNABOMB_INCREASE_SIZE,
4044 EL_DYNABOMB_INCREASE_POWER,
4048 EL_SOKOBAN_FIELD_EMPTY,
4049 EL_SOKOBAN_FIELD_FULL,
4050 EL_WALL_EMERALD_RED,
4051 EL_WALL_EMERALD_PURPLE,
4052 EL_ACID_POOL_TOPLEFT,
4053 EL_ACID_POOL_TOPRIGHT,
4054 EL_ACID_POOL_BOTTOMLEFT,
4055 EL_ACID_POOL_BOTTOM,
4056 EL_ACID_POOL_BOTTOMRIGHT,
4060 EL_BD_MAGIC_WALL_DEAD,
4062 EL_DC_MAGIC_WALL_DEAD,
4063 EL_AMOEBA_TO_DIAMOND,
4071 EL_SP_GRAVITY_PORT_RIGHT,
4072 EL_SP_GRAVITY_PORT_DOWN,
4073 EL_SP_GRAVITY_PORT_LEFT,
4074 EL_SP_GRAVITY_PORT_UP,
4075 EL_SP_PORT_HORIZONTAL,
4076 EL_SP_PORT_VERTICAL,
4087 EL_SP_HARDWARE_GRAY,
4088 EL_SP_HARDWARE_GREEN,
4089 EL_SP_HARDWARE_BLUE,
4091 EL_SP_HARDWARE_YELLOW,
4092 EL_SP_HARDWARE_BASE_1,
4093 EL_SP_HARDWARE_BASE_2,
4094 EL_SP_HARDWARE_BASE_3,
4095 EL_SP_HARDWARE_BASE_4,
4096 EL_SP_HARDWARE_BASE_5,
4097 EL_SP_HARDWARE_BASE_6,
4098 EL_SP_GRAVITY_ON_PORT_LEFT,
4099 EL_SP_GRAVITY_ON_PORT_RIGHT,
4100 EL_SP_GRAVITY_ON_PORT_UP,
4101 EL_SP_GRAVITY_ON_PORT_DOWN,
4102 EL_SP_GRAVITY_OFF_PORT_LEFT,
4103 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4104 EL_SP_GRAVITY_OFF_PORT_UP,
4105 EL_SP_GRAVITY_OFF_PORT_DOWN,
4106 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4107 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4108 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4109 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4110 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4111 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4112 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4113 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4114 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4115 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4116 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4117 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4118 EL_SIGN_EXCLAMATION,
4119 EL_SIGN_RADIOACTIVITY,
4126 EL_SIGN_ENTRY_FORBIDDEN,
4127 EL_SIGN_EMERGENCY_EXIT,
4135 EL_DC_STEELWALL_1_LEFT,
4136 EL_DC_STEELWALL_1_RIGHT,
4137 EL_DC_STEELWALL_1_TOP,
4138 EL_DC_STEELWALL_1_BOTTOM,
4139 EL_DC_STEELWALL_1_HORIZONTAL,
4140 EL_DC_STEELWALL_1_VERTICAL,
4141 EL_DC_STEELWALL_1_TOPLEFT,
4142 EL_DC_STEELWALL_1_TOPRIGHT,
4143 EL_DC_STEELWALL_1_BOTTOMLEFT,
4144 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4145 EL_DC_STEELWALL_1_TOPLEFT_2,
4146 EL_DC_STEELWALL_1_TOPRIGHT_2,
4147 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4148 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4149 EL_DC_STEELWALL_2_LEFT,
4150 EL_DC_STEELWALL_2_RIGHT,
4151 EL_DC_STEELWALL_2_TOP,
4152 EL_DC_STEELWALL_2_BOTTOM,
4153 EL_DC_STEELWALL_2_HORIZONTAL,
4154 EL_DC_STEELWALL_2_VERTICAL,
4155 EL_DC_STEELWALL_2_MIDDLE,
4156 EL_DC_STEELWALL_2_SINGLE,
4157 EL_STEELWALL_SLIPPERY,
4162 EL_EMC_WALL_SLIPPERY_1,
4163 EL_EMC_WALL_SLIPPERY_2,
4164 EL_EMC_WALL_SLIPPERY_3,
4165 EL_EMC_WALL_SLIPPERY_4,
4186 static int ep_em_slippery_wall[] =
4191 static int ep_gfx_crumbled[] =
4202 static int ep_editor_cascade_active[] =
4204 EL_INTERNAL_CASCADE_BD_ACTIVE,
4205 EL_INTERNAL_CASCADE_EM_ACTIVE,
4206 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4207 EL_INTERNAL_CASCADE_RND_ACTIVE,
4208 EL_INTERNAL_CASCADE_SB_ACTIVE,
4209 EL_INTERNAL_CASCADE_SP_ACTIVE,
4210 EL_INTERNAL_CASCADE_DC_ACTIVE,
4211 EL_INTERNAL_CASCADE_DX_ACTIVE,
4212 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4213 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4214 EL_INTERNAL_CASCADE_CE_ACTIVE,
4215 EL_INTERNAL_CASCADE_GE_ACTIVE,
4216 EL_INTERNAL_CASCADE_REF_ACTIVE,
4217 EL_INTERNAL_CASCADE_USER_ACTIVE,
4218 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4223 static int ep_editor_cascade_inactive[] =
4225 EL_INTERNAL_CASCADE_BD,
4226 EL_INTERNAL_CASCADE_EM,
4227 EL_INTERNAL_CASCADE_EMC,
4228 EL_INTERNAL_CASCADE_RND,
4229 EL_INTERNAL_CASCADE_SB,
4230 EL_INTERNAL_CASCADE_SP,
4231 EL_INTERNAL_CASCADE_DC,
4232 EL_INTERNAL_CASCADE_DX,
4233 EL_INTERNAL_CASCADE_CHARS,
4234 EL_INTERNAL_CASCADE_STEEL_CHARS,
4235 EL_INTERNAL_CASCADE_CE,
4236 EL_INTERNAL_CASCADE_GE,
4237 EL_INTERNAL_CASCADE_REF,
4238 EL_INTERNAL_CASCADE_USER,
4239 EL_INTERNAL_CASCADE_DYNAMIC,
4244 static int ep_obsolete[] =
4248 EL_EM_KEY_1_FILE_OBSOLETE,
4249 EL_EM_KEY_2_FILE_OBSOLETE,
4250 EL_EM_KEY_3_FILE_OBSOLETE,
4251 EL_EM_KEY_4_FILE_OBSOLETE,
4252 EL_ENVELOPE_OBSOLETE,
4261 } element_properties[] =
4263 { ep_diggable, EP_DIGGABLE },
4264 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4265 { ep_dont_run_into, EP_DONT_RUN_INTO },
4266 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4267 { ep_dont_touch, EP_DONT_TOUCH },
4268 { ep_indestructible, EP_INDESTRUCTIBLE },
4269 { ep_slippery, EP_SLIPPERY },
4270 { ep_can_change, EP_CAN_CHANGE },
4271 { ep_can_move, EP_CAN_MOVE },
4272 { ep_can_fall, EP_CAN_FALL },
4273 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4274 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4275 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4276 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4277 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4278 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4279 { ep_walkable_over, EP_WALKABLE_OVER },
4280 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4281 { ep_walkable_under, EP_WALKABLE_UNDER },
4282 { ep_passable_over, EP_PASSABLE_OVER },
4283 { ep_passable_inside, EP_PASSABLE_INSIDE },
4284 { ep_passable_under, EP_PASSABLE_UNDER },
4285 { ep_droppable, EP_DROPPABLE },
4286 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4287 { ep_pushable, EP_PUSHABLE },
4288 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4289 { ep_protected, EP_PROTECTED },
4290 { ep_throwable, EP_THROWABLE },
4291 { ep_can_explode, EP_CAN_EXPLODE },
4292 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4294 { ep_player, EP_PLAYER },
4295 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4296 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4297 { ep_switchable, EP_SWITCHABLE },
4298 { ep_bd_element, EP_BD_ELEMENT },
4299 { ep_sp_element, EP_SP_ELEMENT },
4300 { ep_sb_element, EP_SB_ELEMENT },
4302 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4303 { ep_food_penguin, EP_FOOD_PENGUIN },
4304 { ep_food_pig, EP_FOOD_PIG },
4305 { ep_historic_wall, EP_HISTORIC_WALL },
4306 { ep_historic_solid, EP_HISTORIC_SOLID },
4307 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4308 { ep_belt, EP_BELT },
4309 { ep_belt_active, EP_BELT_ACTIVE },
4310 { ep_belt_switch, EP_BELT_SWITCH },
4311 { ep_tube, EP_TUBE },
4312 { ep_acid_pool, EP_ACID_POOL },
4313 { ep_keygate, EP_KEYGATE },
4314 { ep_amoeboid, EP_AMOEBOID },
4315 { ep_amoebalive, EP_AMOEBALIVE },
4316 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4317 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4318 { ep_can_grow, EP_CAN_GROW },
4319 { ep_active_bomb, EP_ACTIVE_BOMB },
4320 { ep_inactive, EP_INACTIVE },
4322 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4324 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4326 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4327 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4329 { ep_obsolete, EP_OBSOLETE },
4336 /* always start with reliable default values (element has no properties) */
4337 /* (but never initialize clipboard elements after the very first time) */
4338 /* (to be able to use clipboard elements between several levels) */
4339 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4340 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4341 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4342 SET_PROPERTY(i, j, FALSE);
4344 /* set all base element properties from above array definitions */
4345 for (i = 0; element_properties[i].elements != NULL; i++)
4346 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4347 SET_PROPERTY((element_properties[i].elements)[j],
4348 element_properties[i].property, TRUE);
4350 /* copy properties to some elements that are only stored in level file */
4351 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4352 for (j = 0; copy_properties[j][0] != -1; j++)
4353 if (HAS_PROPERTY(copy_properties[j][0], i))
4354 for (k = 1; k <= 4; k++)
4355 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4357 /* set static element properties that are not listed in array definitions */
4358 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4359 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4361 clipboard_elements_initialized = TRUE;
4364 void InitElementPropertiesEngine(int engine_version)
4366 static int no_wall_properties[] =
4369 EP_COLLECTIBLE_ONLY,
4371 EP_DONT_COLLIDE_WITH,
4374 EP_CAN_SMASH_PLAYER,
4375 EP_CAN_SMASH_ENEMIES,
4376 EP_CAN_SMASH_EVERYTHING,
4381 EP_FOOD_DARK_YAMYAM,
4397 /* important: after initialization in InitElementPropertiesStatic(), the
4398 elements are not again initialized to a default value; therefore all
4399 changes have to make sure that they leave the element with a defined
4400 property (which means that conditional property changes must be set to
4401 a reliable default value before) */
4403 /* resolve group elements */
4404 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4405 ResolveGroupElement(EL_GROUP_START + i);
4407 /* set all special, combined or engine dependent element properties */
4408 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4410 /* do not change (already initialized) clipboard elements here */
4411 if (IS_CLIPBOARD_ELEMENT(i))
4414 /* ---------- INACTIVE ------------------------------------------------- */
4415 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4416 i <= EL_CHAR_END) ||
4417 (i >= EL_STEEL_CHAR_START &&
4418 i <= EL_STEEL_CHAR_END)));
4420 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4421 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4422 IS_WALKABLE_INSIDE(i) ||
4423 IS_WALKABLE_UNDER(i)));
4425 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4426 IS_PASSABLE_INSIDE(i) ||
4427 IS_PASSABLE_UNDER(i)));
4429 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4430 IS_PASSABLE_OVER(i)));
4432 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4433 IS_PASSABLE_INSIDE(i)));
4435 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4436 IS_PASSABLE_UNDER(i)));
4438 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4441 /* ---------- COLLECTIBLE ---------------------------------------------- */
4442 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4446 /* ---------- SNAPPABLE ------------------------------------------------ */
4447 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4448 IS_COLLECTIBLE(i) ||
4452 /* ---------- WALL ----------------------------------------------------- */
4453 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4455 for (j = 0; no_wall_properties[j] != -1; j++)
4456 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4457 i >= EL_FIRST_RUNTIME_UNREAL)
4458 SET_PROPERTY(i, EP_WALL, FALSE);
4460 if (IS_HISTORIC_WALL(i))
4461 SET_PROPERTY(i, EP_WALL, TRUE);
4463 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4464 if (engine_version < VERSION_IDENT(2,2,0,0))
4465 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4467 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4469 !IS_COLLECTIBLE(i)));
4471 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4472 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4473 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4475 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4476 IS_INDESTRUCTIBLE(i)));
4478 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4480 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4481 else if (engine_version < VERSION_IDENT(2,2,0,0))
4482 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4484 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4488 if (IS_CUSTOM_ELEMENT(i))
4490 /* these are additional properties which are initially false when set */
4492 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4494 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4495 if (DONT_COLLIDE_WITH(i))
4496 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4498 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4499 if (CAN_SMASH_EVERYTHING(i))
4500 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4501 if (CAN_SMASH_ENEMIES(i))
4502 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4505 /* ---------- CAN_SMASH ------------------------------------------------ */
4506 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4507 CAN_SMASH_ENEMIES(i) ||
4508 CAN_SMASH_EVERYTHING(i)));
4510 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4511 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4512 EXPLODES_BY_FIRE(i)));
4514 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4515 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4516 EXPLODES_SMASHED(i)));
4518 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4519 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4520 EXPLODES_IMPACT(i)));
4522 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4523 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4525 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4526 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4527 i == EL_BLACK_ORB));
4529 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4530 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4532 IS_CUSTOM_ELEMENT(i)));
4534 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4535 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4536 i == EL_SP_ELECTRON));
4538 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4539 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4540 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4541 getMoveIntoAcidProperty(&level, i));
4543 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4544 if (MAYBE_DONT_COLLIDE_WITH(i))
4545 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4546 getDontCollideWithProperty(&level, i));
4548 /* ---------- SP_PORT -------------------------------------------------- */
4549 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4550 IS_PASSABLE_INSIDE(i)));
4552 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4553 for (j = 0; j < level.num_android_clone_elements; j++)
4554 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4556 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4558 /* ---------- CAN_CHANGE ----------------------------------------------- */
4559 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4560 for (j = 0; j < element_info[i].num_change_pages; j++)
4561 if (element_info[i].change_page[j].can_change)
4562 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4564 /* ---------- HAS_ACTION ----------------------------------------------- */
4565 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4566 for (j = 0; j < element_info[i].num_change_pages; j++)
4567 if (element_info[i].change_page[j].has_action)
4568 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4570 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4571 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4574 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4575 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4576 element_info[i].crumbled[ACTION_DEFAULT] !=
4577 element_info[i].graphic[ACTION_DEFAULT]);
4579 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4580 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4581 IS_EDITOR_CASCADE_INACTIVE(i)));
4584 /* dynamically adjust element properties according to game engine version */
4586 static int ep_em_slippery_wall[] =
4591 EL_EXPANDABLE_WALL_HORIZONTAL,
4592 EL_EXPANDABLE_WALL_VERTICAL,
4593 EL_EXPANDABLE_WALL_ANY,
4594 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4595 EL_EXPANDABLE_STEELWALL_VERTICAL,
4596 EL_EXPANDABLE_STEELWALL_ANY,
4597 EL_EXPANDABLE_STEELWALL_GROWING,
4601 static int ep_em_explodes_by_fire[] =
4604 EL_EM_DYNAMITE_ACTIVE,
4609 /* special EM style gems behaviour */
4610 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4611 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4612 level.em_slippery_gems);
4614 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4615 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4616 (level.em_slippery_gems &&
4617 engine_version > VERSION_IDENT(2,0,1,0)));
4619 /* special EM style explosion behaviour regarding chain reactions */
4620 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4621 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4622 level.em_explodes_by_fire);
4625 /* this is needed because some graphics depend on element properties */
4626 if (game_status == GAME_MODE_PLAYING)
4627 InitElementGraphicInfo();
4630 void InitElementPropertiesAfterLoading(int engine_version)
4634 /* set some other uninitialized values of custom elements in older levels */
4635 if (engine_version < VERSION_IDENT(3,1,0,0))
4637 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4639 int element = EL_CUSTOM_START + i;
4641 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4643 element_info[element].explosion_delay = 17;
4644 element_info[element].ignition_delay = 8;
4649 void InitElementPropertiesGfxElement()
4653 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4655 struct ElementInfo *ei = &element_info[i];
4657 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4661 static void InitGlobal()
4666 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4668 /* check if element_name_info entry defined for each element in "main.h" */
4669 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4670 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4672 element_info[i].token_name = element_name_info[i].token_name;
4673 element_info[i].class_name = element_name_info[i].class_name;
4674 element_info[i].editor_description= element_name_info[i].editor_description;
4677 /* create hash from image config list */
4678 image_config_hash = newSetupFileHash();
4679 for (i = 0; image_config[i].token != NULL; i++)
4680 setHashEntry(image_config_hash,
4681 image_config[i].token,
4682 image_config[i].value);
4684 /* create hash from element token list */
4685 element_token_hash = newSetupFileHash();
4686 for (i = 0; element_name_info[i].token_name != NULL; i++)
4687 setHashEntry(element_token_hash,
4688 element_name_info[i].token_name,
4691 /* create hash from graphic token list */
4692 graphic_token_hash = newSetupFileHash();
4693 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4694 if (strSuffix(image_config[i].value, ".png") ||
4695 strSuffix(image_config[i].value, ".pcx") ||
4696 strSuffix(image_config[i].value, ".wav") ||
4697 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4698 setHashEntry(graphic_token_hash,
4699 image_config[i].token,
4700 int2str(graphic++, 0));
4702 /* create hash from font token list */
4703 font_token_hash = newSetupFileHash();
4704 for (i = 0; font_info[i].token_name != NULL; i++)
4705 setHashEntry(font_token_hash,
4706 font_info[i].token_name,
4709 /* set default filenames for all cloned graphics in static configuration */
4710 for (i = 0; image_config[i].token != NULL; i++)
4712 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4714 char *token = image_config[i].token;
4715 char *token_clone_from = getStringCat2(token, ".clone_from");
4716 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4718 if (token_cloned != NULL)
4720 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4722 if (value_cloned != NULL)
4724 /* set default filename in static configuration */
4725 image_config[i].value = value_cloned;
4727 /* set default filename in image config hash */
4728 setHashEntry(image_config_hash, token, value_cloned);
4732 free(token_clone_from);
4736 /* always start with reliable default values (all elements) */
4737 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4738 ActiveElement[i] = i;
4740 /* now add all entries that have an active state (active elements) */
4741 for (i = 0; element_with_active_state[i].element != -1; i++)
4743 int element = element_with_active_state[i].element;
4744 int element_active = element_with_active_state[i].element_active;
4746 ActiveElement[element] = element_active;
4749 /* always start with reliable default values (all buttons) */
4750 for (i = 0; i < NUM_IMAGE_FILES; i++)
4751 ActiveButton[i] = i;
4753 /* now add all entries that have an active state (active buttons) */
4754 for (i = 0; button_with_active_state[i].button != -1; i++)
4756 int button = button_with_active_state[i].button;
4757 int button_active = button_with_active_state[i].button_active;
4759 ActiveButton[button] = button_active;
4762 /* always start with reliable default values (all fonts) */
4763 for (i = 0; i < NUM_FONTS; i++)
4766 /* now add all entries that have an active state (active fonts) */
4767 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4769 int font = font_with_active_state[i].font_nr;
4770 int font_active = font_with_active_state[i].font_nr_active;
4772 ActiveFont[font] = font_active;
4775 global.autoplay_leveldir = NULL;
4776 global.convert_leveldir = NULL;
4777 global.create_images_dir = NULL;
4779 global.frames_per_second = 0;
4781 global.border_status = GAME_MODE_LOADING;
4782 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4784 global.use_envelope_request = FALSE;
4787 void Execute_Command(char *command)
4791 if (strEqual(command, "print graphicsinfo.conf"))
4793 Print("# You can configure additional/alternative image files here.\n");
4794 Print("# (The entries below are default and therefore commented out.)\n");
4796 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4798 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4801 for (i = 0; image_config[i].token != NULL; i++)
4802 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4803 image_config[i].value));
4807 else if (strEqual(command, "print soundsinfo.conf"))
4809 Print("# You can configure additional/alternative sound files here.\n");
4810 Print("# (The entries below are default and therefore commented out.)\n");
4812 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4814 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4817 for (i = 0; sound_config[i].token != NULL; i++)
4818 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4819 sound_config[i].value));
4823 else if (strEqual(command, "print musicinfo.conf"))
4825 Print("# You can configure additional/alternative music files here.\n");
4826 Print("# (The entries below are default and therefore commented out.)\n");
4828 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4830 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4833 for (i = 0; music_config[i].token != NULL; i++)
4834 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4835 music_config[i].value));
4839 else if (strEqual(command, "print editorsetup.conf"))
4841 Print("# You can configure your personal editor element list here.\n");
4842 Print("# (The entries below are default and therefore commented out.)\n");
4845 /* this is needed to be able to check element list for cascade elements */
4846 InitElementPropertiesStatic();
4847 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4849 PrintEditorElementList();
4853 else if (strEqual(command, "print helpanim.conf"))
4855 Print("# You can configure different element help animations here.\n");
4856 Print("# (The entries below are default and therefore commented out.)\n");
4859 for (i = 0; helpanim_config[i].token != NULL; i++)
4861 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4862 helpanim_config[i].value));
4864 if (strEqual(helpanim_config[i].token, "end"))
4870 else if (strEqual(command, "print helptext.conf"))
4872 Print("# You can configure different element help text here.\n");
4873 Print("# (The entries below are default and therefore commented out.)\n");
4876 for (i = 0; helptext_config[i].token != NULL; i++)
4877 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4878 helptext_config[i].value));
4882 else if (strPrefix(command, "dump level "))
4884 char *filename = &command[11];
4886 if (!fileExists(filename))
4887 Error(ERR_EXIT, "cannot open file '%s'", filename);
4889 LoadLevelFromFilename(&level, filename);
4894 else if (strPrefix(command, "dump tape "))
4896 char *filename = &command[10];
4898 if (!fileExists(filename))
4899 Error(ERR_EXIT, "cannot open file '%s'", filename);
4901 LoadTapeFromFilename(filename);
4906 else if (strPrefix(command, "autotest ") ||
4907 strPrefix(command, "autoplay ") ||
4908 strPrefix(command, "autoffwd ") ||
4909 strPrefix(command, "autowarp "))
4911 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4913 global.autoplay_mode =
4914 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
4915 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
4916 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
4917 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
4918 AUTOPLAY_MODE_NONE);
4920 while (*str_ptr != '\0') /* continue parsing string */
4922 /* cut leading whitespace from string, replace it by string terminator */
4923 while (*str_ptr == ' ' || *str_ptr == '\t')
4926 if (*str_ptr == '\0') /* end of string reached */
4929 if (global.autoplay_leveldir == NULL) /* read level set string */
4931 global.autoplay_leveldir = str_ptr;
4932 global.autoplay_all = TRUE; /* default: play all tapes */
4934 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4935 global.autoplay_level[i] = FALSE;
4937 else /* read level number string */
4939 int level_nr = atoi(str_ptr); /* get level_nr value */
4941 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4942 global.autoplay_level[level_nr] = TRUE;
4944 global.autoplay_all = FALSE;
4947 /* advance string pointer to the next whitespace (or end of string) */
4948 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4952 else if (strPrefix(command, "convert "))
4954 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4955 char *str_ptr = strchr(str_copy, ' ');
4957 global.convert_leveldir = str_copy;
4958 global.convert_level_nr = -1;
4960 if (str_ptr != NULL) /* level number follows */
4962 *str_ptr++ = '\0'; /* terminate leveldir string */
4963 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4966 else if (strPrefix(command, "create images "))
4968 global.create_images_dir = getStringCopy(&command[14]);
4970 if (access(global.create_images_dir, W_OK) != 0)
4971 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4972 global.create_images_dir);
4974 else if (strPrefix(command, "create CE image "))
4976 CreateCustomElementImages(&command[16]);
4982 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4986 static void InitSetup()
4988 LoadSetup(); /* global setup info */
4990 /* set some options from setup file */
4992 if (setup.options.verbose)
4993 options.verbose = TRUE;
4996 static void InitGameInfo()
4998 game.restart_level = FALSE;
5001 static void InitPlayerInfo()
5005 /* choose default local player */
5006 local_player = &stored_player[0];
5008 for (i = 0; i < MAX_PLAYERS; i++)
5009 stored_player[i].connected = FALSE;
5011 local_player->connected = TRUE;
5014 static void InitArtworkInfo()
5019 static char *get_string_in_brackets(char *string)
5021 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5023 sprintf(string_in_brackets, "[%s]", string);
5025 return string_in_brackets;
5028 static char *get_level_id_suffix(int id_nr)
5030 char *id_suffix = checked_malloc(1 + 3 + 1);
5032 if (id_nr < 0 || id_nr > 999)
5035 sprintf(id_suffix, ".%03d", id_nr);
5040 static void InitArtworkConfig()
5042 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5044 NUM_GLOBAL_ANIM_TOKENS + 1];
5045 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5046 NUM_GLOBAL_ANIM_TOKENS + 1];
5047 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5048 NUM_GLOBAL_ANIM_TOKENS + 1];
5049 static char *action_id_suffix[NUM_ACTIONS + 1];
5050 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5051 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5052 static char *level_id_suffix[MAX_LEVELS + 1];
5053 static char *dummy[1] = { NULL };
5054 static char *ignore_generic_tokens[] =
5060 static char **ignore_image_tokens;
5061 static char **ignore_sound_tokens;
5062 static char **ignore_music_tokens;
5063 int num_ignore_generic_tokens;
5064 int num_ignore_image_tokens;
5065 int num_ignore_sound_tokens;
5066 int num_ignore_music_tokens;
5069 /* dynamically determine list of generic tokens to be ignored */
5070 num_ignore_generic_tokens = 0;
5071 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5072 num_ignore_generic_tokens++;
5074 /* dynamically determine list of image tokens to be ignored */
5075 num_ignore_image_tokens = num_ignore_generic_tokens;
5076 for (i = 0; image_config_vars[i].token != NULL; i++)
5077 num_ignore_image_tokens++;
5078 ignore_image_tokens =
5079 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5080 for (i = 0; i < num_ignore_generic_tokens; i++)
5081 ignore_image_tokens[i] = ignore_generic_tokens[i];
5082 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5083 ignore_image_tokens[num_ignore_generic_tokens + i] =
5084 image_config_vars[i].token;
5085 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5087 /* dynamically determine list of sound tokens to be ignored */
5088 num_ignore_sound_tokens = num_ignore_generic_tokens;
5089 ignore_sound_tokens =
5090 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5091 for (i = 0; i < num_ignore_generic_tokens; i++)
5092 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5093 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5095 /* dynamically determine list of music tokens to be ignored */
5096 num_ignore_music_tokens = num_ignore_generic_tokens;
5097 ignore_music_tokens =
5098 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5099 for (i = 0; i < num_ignore_generic_tokens; i++)
5100 ignore_music_tokens[i] = ignore_generic_tokens[i];
5101 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5103 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5104 image_id_prefix[i] = element_info[i].token_name;
5105 for (i = 0; i < NUM_FONTS; i++)
5106 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5107 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5108 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5109 global_anim_info[i].token_name;
5110 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5112 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5113 sound_id_prefix[i] = element_info[i].token_name;
5114 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5115 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5116 get_string_in_brackets(element_info[i].class_name);
5117 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5118 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5119 global_anim_info[i].token_name;
5120 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5122 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5123 music_id_prefix[i] = music_prefix_info[i].prefix;
5124 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5125 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5126 global_anim_info[i].token_name;
5127 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5129 for (i = 0; i < NUM_ACTIONS; i++)
5130 action_id_suffix[i] = element_action_info[i].suffix;
5131 action_id_suffix[NUM_ACTIONS] = NULL;
5133 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5134 direction_id_suffix[i] = element_direction_info[i].suffix;
5135 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5137 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5138 special_id_suffix[i] = special_suffix_info[i].suffix;
5139 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5141 for (i = 0; i < MAX_LEVELS; i++)
5142 level_id_suffix[i] = get_level_id_suffix(i);
5143 level_id_suffix[MAX_LEVELS] = NULL;
5145 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5146 image_id_prefix, action_id_suffix, direction_id_suffix,
5147 special_id_suffix, ignore_image_tokens);
5148 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5149 sound_id_prefix, action_id_suffix, dummy,
5150 special_id_suffix, ignore_sound_tokens);
5151 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5152 music_id_prefix, action_id_suffix, special_id_suffix,
5153 level_id_suffix, ignore_music_tokens);
5156 static void InitMixer()
5163 void InitGfxBuffers()
5165 static int win_xsize_last = -1;
5166 static int win_ysize_last = -1;
5168 /* create additional image buffers for double-buffering and cross-fading */
5170 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5172 /* used to temporarily store the backbuffer -- only re-create if changed */
5173 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5174 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5176 win_xsize_last = WIN_XSIZE;
5177 win_ysize_last = WIN_YSIZE;
5180 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5181 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5182 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5183 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5185 /* initialize screen properties */
5186 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5187 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5189 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5190 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5191 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5192 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5193 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5194 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5196 /* required if door size definitions have changed */
5197 InitGraphicCompatibilityInfo_Doors();
5199 InitGfxBuffers_EM();
5200 InitGfxBuffers_SP();
5205 struct GraphicInfo *graphic_info_last = graphic_info;
5206 char *filename_font_initial = NULL;
5207 char *filename_anim_initial = NULL;
5208 Bitmap *bitmap_font_initial = NULL;
5212 /* determine settings for initial font (for displaying startup messages) */
5213 for (i = 0; image_config[i].token != NULL; i++)
5215 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5217 char font_token[128];
5220 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5221 len_font_token = strlen(font_token);
5223 if (strEqual(image_config[i].token, font_token))
5224 filename_font_initial = image_config[i].value;
5225 else if (strlen(image_config[i].token) > len_font_token &&
5226 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5228 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5229 font_initial[j].src_x = atoi(image_config[i].value);
5230 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5231 font_initial[j].src_y = atoi(image_config[i].value);
5232 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5233 font_initial[j].width = atoi(image_config[i].value);
5234 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5235 font_initial[j].height = atoi(image_config[i].value);
5240 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5242 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5243 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5246 if (filename_font_initial == NULL) /* should not happen */
5247 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5250 InitGfxCustomArtworkInfo();
5251 InitGfxOtherSettings();
5253 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5255 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5256 font_initial[j].bitmap = bitmap_font_initial;
5258 InitFontGraphicInfo();
5260 font_height = getFontHeight(FC_RED);
5262 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5263 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5264 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5267 DrawInitText("Loading graphics", 120, FC_GREEN);
5269 /* initialize settings for busy animation with default values */
5270 int parameter[NUM_GFX_ARGS];
5271 for (i = 0; i < NUM_GFX_ARGS; i++)
5272 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5273 image_config_suffix[i].token,
5274 image_config_suffix[i].type);
5276 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5277 int len_anim_token = strlen(anim_token);
5279 /* read settings for busy animation from default custom artwork config */
5280 char *gfx_config_filename = getPath3(options.graphics_directory,
5282 GRAPHICSINFO_FILENAME);
5284 if (fileExists(gfx_config_filename))
5286 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5288 if (setup_file_hash)
5290 char *filename = getHashEntry(setup_file_hash, anim_token);
5294 filename_anim_initial = getStringCopy(filename);
5296 for (j = 0; image_config_suffix[j].token != NULL; j++)
5298 int type = image_config_suffix[j].type;
5299 char *suffix = image_config_suffix[j].token;
5300 char *token = getStringCat2(anim_token, suffix);
5301 char *value = getHashEntry(setup_file_hash, token);
5303 checked_free(token);
5306 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5310 freeSetupFileHash(setup_file_hash);
5314 if (filename_anim_initial == NULL)
5316 /* read settings for busy animation from static default artwork config */
5317 for (i = 0; image_config[i].token != NULL; i++)
5319 if (strEqual(image_config[i].token, anim_token))
5320 filename_anim_initial = getStringCopy(image_config[i].value);
5321 else if (strlen(image_config[i].token) > len_anim_token &&
5322 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5324 for (j = 0; image_config_suffix[j].token != NULL; j++)
5326 if (strEqual(&image_config[i].token[len_anim_token],
5327 image_config_suffix[j].token))
5329 get_graphic_parameter_value(image_config[i].value,
5330 image_config_suffix[j].token,
5331 image_config_suffix[j].type);
5337 if (filename_anim_initial == NULL) /* should not happen */
5338 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5340 anim_initial.bitmaps =
5341 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5343 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5344 LoadCustomImage(filename_anim_initial);
5346 checked_free(filename_anim_initial);
5348 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5350 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5352 graphic_info = graphic_info_last;
5354 init.busy.width = anim_initial.width;
5355 init.busy.height = anim_initial.height;
5357 InitMenuDesignSettings_Static();
5359 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5360 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5361 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5363 gfx.fade_border_source_status = global.border_status;
5364 gfx.fade_border_target_status = global.border_status;
5365 gfx.masked_border_bitmap_ptr = backbuffer;
5367 /* use copy of busy animation to prevent change while reloading artwork */
5371 void InitGfxBackground()
5373 fieldbuffer = bitmap_db_field;
5374 SetDrawtoField(DRAW_TO_BACKBUFFER);
5376 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5378 redraw_mask = REDRAW_ALL;
5381 static void InitLevelInfo()
5383 LoadLevelInfo(); /* global level info */
5384 LoadLevelSetup_LastSeries(); /* last played series info */
5385 LoadLevelSetup_SeriesInfo(); /* last played level info */
5387 if (global.autoplay_leveldir &&
5388 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5390 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5391 global.autoplay_leveldir);
5392 if (leveldir_current == NULL)
5393 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5397 static void InitLevelArtworkInfo()
5399 LoadLevelArtworkInfo();
5402 static void InitImages()
5404 print_timestamp_init("InitImages");
5407 printf("::: leveldir_current->identifier == '%s'\n",
5408 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5409 printf("::: leveldir_current->graphics_path == '%s'\n",
5410 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5411 printf("::: leveldir_current->graphics_set == '%s'\n",
5412 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5413 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5414 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5417 setLevelArtworkDir(artwork.gfx_first);
5420 printf("::: leveldir_current->identifier == '%s'\n",
5421 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5422 printf("::: leveldir_current->graphics_path == '%s'\n",
5423 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5424 printf("::: leveldir_current->graphics_set == '%s'\n",
5425 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5426 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5427 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5431 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5432 leveldir_current->identifier,
5433 artwork.gfx_current_identifier,
5434 artwork.gfx_current->identifier,
5435 leveldir_current->graphics_set,
5436 leveldir_current->graphics_path);
5439 UPDATE_BUSY_STATE();
5441 ReloadCustomImages();
5442 print_timestamp_time("ReloadCustomImages");
5444 UPDATE_BUSY_STATE();
5446 LoadCustomElementDescriptions();
5447 print_timestamp_time("LoadCustomElementDescriptions");
5449 UPDATE_BUSY_STATE();
5451 LoadMenuDesignSettings();
5452 print_timestamp_time("LoadMenuDesignSettings");
5454 UPDATE_BUSY_STATE();
5456 ReinitializeGraphics();
5457 print_timestamp_time("ReinitializeGraphics");
5459 LoadMenuDesignSettings_AfterGraphics();
5460 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5462 UPDATE_BUSY_STATE();
5464 print_timestamp_done("InitImages");
5467 static void InitSound(char *identifier)
5469 print_timestamp_init("InitSound");
5471 if (identifier == NULL)
5472 identifier = artwork.snd_current->identifier;
5474 /* set artwork path to send it to the sound server process */
5475 setLevelArtworkDir(artwork.snd_first);
5477 InitReloadCustomSounds(identifier);
5478 print_timestamp_time("InitReloadCustomSounds");
5480 ReinitializeSounds();
5481 print_timestamp_time("ReinitializeSounds");
5483 print_timestamp_done("InitSound");
5486 static void InitMusic(char *identifier)
5488 print_timestamp_init("InitMusic");
5490 if (identifier == NULL)
5491 identifier = artwork.mus_current->identifier;
5493 /* set artwork path to send it to the sound server process */
5494 setLevelArtworkDir(artwork.mus_first);
5496 InitReloadCustomMusic(identifier);
5497 print_timestamp_time("InitReloadCustomMusic");
5499 ReinitializeMusic();
5500 print_timestamp_time("ReinitializeMusic");
5502 print_timestamp_done("InitMusic");
5505 static void InitArtworkDone()
5507 InitGlobalAnimations();
5510 void InitNetworkServer()
5512 #if defined(NETWORK_AVALIABLE)
5516 if (!options.network)
5519 #if defined(NETWORK_AVALIABLE)
5520 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5522 if (!ConnectToServer(options.server_host, options.server_port))
5523 Error(ERR_EXIT, "cannot connect to network game server");
5525 SendToServer_PlayerName(setup.player_name);
5526 SendToServer_ProtocolVersion();
5529 SendToServer_NrWanted(nr_wanted);
5533 static boolean CheckArtworkConfigForCustomElements(char *filename)
5535 SetupFileHash *setup_file_hash;
5536 boolean redefined_ce_found = FALSE;
5538 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5540 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5542 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5544 char *token = HASH_ITERATION_TOKEN(itr);
5546 if (strPrefix(token, "custom_"))
5548 redefined_ce_found = TRUE;
5553 END_HASH_ITERATION(setup_file_hash, itr)
5555 freeSetupFileHash(setup_file_hash);
5558 return redefined_ce_found;
5561 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5563 char *filename_base, *filename_local;
5564 boolean redefined_ce_found = FALSE;
5566 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5569 printf("::: leveldir_current->identifier == '%s'\n",
5570 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5571 printf("::: leveldir_current->graphics_path == '%s'\n",
5572 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5573 printf("::: leveldir_current->graphics_set == '%s'\n",
5574 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5575 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5576 leveldir_current == NULL ? "[NULL]" :
5577 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5580 /* first look for special artwork configured in level series config */
5581 filename_base = getCustomArtworkLevelConfigFilename(type);
5584 printf("::: filename_base == '%s'\n", filename_base);
5587 if (fileExists(filename_base))
5588 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5590 filename_local = getCustomArtworkConfigFilename(type);
5593 printf("::: filename_local == '%s'\n", filename_local);
5596 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5597 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5600 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5603 return redefined_ce_found;
5606 static void InitOverrideArtwork()
5608 boolean redefined_ce_found = FALSE;
5610 /* to check if this level set redefines any CEs, do not use overriding */
5611 gfx.override_level_graphics = FALSE;
5612 gfx.override_level_sounds = FALSE;
5613 gfx.override_level_music = FALSE;
5615 /* now check if this level set has definitions for custom elements */
5616 if (setup.override_level_graphics == AUTO ||
5617 setup.override_level_sounds == AUTO ||
5618 setup.override_level_music == AUTO)
5619 redefined_ce_found =
5620 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5621 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5622 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5625 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5628 if (redefined_ce_found)
5630 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5631 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5632 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5633 gfx.override_level_music = (setup.override_level_music == TRUE);
5637 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5638 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5639 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5640 gfx.override_level_music = (setup.override_level_music != FALSE);
5644 printf("::: => %d, %d, %d\n",
5645 gfx.override_level_graphics,
5646 gfx.override_level_sounds,
5647 gfx.override_level_music);
5651 static char *getNewArtworkIdentifier(int type)
5653 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5654 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5655 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5656 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5657 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5658 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5659 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5660 char *leveldir_identifier = leveldir_current->identifier;
5661 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5662 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5663 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5664 char *artwork_current_identifier;
5665 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5667 /* leveldir_current may be invalid (level group, parent link) */
5668 if (!validLevelSeries(leveldir_current))
5671 /* 1st step: determine artwork set to be activated in descending order:
5672 --------------------------------------------------------------------
5673 1. setup artwork (when configured to override everything else)
5674 2. artwork set configured in "levelinfo.conf" of current level set
5675 (artwork in level directory will have priority when loading later)
5676 3. artwork in level directory (stored in artwork sub-directory)
5677 4. setup artwork (currently configured in setup menu) */
5679 if (setup_override_artwork)
5680 artwork_current_identifier = setup_artwork_set;
5681 else if (leveldir_artwork_set != NULL)
5682 artwork_current_identifier = leveldir_artwork_set;
5683 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5684 artwork_current_identifier = leveldir_identifier;
5686 artwork_current_identifier = setup_artwork_set;
5689 /* 2nd step: check if it is really needed to reload artwork set
5690 ------------------------------------------------------------ */
5692 /* ---------- reload if level set and also artwork set has changed ------- */
5693 if (leveldir_current_identifier[type] != leveldir_identifier &&
5694 (last_has_level_artwork_set[type] || has_level_artwork_set))
5695 artwork_new_identifier = artwork_current_identifier;
5697 leveldir_current_identifier[type] = leveldir_identifier;
5698 last_has_level_artwork_set[type] = has_level_artwork_set;
5700 /* ---------- reload if "override artwork" setting has changed ----------- */
5701 if (last_override_level_artwork[type] != setup_override_artwork)
5702 artwork_new_identifier = artwork_current_identifier;
5704 last_override_level_artwork[type] = setup_override_artwork;
5706 /* ---------- reload if current artwork identifier has changed ----------- */
5707 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5708 artwork_current_identifier))
5709 artwork_new_identifier = artwork_current_identifier;
5711 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5713 /* ---------- do not reload directly after starting ---------------------- */
5714 if (!initialized[type])
5715 artwork_new_identifier = NULL;
5717 initialized[type] = TRUE;
5719 return artwork_new_identifier;
5722 void ReloadCustomArtwork(int force_reload)
5724 int last_game_status = game_status; /* save current game status */
5725 char *gfx_new_identifier;
5726 char *snd_new_identifier;
5727 char *mus_new_identifier;
5728 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5729 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5730 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5731 boolean reload_needed;
5733 InitOverrideArtwork();
5735 force_reload_gfx |= AdjustGraphicsForEMC();
5737 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5738 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5739 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5741 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5742 snd_new_identifier != NULL || force_reload_snd ||
5743 mus_new_identifier != NULL || force_reload_mus);
5748 print_timestamp_init("ReloadCustomArtwork");
5750 SetGameStatus(GAME_MODE_LOADING);
5752 FadeOut(REDRAW_ALL);
5754 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5755 print_timestamp_time("ClearRectangle");
5759 if (gfx_new_identifier != NULL || force_reload_gfx)
5762 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5763 artwork.gfx_current_identifier,
5765 artwork.gfx_current->identifier,
5766 leveldir_current->graphics_set);
5770 print_timestamp_time("InitImages");
5773 if (snd_new_identifier != NULL || force_reload_snd)
5775 InitSound(snd_new_identifier);
5776 print_timestamp_time("InitSound");
5779 if (mus_new_identifier != NULL || force_reload_mus)
5781 InitMusic(mus_new_identifier);
5782 print_timestamp_time("InitMusic");
5787 SetGameStatus(last_game_status); /* restore current game status */
5789 init_last = init; /* switch to new busy animation */
5791 FadeOut(REDRAW_ALL);
5793 RedrawGlobalBorder();
5795 /* force redraw of (open or closed) door graphics */
5796 SetDoorState(DOOR_OPEN_ALL);
5797 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5799 FadeSetEnterScreen();
5800 FadeSkipNextFadeOut();
5802 print_timestamp_done("ReloadCustomArtwork");
5804 LimitScreenUpdates(FALSE);
5807 void KeyboardAutoRepeatOffUnlessAutoplay()
5809 if (global.autoplay_leveldir == NULL)
5810 KeyboardAutoRepeatOff();
5813 void DisplayExitMessage(char *format, va_list ap)
5815 // check if draw buffer and fonts for exit message are already available
5816 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5819 int font_1 = FC_RED;
5820 int font_2 = FC_YELLOW;
5821 int font_3 = FC_BLUE;
5822 int font_width = getFontWidth(font_2);
5823 int font_height = getFontHeight(font_2);
5826 int sxsize = WIN_XSIZE - 2 * sx;
5827 int sysize = WIN_YSIZE - 2 * sy;
5828 int line_length = sxsize / font_width;
5829 int max_lines = sysize / font_height;
5830 int num_lines_printed;
5834 gfx.sxsize = sxsize;
5835 gfx.sysize = sysize;
5839 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5841 DrawTextSCentered(sy, font_1, "Fatal error:");
5842 sy += 3 * font_height;;
5845 DrawTextBufferVA(sx, sy, format, ap, font_2,
5846 line_length, line_length, max_lines,
5847 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5848 sy += (num_lines_printed + 3) * font_height;
5850 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5851 sy += 3 * font_height;
5854 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5855 line_length, line_length, max_lines,
5856 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5858 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5860 redraw_mask = REDRAW_ALL;
5862 /* force drawing exit message even if screen updates are currently limited */
5863 LimitScreenUpdates(FALSE);
5867 /* deactivate toons on error message screen */
5868 setup.toons = FALSE;
5870 WaitForEventToContinue();
5874 /* ========================================================================= */
5876 /* ========================================================================= */
5880 print_timestamp_init("OpenAll");
5882 SetGameStatus(GAME_MODE_LOADING);
5886 InitGlobal(); /* initialize some global variables */
5888 print_timestamp_time("[init global stuff]");
5892 print_timestamp_time("[init setup/config stuff (1)]");
5894 if (options.execute_command)
5895 Execute_Command(options.execute_command);
5897 if (options.serveronly)
5899 #if defined(PLATFORM_UNIX)
5900 NetworkServer(options.server_port, options.serveronly);
5902 Error(ERR_WARN, "networking only supported in Unix version");
5905 exit(0); /* never reached, server loops forever */
5909 print_timestamp_time("[init setup/config stuff (2)]");
5911 print_timestamp_time("[init setup/config stuff (3)]");
5912 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5913 print_timestamp_time("[init setup/config stuff (4)]");
5914 InitArtworkConfig(); /* needed before forking sound child process */
5915 print_timestamp_time("[init setup/config stuff (5)]");
5917 print_timestamp_time("[init setup/config stuff (6)]");
5919 InitRND(NEW_RANDOMIZE);
5920 InitSimpleRandom(NEW_RANDOMIZE);
5924 print_timestamp_time("[init setup/config stuff]");
5927 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5931 print_timestamp_time("[init video stuff]");
5933 InitElementPropertiesStatic();
5934 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5935 InitElementPropertiesGfxElement();
5937 print_timestamp_time("[init element properties stuff]");
5941 print_timestamp_time("InitGfx");
5944 print_timestamp_time("InitLevelInfo");
5946 InitLevelArtworkInfo();
5947 print_timestamp_time("InitLevelArtworkInfo");
5949 InitOverrideArtwork(); /* needs to know current level directory */
5950 print_timestamp_time("InitOverrideArtwork");
5952 InitImages(); /* needs to know current level directory */
5953 print_timestamp_time("InitImages");
5955 InitSound(NULL); /* needs to know current level directory */
5956 print_timestamp_time("InitSound");
5958 InitMusic(NULL); /* needs to know current level directory */
5959 print_timestamp_time("InitMusic");
5963 InitGfxBackground();
5968 if (global.autoplay_leveldir)
5973 else if (global.convert_leveldir)
5978 else if (global.create_images_dir)
5980 CreateLevelSketchImages();
5984 SetGameStatus(GAME_MODE_MAIN);
5986 FadeSetEnterScreen();
5987 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5988 FadeSkipNextFadeOut();
5990 print_timestamp_time("[post-artwork]");
5992 print_timestamp_done("OpenAll");
5996 InitNetworkServer();
5999 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6001 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6002 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6003 #if defined(PLATFORM_ANDROID)
6004 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6005 SDL_AndroidGetInternalStoragePath());
6006 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6007 SDL_AndroidGetExternalStoragePath());
6008 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6009 (SDL_AndroidGetExternalStorageState() ==
6010 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
6011 SDL_AndroidGetExternalStorageState() ==
6012 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
6017 void CloseAllAndExit(int exit_value)
6022 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6029 #if defined(TARGET_SDL)
6030 #if defined(TARGET_SDL2)
6032 // set a flag to tell the network server thread to quit and wait for it
6033 // using SDL_WaitThread()
6035 if (network_server) /* terminate network server */
6036 SDL_KillThread(server_thread);
6040 CloseVideoDisplay();
6041 ClosePlatformDependentStuff();
6043 if (exit_value != 0)
6045 /* fall back to default level set (current set may have caused an error) */
6046 SaveLevelSetup_LastSeries_Deactivate();
6048 /* tell user where to find error log file which may contain more details */
6049 // (error notification now directly displayed on screen inside R'n'D
6050 // NotifyUserAboutErrorFile(); /* currently only works for Windows */