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
87 /* forward declaration for internal use */
88 static int get_graphic_parameter_value(char *, char *, int);
93 struct GraphicInfo *graphic_info_last = graphic_info;
95 static unsigned int action_delay = 0;
96 unsigned int action_delay_value = GameFrameDelay;
97 int sync_frame = FrameCounter;
100 /* prevent OS (Windows) from complaining about program not responding */
103 if (game_status != GAME_MODE_LOADING)
106 if (anim_initial.bitmap == NULL || window == NULL)
109 if (!DelayReached(&action_delay, action_delay_value))
112 if (init_last.busy.x == -1)
113 init_last.busy.x = WIN_XSIZE / 2;
114 if (init_last.busy.y == -1)
115 init_last.busy.y = WIN_YSIZE / 2;
117 x = ALIGNED_TEXT_XPOS(&init_last.busy);
118 y = ALIGNED_TEXT_YPOS(&init_last.busy);
120 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
122 if (sync_frame % anim_initial.anim_delay == 0)
126 int width = graphic_info[graphic].width;
127 int height = graphic_info[graphic].height;
128 int frame = getGraphicAnimationFrame(graphic, sync_frame);
130 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
131 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
134 graphic_info = graphic_info_last;
141 FreeLevelEditorGadgets();
150 static boolean gadgets_initialized = FALSE;
152 if (gadgets_initialized)
155 CreateLevelEditorGadgets();
159 CreateScreenGadgets();
161 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
163 gadgets_initialized = TRUE;
166 inline static void InitElementSmallImagesScaledUp(int graphic)
168 struct GraphicInfo *g = &graphic_info[graphic];
170 // create small and game tile sized bitmaps (and scale up, if needed)
171 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
174 void InitElementSmallImages()
176 print_timestamp_init("InitElementSmallImages");
178 static int special_graphics[] =
192 IMG_EDITOR_ELEMENT_BORDER,
193 IMG_EDITOR_ELEMENT_BORDER_INPUT,
194 IMG_EDITOR_CASCADE_LIST,
195 IMG_EDITOR_CASCADE_LIST_ACTIVE,
198 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
199 int num_property_mappings = getImageListPropertyMappingSize();
202 print_timestamp_time("getImageListPropertyMapping/Size");
204 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
205 /* initialize normal element images from static configuration */
206 for (i = 0; element_to_graphic[i].element > -1; i++)
207 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
208 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
210 /* initialize special element images from static configuration */
211 for (i = 0; element_to_special_graphic[i].element > -1; i++)
212 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
213 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
215 /* initialize element images from dynamic configuration */
216 for (i = 0; i < num_property_mappings; i++)
217 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
218 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
219 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
221 /* initialize special non-element images from above list */
222 for (i = 0; special_graphics[i] > -1; i++)
223 InitElementSmallImagesScaledUp(special_graphics[i]);
224 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
226 print_timestamp_done("InitElementSmallImages");
229 inline static void InitScaledImagesScaledUp(int graphic)
231 struct GraphicInfo *g = &graphic_info[graphic];
233 ScaleImage(graphic, g->scale_up_factor);
236 void InitScaledImages()
238 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
239 int num_property_mappings = getImageListPropertyMappingSize();
242 /* scale normal images from static configuration, if not already scaled */
243 for (i = 0; i < NUM_IMAGE_FILES; i++)
244 InitScaledImagesScaledUp(i);
246 /* scale images from dynamic configuration, if not already scaled */
247 for (i = 0; i < num_property_mappings; i++)
248 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
251 void InitBitmapPointers()
253 int num_images = getImageListSize();
256 // standard size bitmap may have changed -- update default bitmap pointer
257 for (i = 0; i < num_images; i++)
258 if (graphic_info[i].bitmaps)
259 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
262 void InitImageTextures()
266 FreeAllImageTextures();
268 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
269 CreateImageTextures(i);
271 for (i = 0; i < MAX_NUM_TOONS; i++)
272 CreateImageTextures(IMG_TOON_1 + i);
274 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
276 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
278 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
280 int graphic = global_anim_info[i].graphic[j][k];
282 if (graphic == IMG_UNDEFINED)
285 CreateImageTextures(graphic);
292 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
293 void SetBitmaps_EM(Bitmap **em_bitmap)
295 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
296 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
301 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
302 void SetBitmaps_SP(Bitmap **sp_bitmap)
304 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
308 static int getFontBitmapID(int font_nr)
312 /* (special case: do not use special font for GAME_MODE_LOADING) */
313 if (game_status >= GAME_MODE_TITLE_INITIAL &&
314 game_status <= GAME_MODE_PSEUDO_PREVIEW)
315 special = game_status;
316 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
317 special = GFX_SPECIAL_ARG_MAIN;
320 return font_info[font_nr].special_bitmap_id[special];
325 static int getFontFromToken(char *token)
327 char *value = getHashEntry(font_token_hash, token);
332 /* if font not found, use reliable default value */
333 return FONT_INITIAL_1;
336 void InitFontGraphicInfo()
338 static struct FontBitmapInfo *font_bitmap_info = NULL;
339 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
340 int num_property_mappings = getImageListPropertyMappingSize();
341 int num_font_bitmaps = NUM_FONTS;
344 if (graphic_info == NULL) /* still at startup phase */
346 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
347 getFontBitmapID, getFontFromToken);
352 /* ---------- initialize font graphic definitions ---------- */
354 /* always start with reliable default values (normal font graphics) */
355 for (i = 0; i < NUM_FONTS; i++)
356 font_info[i].graphic = IMG_FONT_INITIAL_1;
358 /* initialize normal font/graphic mapping from static configuration */
359 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
361 int font_nr = font_to_graphic[i].font_nr;
362 int special = font_to_graphic[i].special;
363 int graphic = font_to_graphic[i].graphic;
368 font_info[font_nr].graphic = graphic;
371 /* always start with reliable default values (special font graphics) */
372 for (i = 0; i < NUM_FONTS; i++)
374 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
376 font_info[i].special_graphic[j] = font_info[i].graphic;
377 font_info[i].special_bitmap_id[j] = i;
381 /* initialize special font/graphic mapping from static configuration */
382 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
384 int font_nr = font_to_graphic[i].font_nr;
385 int special = font_to_graphic[i].special;
386 int graphic = font_to_graphic[i].graphic;
387 int base_graphic = font2baseimg(font_nr);
389 if (IS_SPECIAL_GFX_ARG(special))
391 boolean base_redefined =
392 getImageListEntryFromImageID(base_graphic)->redefined;
393 boolean special_redefined =
394 getImageListEntryFromImageID(graphic)->redefined;
395 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
397 /* if the base font ("font.title_1", for example) has been redefined,
398 but not the special font ("font.title_1.LEVELS", for example), do not
399 use an existing (in this case considered obsolete) special font
400 anymore, but use the automatically determined default font */
401 /* special case: cloned special fonts must be explicitly redefined,
402 but are not automatically redefined by redefining base font */
403 if (base_redefined && !special_redefined && !special_cloned)
406 font_info[font_nr].special_graphic[special] = graphic;
407 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
412 /* initialize special font/graphic mapping from dynamic configuration */
413 for (i = 0; i < num_property_mappings; i++)
415 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
416 int special = property_mapping[i].ext3_index;
417 int graphic = property_mapping[i].artwork_index;
419 if (font_nr < 0 || font_nr >= NUM_FONTS)
422 if (IS_SPECIAL_GFX_ARG(special))
424 font_info[font_nr].special_graphic[special] = graphic;
425 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
430 /* correct special font/graphic mapping for cloned fonts for downwards
431 compatibility of PREVIEW fonts -- this is only needed for implicit
432 redefinition of special font by redefined base font, and only if other
433 fonts are cloned from this special font (like in the "Zelda" level set) */
434 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
436 int font_nr = font_to_graphic[i].font_nr;
437 int special = font_to_graphic[i].special;
438 int graphic = font_to_graphic[i].graphic;
440 if (IS_SPECIAL_GFX_ARG(special))
442 boolean special_redefined =
443 getImageListEntryFromImageID(graphic)->redefined;
444 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
446 if (special_cloned && !special_redefined)
450 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
452 int font_nr2 = font_to_graphic[j].font_nr;
453 int special2 = font_to_graphic[j].special;
454 int graphic2 = font_to_graphic[j].graphic;
456 if (IS_SPECIAL_GFX_ARG(special2) &&
457 graphic2 == graphic_info[graphic].clone_from)
459 font_info[font_nr].special_graphic[special] =
460 font_info[font_nr2].special_graphic[special2];
461 font_info[font_nr].special_bitmap_id[special] =
462 font_info[font_nr2].special_bitmap_id[special2];
469 /* reset non-redefined ".active" font graphics if normal font is redefined */
470 /* (this different treatment is needed because normal and active fonts are
471 independently defined ("active" is not a property of font definitions!) */
472 for (i = 0; i < NUM_FONTS; i++)
474 int font_nr_base = i;
475 int font_nr_active = FONT_ACTIVE(font_nr_base);
477 /* check only those fonts with exist as normal and ".active" variant */
478 if (font_nr_base != font_nr_active)
480 int base_graphic = font_info[font_nr_base].graphic;
481 int active_graphic = font_info[font_nr_active].graphic;
482 boolean base_redefined =
483 getImageListEntryFromImageID(base_graphic)->redefined;
484 boolean active_redefined =
485 getImageListEntryFromImageID(active_graphic)->redefined;
487 /* if the base font ("font.menu_1", for example) has been redefined,
488 but not the active font ("font.menu_1.active", for example), do not
489 use an existing (in this case considered obsolete) active font
490 anymore, but use the automatically determined default font */
491 if (base_redefined && !active_redefined)
492 font_info[font_nr_active].graphic = base_graphic;
494 /* now also check each "special" font (which may be the same as above) */
495 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
497 int base_graphic = font_info[font_nr_base].special_graphic[j];
498 int active_graphic = font_info[font_nr_active].special_graphic[j];
499 boolean base_redefined =
500 getImageListEntryFromImageID(base_graphic)->redefined;
501 boolean active_redefined =
502 getImageListEntryFromImageID(active_graphic)->redefined;
504 /* same as above, but check special graphic definitions, for example:
505 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
506 if (base_redefined && !active_redefined)
508 font_info[font_nr_active].special_graphic[j] =
509 font_info[font_nr_base].special_graphic[j];
510 font_info[font_nr_active].special_bitmap_id[j] =
511 font_info[font_nr_base].special_bitmap_id[j];
517 /* ---------- initialize font bitmap array ---------- */
519 if (font_bitmap_info != NULL)
520 FreeFontInfo(font_bitmap_info);
523 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
525 /* ---------- initialize font bitmap definitions ---------- */
527 for (i = 0; i < NUM_FONTS; i++)
529 if (i < NUM_INITIAL_FONTS)
531 font_bitmap_info[i] = font_initial[i];
535 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
537 int font_bitmap_id = font_info[i].special_bitmap_id[j];
538 int graphic = font_info[i].special_graphic[j];
540 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
541 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
543 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
544 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
547 /* copy font relevant information from graphics information */
548 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
549 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
550 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
551 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
552 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
554 font_bitmap_info[font_bitmap_id].draw_xoffset =
555 graphic_info[graphic].draw_xoffset;
556 font_bitmap_info[font_bitmap_id].draw_yoffset =
557 graphic_info[graphic].draw_yoffset;
559 font_bitmap_info[font_bitmap_id].num_chars =
560 graphic_info[graphic].anim_frames;
561 font_bitmap_info[font_bitmap_id].num_chars_per_line =
562 graphic_info[graphic].anim_frames_per_line;
566 InitFontInfo(font_bitmap_info, num_font_bitmaps,
567 getFontBitmapID, getFontFromToken);
570 void InitGlobalAnimGraphicInfo()
572 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
573 int num_property_mappings = getImageListPropertyMappingSize();
576 if (graphic_info == NULL) /* still at startup phase */
579 /* always start with reliable default values (no global animations) */
580 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
581 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
582 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
583 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
585 /* initialize global animation definitions from static configuration */
586 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
588 int j = GLOBAL_ANIM_ID_PART_BASE;
589 int k = GFX_SPECIAL_ARG_DEFAULT;
591 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
594 /* initialize global animation definitions from dynamic configuration */
595 for (i = 0; i < num_property_mappings; i++)
597 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
598 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
599 int special = property_mapping[i].ext3_index;
600 int graphic = property_mapping[i].artwork_index;
602 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
605 /* set animation part to base part, if not specified */
606 if (!IS_GLOBAL_ANIM_PART(part_nr))
607 part_nr = GLOBAL_ANIM_ID_PART_BASE;
609 /* set animation screen to default, if not specified */
610 if (!IS_SPECIAL_GFX_ARG(special))
611 special = GFX_SPECIAL_ARG_DEFAULT;
613 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
615 /* fix default value for ".draw_masked" (for backward compatibility) */
616 struct GraphicInfo *g = &graphic_info[graphic];
617 struct FileInfo *image = getImageListEntryFromImageID(graphic);
618 char **parameter_raw = image->parameter;
619 int p = GFX_ARG_DRAW_MASKED;
620 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
621 image_config_suffix[p].token,
622 image_config_suffix[p].type);
624 /* if ".draw_masked" parameter is undefined, use default value "TRUE" */
625 if (draw_masked == ARG_UNDEFINED_VALUE)
626 g->draw_masked = TRUE;
630 printf("::: InitGlobalAnimGraphicInfo\n");
632 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
633 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
634 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
635 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
636 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
637 printf("::: - anim %d, part %d, mode %d => %d\n",
638 i, j, k, global_anim_info[i].graphic[j][k]);
642 void InitGlobalAnimSoundInfo()
644 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
645 int num_property_mappings = getSoundListPropertyMappingSize();
648 /* always start with reliable default values (no global animation sounds) */
649 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
650 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
651 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
652 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
654 /* initialize global animation sound definitions from dynamic configuration */
655 for (i = 0; i < num_property_mappings; i++)
657 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
658 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
659 int special = property_mapping[i].ext3_index;
660 int sound = property_mapping[i].artwork_index;
662 // sound uses control definition; map it to position of graphic (artwork)
663 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
665 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
668 /* set animation part to base part, if not specified */
669 if (!IS_GLOBAL_ANIM_PART(part_nr))
670 part_nr = GLOBAL_ANIM_ID_PART_BASE;
672 /* set animation screen to default, if not specified */
673 if (!IS_SPECIAL_GFX_ARG(special))
674 special = GFX_SPECIAL_ARG_DEFAULT;
676 global_anim_info[anim_nr].sound[part_nr][special] = sound;
680 printf("::: InitGlobalAnimSoundInfo\n");
682 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
683 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
684 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
685 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
686 printf("::: - anim %d, part %d, mode %d => %d\n",
687 i, j, k, global_anim_info[i].sound[j][k]);
691 void InitGlobalAnimMusicInfo()
693 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
694 int num_property_mappings = getMusicListPropertyMappingSize();
697 /* always start with reliable default values (no global animation music) */
698 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
699 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
700 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
701 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
703 /* initialize global animation music definitions from dynamic configuration */
704 for (i = 0; i < num_property_mappings; i++)
706 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
707 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
708 int special = property_mapping[i].ext2_index;
709 int music = property_mapping[i].artwork_index;
711 // music uses control definition; map it to position of graphic (artwork)
712 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
714 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
717 /* set animation part to base part, if not specified */
718 if (!IS_GLOBAL_ANIM_PART(part_nr))
719 part_nr = GLOBAL_ANIM_ID_PART_BASE;
721 /* set animation screen to default, if not specified */
722 if (!IS_SPECIAL_GFX_ARG(special))
723 special = GFX_SPECIAL_ARG_DEFAULT;
725 global_anim_info[anim_nr].music[part_nr][special] = music;
729 printf("::: InitGlobalAnimMusicInfo\n");
731 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
732 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
733 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
734 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
735 printf("::: - anim %d, part %d, mode %d => %d\n",
736 i, j, k, global_anim_info[i].music[j][k]);
740 void InitElementGraphicInfo()
742 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
743 int num_property_mappings = getImageListPropertyMappingSize();
746 if (graphic_info == NULL) /* still at startup phase */
749 /* set values to -1 to identify later as "uninitialized" values */
750 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
752 for (act = 0; act < NUM_ACTIONS; act++)
754 element_info[i].graphic[act] = -1;
755 element_info[i].crumbled[act] = -1;
757 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
759 element_info[i].direction_graphic[act][dir] = -1;
760 element_info[i].direction_crumbled[act][dir] = -1;
767 /* initialize normal element/graphic mapping from static configuration */
768 for (i = 0; element_to_graphic[i].element > -1; i++)
770 int element = element_to_graphic[i].element;
771 int action = element_to_graphic[i].action;
772 int direction = element_to_graphic[i].direction;
773 boolean crumbled = element_to_graphic[i].crumbled;
774 int graphic = element_to_graphic[i].graphic;
775 int base_graphic = el2baseimg(element);
777 if (graphic_info[graphic].bitmap == NULL)
780 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
783 boolean base_redefined =
784 getImageListEntryFromImageID(base_graphic)->redefined;
785 boolean act_dir_redefined =
786 getImageListEntryFromImageID(graphic)->redefined;
788 /* if the base graphic ("emerald", for example) has been redefined,
789 but not the action graphic ("emerald.falling", for example), do not
790 use an existing (in this case considered obsolete) action graphic
791 anymore, but use the automatically determined default graphic */
792 if (base_redefined && !act_dir_redefined)
797 action = ACTION_DEFAULT;
802 element_info[element].direction_crumbled[action][direction] = graphic;
804 element_info[element].crumbled[action] = graphic;
809 element_info[element].direction_graphic[action][direction] = graphic;
811 element_info[element].graphic[action] = graphic;
815 /* initialize normal element/graphic mapping from dynamic configuration */
816 for (i = 0; i < num_property_mappings; i++)
818 int element = property_mapping[i].base_index;
819 int action = property_mapping[i].ext1_index;
820 int direction = property_mapping[i].ext2_index;
821 int special = property_mapping[i].ext3_index;
822 int graphic = property_mapping[i].artwork_index;
823 boolean crumbled = FALSE;
825 if (special == GFX_SPECIAL_ARG_CRUMBLED)
831 if (graphic_info[graphic].bitmap == NULL)
834 if (element >= MAX_NUM_ELEMENTS || special != -1)
838 action = ACTION_DEFAULT;
843 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
844 element_info[element].direction_crumbled[action][dir] = -1;
847 element_info[element].direction_crumbled[action][direction] = graphic;
849 element_info[element].crumbled[action] = graphic;
854 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
855 element_info[element].direction_graphic[action][dir] = -1;
858 element_info[element].direction_graphic[action][direction] = graphic;
860 element_info[element].graphic[action] = graphic;
864 /* now copy all graphics that are defined to be cloned from other graphics */
865 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
867 int graphic = element_info[i].graphic[ACTION_DEFAULT];
868 int crumbled_like, diggable_like;
873 crumbled_like = graphic_info[graphic].crumbled_like;
874 diggable_like = graphic_info[graphic].diggable_like;
876 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
878 for (act = 0; act < NUM_ACTIONS; act++)
879 element_info[i].crumbled[act] =
880 element_info[crumbled_like].crumbled[act];
881 for (act = 0; act < NUM_ACTIONS; act++)
882 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
883 element_info[i].direction_crumbled[act][dir] =
884 element_info[crumbled_like].direction_crumbled[act][dir];
887 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
889 element_info[i].graphic[ACTION_DIGGING] =
890 element_info[diggable_like].graphic[ACTION_DIGGING];
891 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
892 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
893 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
897 /* set hardcoded definitions for some runtime elements without graphic */
898 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
900 /* set hardcoded definitions for some internal elements without graphic */
901 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
903 if (IS_EDITOR_CASCADE_INACTIVE(i))
904 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
905 else if (IS_EDITOR_CASCADE_ACTIVE(i))
906 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
909 /* now set all undefined/invalid graphics to -1 to set to default after it */
910 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
912 for (act = 0; act < NUM_ACTIONS; act++)
916 graphic = element_info[i].graphic[act];
917 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
918 element_info[i].graphic[act] = -1;
920 graphic = element_info[i].crumbled[act];
921 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
922 element_info[i].crumbled[act] = -1;
924 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
926 graphic = element_info[i].direction_graphic[act][dir];
927 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
928 element_info[i].direction_graphic[act][dir] = -1;
930 graphic = element_info[i].direction_crumbled[act][dir];
931 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
932 element_info[i].direction_crumbled[act][dir] = -1;
939 /* adjust graphics with 2nd tile for movement according to direction
940 (do this before correcting '-1' values to minimize calculations) */
941 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
943 for (act = 0; act < NUM_ACTIONS; act++)
945 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
947 int graphic = element_info[i].direction_graphic[act][dir];
948 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
950 if (act == ACTION_FALLING) /* special case */
951 graphic = element_info[i].graphic[act];
954 graphic_info[graphic].double_movement &&
955 graphic_info[graphic].swap_double_tiles != 0)
957 struct GraphicInfo *g = &graphic_info[graphic];
958 int src_x_front = g->src_x;
959 int src_y_front = g->src_y;
960 int src_x_back = g->src_x + g->offset2_x;
961 int src_y_back = g->src_y + g->offset2_y;
962 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
964 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
965 src_y_front < src_y_back);
966 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
967 boolean swap_movement_tiles_autodetected =
968 (!frames_are_ordered_diagonally &&
969 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
970 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
971 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
972 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
974 /* swap frontside and backside graphic tile coordinates, if needed */
975 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
977 /* get current (wrong) backside tile coordinates */
978 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
980 /* set frontside tile coordinates to backside tile coordinates */
981 g->src_x = src_x_back;
982 g->src_y = src_y_back;
984 /* invert tile offset to point to new backside tile coordinates */
988 /* do not swap front and backside tiles again after correction */
989 g->swap_double_tiles = 0;
998 /* now set all '-1' values to element specific default values */
999 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1001 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1002 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1003 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1004 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1006 if (default_graphic == -1)
1007 default_graphic = IMG_UNKNOWN;
1009 if (default_crumbled == -1)
1010 default_crumbled = default_graphic;
1012 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1014 default_direction_graphic[dir] =
1015 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1016 default_direction_crumbled[dir] =
1017 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1019 if (default_direction_graphic[dir] == -1)
1020 default_direction_graphic[dir] = default_graphic;
1022 if (default_direction_crumbled[dir] == -1)
1023 default_direction_crumbled[dir] = default_direction_graphic[dir];
1026 for (act = 0; act < NUM_ACTIONS; act++)
1028 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1029 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1030 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1031 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1032 act == ACTION_TURNING_FROM_RIGHT ||
1033 act == ACTION_TURNING_FROM_UP ||
1034 act == ACTION_TURNING_FROM_DOWN);
1036 /* generic default action graphic (defined by "[default]" directive) */
1037 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1038 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1039 int default_remove_graphic = IMG_EMPTY;
1041 if (act_remove && default_action_graphic != -1)
1042 default_remove_graphic = default_action_graphic;
1044 /* look for special default action graphic (classic game specific) */
1045 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1046 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1047 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1048 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1049 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1050 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1052 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1053 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1054 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1055 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1056 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1057 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1059 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1060 /* !!! make this better !!! */
1061 if (i == EL_EMPTY_SPACE)
1063 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1064 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1067 if (default_action_graphic == -1)
1068 default_action_graphic = default_graphic;
1070 if (default_action_crumbled == -1)
1071 default_action_crumbled = default_action_graphic;
1073 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1075 /* use action graphic as the default direction graphic, if undefined */
1076 int default_action_direction_graphic = element_info[i].graphic[act];
1077 int default_action_direction_crumbled = element_info[i].crumbled[act];
1079 /* no graphic for current action -- use default direction graphic */
1080 if (default_action_direction_graphic == -1)
1081 default_action_direction_graphic =
1082 (act_remove ? default_remove_graphic :
1084 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1085 default_action_graphic != default_graphic ?
1086 default_action_graphic :
1087 default_direction_graphic[dir]);
1089 if (element_info[i].direction_graphic[act][dir] == -1)
1090 element_info[i].direction_graphic[act][dir] =
1091 default_action_direction_graphic;
1093 if (default_action_direction_crumbled == -1)
1094 default_action_direction_crumbled =
1095 element_info[i].direction_graphic[act][dir];
1097 if (element_info[i].direction_crumbled[act][dir] == -1)
1098 element_info[i].direction_crumbled[act][dir] =
1099 default_action_direction_crumbled;
1102 /* no graphic for this specific action -- use default action graphic */
1103 if (element_info[i].graphic[act] == -1)
1104 element_info[i].graphic[act] =
1105 (act_remove ? default_remove_graphic :
1106 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1107 default_action_graphic);
1109 if (element_info[i].crumbled[act] == -1)
1110 element_info[i].crumbled[act] = element_info[i].graphic[act];
1114 UPDATE_BUSY_STATE();
1117 void InitElementSpecialGraphicInfo()
1119 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1120 int num_property_mappings = getImageListPropertyMappingSize();
1123 /* always start with reliable default values */
1124 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1125 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1126 element_info[i].special_graphic[j] =
1127 element_info[i].graphic[ACTION_DEFAULT];
1129 /* initialize special element/graphic mapping from static configuration */
1130 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1132 int element = element_to_special_graphic[i].element;
1133 int special = element_to_special_graphic[i].special;
1134 int graphic = element_to_special_graphic[i].graphic;
1135 int base_graphic = el2baseimg(element);
1136 boolean base_redefined =
1137 getImageListEntryFromImageID(base_graphic)->redefined;
1138 boolean special_redefined =
1139 getImageListEntryFromImageID(graphic)->redefined;
1141 /* if the base graphic ("emerald", for example) has been redefined,
1142 but not the special graphic ("emerald.EDITOR", for example), do not
1143 use an existing (in this case considered obsolete) special graphic
1144 anymore, but use the automatically created (down-scaled) graphic */
1145 if (base_redefined && !special_redefined)
1148 element_info[element].special_graphic[special] = graphic;
1151 /* initialize special element/graphic mapping from dynamic configuration */
1152 for (i = 0; i < num_property_mappings; i++)
1154 int element = property_mapping[i].base_index;
1155 int action = property_mapping[i].ext1_index;
1156 int direction = property_mapping[i].ext2_index;
1157 int special = property_mapping[i].ext3_index;
1158 int graphic = property_mapping[i].artwork_index;
1160 /* for action ".active", replace element with active element, if exists */
1161 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1163 element = ELEMENT_ACTIVE(element);
1167 if (element >= MAX_NUM_ELEMENTS)
1170 /* do not change special graphic if action or direction was specified */
1171 if (action != -1 || direction != -1)
1174 if (IS_SPECIAL_GFX_ARG(special))
1175 element_info[element].special_graphic[special] = graphic;
1178 /* now set all undefined/invalid graphics to default */
1179 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1180 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1181 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1182 element_info[i].special_graphic[j] =
1183 element_info[i].graphic[ACTION_DEFAULT];
1186 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1188 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1189 return get_parameter_value(value_raw, suffix, type);
1191 if (strEqual(value_raw, ARG_UNDEFINED))
1192 return ARG_UNDEFINED_VALUE;
1194 if (type == TYPE_ELEMENT)
1196 char *value = getHashEntry(element_token_hash, value_raw);
1200 Error(ERR_INFO_LINE, "-");
1201 Error(ERR_INFO, "warning: error found in config file:");
1202 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1203 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1204 Error(ERR_INFO, "custom graphic rejected for this element/action");
1205 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1206 Error(ERR_INFO_LINE, "-");
1209 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1211 else if (type == TYPE_GRAPHIC)
1213 char *value = getHashEntry(graphic_token_hash, value_raw);
1214 int fallback_graphic = IMG_CHAR_EXCLAM;
1218 Error(ERR_INFO_LINE, "-");
1219 Error(ERR_INFO, "warning: error found in config file:");
1220 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1221 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1222 Error(ERR_INFO, "custom graphic rejected for this element/action");
1223 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1224 Error(ERR_INFO_LINE, "-");
1227 return (value != NULL ? atoi(value) : fallback_graphic);
1233 static int get_scaled_graphic_width(int graphic)
1235 int original_width = getOriginalImageWidthFromImageID(graphic);
1236 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1238 return original_width * scale_up_factor;
1241 static int get_scaled_graphic_height(int graphic)
1243 int original_height = getOriginalImageHeightFromImageID(graphic);
1244 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1246 return original_height * scale_up_factor;
1249 static void set_graphic_parameters_ext(int graphic, int *parameter,
1250 Bitmap **src_bitmaps)
1252 struct GraphicInfo *g = &graphic_info[graphic];
1253 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1254 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1255 int anim_frames_per_line = 1;
1257 /* always start with reliable default values */
1258 g->src_image_width = 0;
1259 g->src_image_height = 0;
1262 g->width = TILEX; /* default for element graphics */
1263 g->height = TILEY; /* default for element graphics */
1264 g->offset_x = 0; /* one or both of these values ... */
1265 g->offset_y = 0; /* ... will be corrected later */
1266 g->offset2_x = 0; /* one or both of these values ... */
1267 g->offset2_y = 0; /* ... will be corrected later */
1268 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1269 g->crumbled_like = -1; /* do not use clone element */
1270 g->diggable_like = -1; /* do not use clone element */
1271 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1272 g->scale_up_factor = 1; /* default: no scaling up */
1273 g->tile_size = TILESIZE; /* default: standard tile size */
1274 g->clone_from = -1; /* do not use clone graphic */
1275 g->init_delay_fixed = 0;
1276 g->init_delay_random = 0;
1277 g->anim_delay_fixed = 0;
1278 g->anim_delay_random = 0;
1279 g->post_delay_fixed = 0;
1280 g->post_delay_random = 0;
1281 g->init_event = ANIM_EVENT_DEFAULT;
1282 g->anim_event = ANIM_EVENT_DEFAULT;
1283 g->draw_masked = FALSE;
1285 g->fade_mode = FADE_MODE_DEFAULT;
1289 g->align = ALIGN_CENTER; /* default for title screens */
1290 g->valign = VALIGN_MIDDLE; /* default for title screens */
1291 g->sort_priority = 0; /* default for title screens */
1293 g->style = STYLE_DEFAULT;
1295 g->bitmaps = src_bitmaps;
1296 g->bitmap = src_bitmap;
1298 /* optional zoom factor for scaling up the image to a larger size */
1299 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1300 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1301 if (g->scale_up_factor < 1)
1302 g->scale_up_factor = 1; /* no scaling */
1304 /* optional tile size for using non-standard image size */
1305 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1307 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1310 // CHECK: should tile sizes less than standard tile size be allowed?
1311 if (g->tile_size < TILESIZE)
1312 g->tile_size = TILESIZE; /* standard tile size */
1315 // when setting tile size, also set width and height accordingly
1316 g->width = g->tile_size;
1317 g->height = g->tile_size;
1320 if (g->use_image_size)
1322 /* set new default bitmap size (with scaling, but without small images) */
1323 g->width = get_scaled_graphic_width(graphic);
1324 g->height = get_scaled_graphic_height(graphic);
1327 /* optional width and height of each animation frame */
1328 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1329 g->width = parameter[GFX_ARG_WIDTH];
1330 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1331 g->height = parameter[GFX_ARG_HEIGHT];
1333 /* optional x and y tile position of animation frame sequence */
1334 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1335 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1336 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1337 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1339 /* optional x and y pixel position of animation frame sequence */
1340 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1341 g->src_x = parameter[GFX_ARG_X];
1342 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1343 g->src_y = parameter[GFX_ARG_Y];
1349 Error(ERR_INFO_LINE, "-");
1350 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1351 g->width, getTokenFromImageID(graphic), TILEX);
1352 Error(ERR_INFO_LINE, "-");
1354 g->width = TILEX; /* will be checked to be inside bitmap later */
1359 Error(ERR_INFO_LINE, "-");
1360 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1361 g->height, getTokenFromImageID(graphic), TILEY);
1362 Error(ERR_INFO_LINE, "-");
1364 g->height = TILEY; /* will be checked to be inside bitmap later */
1370 /* get final bitmap size (with scaling, but without small images) */
1371 int src_image_width = get_scaled_graphic_width(graphic);
1372 int src_image_height = get_scaled_graphic_height(graphic);
1374 if (src_image_width == 0 || src_image_height == 0)
1376 /* only happens when loaded outside artwork system (like "global.busy") */
1377 src_image_width = src_bitmap->width;
1378 src_image_height = src_bitmap->height;
1381 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1383 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1384 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1388 anim_frames_per_row = MAX(1, src_image_width / g->width);
1389 anim_frames_per_col = MAX(1, src_image_height / g->height);
1392 g->src_image_width = src_image_width;
1393 g->src_image_height = src_image_height;
1396 /* correct x or y offset dependent of vertical or horizontal frame order */
1397 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1399 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1400 parameter[GFX_ARG_OFFSET] : g->height);
1401 anim_frames_per_line = anim_frames_per_col;
1403 else /* frames are ordered horizontally */
1405 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1406 parameter[GFX_ARG_OFFSET] : g->width);
1407 anim_frames_per_line = anim_frames_per_row;
1410 /* optionally, the x and y offset of frames can be specified directly */
1411 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1412 g->offset_x = parameter[GFX_ARG_XOFFSET];
1413 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1414 g->offset_y = parameter[GFX_ARG_YOFFSET];
1416 /* optionally, moving animations may have separate start and end graphics */
1417 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1419 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1420 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1422 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1423 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1424 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1425 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1426 else /* frames are ordered horizontally */
1427 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1428 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1430 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1431 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1432 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1433 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1434 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1436 /* optionally, the second movement tile can be specified as start tile */
1437 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1438 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1440 /* automatically determine correct number of frames, if not defined */
1441 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1442 g->anim_frames = parameter[GFX_ARG_FRAMES];
1443 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1444 g->anim_frames = anim_frames_per_row;
1445 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1446 g->anim_frames = anim_frames_per_col;
1450 if (g->anim_frames == 0) /* frames must be at least 1 */
1453 g->anim_frames_per_line =
1454 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1455 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1457 g->anim_delay = parameter[GFX_ARG_DELAY];
1458 if (g->anim_delay == 0) /* delay must be at least 1 */
1461 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1463 /* automatically determine correct start frame, if not defined */
1464 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1465 g->anim_start_frame = 0;
1466 else if (g->anim_mode & ANIM_REVERSE)
1467 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1469 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1471 /* animation synchronized with global frame counter, not move position */
1472 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1474 /* optional element for cloning crumble graphics */
1475 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1476 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1478 /* optional element for cloning digging graphics */
1479 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1480 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1482 /* optional border size for "crumbling" diggable graphics */
1483 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1484 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1486 /* used for global animations and player "boring" and "sleeping" actions */
1487 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1488 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1489 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1490 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1491 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1492 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1493 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1494 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1495 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1496 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1497 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1498 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1500 /* used for global animations */
1501 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1502 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1503 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1504 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1506 /* used for toon animations and global animations */
1507 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1508 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1509 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1510 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1511 g->direction = parameter[GFX_ARG_DIRECTION];
1512 g->position = parameter[GFX_ARG_POSITION];
1513 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1514 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1516 /* this is only used for drawing font characters */
1517 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1518 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1520 /* use a different default value for global animations and toons */
1521 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1522 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1523 g->draw_masked = TRUE;
1525 /* this is used for drawing envelopes, global animations and toons */
1526 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1527 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1529 /* used for toon animations and global animations */
1530 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1531 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1533 /* optional graphic for cloning all graphics settings */
1534 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1535 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1537 /* optional settings for drawing title screens and title messages */
1538 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1539 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1540 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1541 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1542 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1543 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1544 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1545 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1546 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1547 g->align = parameter[GFX_ARG_ALIGN];
1548 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1549 g->valign = parameter[GFX_ARG_VALIGN];
1550 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1551 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1553 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1554 g->class = parameter[GFX_ARG_CLASS];
1555 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1556 g->style = parameter[GFX_ARG_STYLE];
1558 /* this is only used for drawing menu buttons and text */
1559 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1560 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1561 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1562 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1565 static void set_graphic_parameters(int graphic)
1567 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1568 char **parameter_raw = image->parameter;
1569 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1570 int parameter[NUM_GFX_ARGS];
1573 /* if fallback to default artwork is done, also use the default parameters */
1574 if (image->fallback_to_default)
1575 parameter_raw = image->default_parameter;
1577 /* get integer values from string parameters */
1578 for (i = 0; i < NUM_GFX_ARGS; i++)
1579 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1580 image_config_suffix[i].token,
1581 image_config_suffix[i].type);
1583 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1585 UPDATE_BUSY_STATE();
1588 static void set_cloned_graphic_parameters(int graphic)
1590 int fallback_graphic = IMG_CHAR_EXCLAM;
1591 int max_num_images = getImageListSize();
1592 int clone_graphic = graphic_info[graphic].clone_from;
1593 int num_references_followed = 1;
1595 while (graphic_info[clone_graphic].clone_from != -1 &&
1596 num_references_followed < max_num_images)
1598 clone_graphic = graphic_info[clone_graphic].clone_from;
1600 num_references_followed++;
1603 if (num_references_followed >= max_num_images)
1605 Error(ERR_INFO_LINE, "-");
1606 Error(ERR_INFO, "warning: error found in config file:");
1607 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1608 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1609 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1610 Error(ERR_INFO, "custom graphic rejected for this element/action");
1612 if (graphic == fallback_graphic)
1613 Error(ERR_EXIT, "no fallback graphic available");
1615 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1616 Error(ERR_INFO_LINE, "-");
1618 graphic_info[graphic] = graphic_info[fallback_graphic];
1622 graphic_info[graphic] = graphic_info[clone_graphic];
1623 graphic_info[graphic].clone_from = clone_graphic;
1627 static void InitGraphicInfo()
1629 int fallback_graphic = IMG_CHAR_EXCLAM;
1630 int num_images = getImageListSize();
1633 /* use image size as default values for width and height for these images */
1634 static int full_size_graphics[] =
1637 IMG_GLOBAL_BORDER_MAIN,
1638 IMG_GLOBAL_BORDER_SCORES,
1639 IMG_GLOBAL_BORDER_EDITOR,
1640 IMG_GLOBAL_BORDER_PLAYING,
1643 IMG_BACKGROUND_ENVELOPE_1,
1644 IMG_BACKGROUND_ENVELOPE_2,
1645 IMG_BACKGROUND_ENVELOPE_3,
1646 IMG_BACKGROUND_ENVELOPE_4,
1647 IMG_BACKGROUND_REQUEST,
1650 IMG_BACKGROUND_TITLE_INITIAL,
1651 IMG_BACKGROUND_TITLE,
1652 IMG_BACKGROUND_MAIN,
1653 IMG_BACKGROUND_LEVELS,
1654 IMG_BACKGROUND_LEVELNR,
1655 IMG_BACKGROUND_SCORES,
1656 IMG_BACKGROUND_EDITOR,
1657 IMG_BACKGROUND_INFO,
1658 IMG_BACKGROUND_INFO_ELEMENTS,
1659 IMG_BACKGROUND_INFO_MUSIC,
1660 IMG_BACKGROUND_INFO_CREDITS,
1661 IMG_BACKGROUND_INFO_PROGRAM,
1662 IMG_BACKGROUND_INFO_VERSION,
1663 IMG_BACKGROUND_INFO_LEVELSET,
1664 IMG_BACKGROUND_SETUP,
1665 IMG_BACKGROUND_PLAYING,
1666 IMG_BACKGROUND_DOOR,
1667 IMG_BACKGROUND_TAPE,
1668 IMG_BACKGROUND_PANEL,
1669 IMG_BACKGROUND_PALETTE,
1670 IMG_BACKGROUND_TOOLBOX,
1672 IMG_TITLESCREEN_INITIAL_1,
1673 IMG_TITLESCREEN_INITIAL_2,
1674 IMG_TITLESCREEN_INITIAL_3,
1675 IMG_TITLESCREEN_INITIAL_4,
1676 IMG_TITLESCREEN_INITIAL_5,
1683 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1684 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1685 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1686 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1687 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1688 IMG_BACKGROUND_TITLEMESSAGE_1,
1689 IMG_BACKGROUND_TITLEMESSAGE_2,
1690 IMG_BACKGROUND_TITLEMESSAGE_3,
1691 IMG_BACKGROUND_TITLEMESSAGE_4,
1692 IMG_BACKGROUND_TITLEMESSAGE_5,
1697 checked_free(graphic_info);
1699 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1701 /* initialize "use_image_size" flag with default value */
1702 for (i = 0; i < num_images; i++)
1703 graphic_info[i].use_image_size = FALSE;
1705 /* initialize "use_image_size" flag from static configuration above */
1706 for (i = 0; full_size_graphics[i] != -1; i++)
1707 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1709 /* first set all graphic paramaters ... */
1710 for (i = 0; i < num_images; i++)
1711 set_graphic_parameters(i);
1713 /* ... then copy these parameters for cloned graphics */
1714 for (i = 0; i < num_images; i++)
1715 if (graphic_info[i].clone_from != -1)
1716 set_cloned_graphic_parameters(i);
1718 for (i = 0; i < num_images; i++)
1723 int first_frame, last_frame;
1724 int src_bitmap_width, src_bitmap_height;
1726 /* now check if no animation frames are outside of the loaded image */
1728 if (graphic_info[i].bitmap == NULL)
1729 continue; /* skip check for optional images that are undefined */
1731 /* get image size (this can differ from the standard element tile size!) */
1732 width = graphic_info[i].width;
1733 height = graphic_info[i].height;
1735 /* get final bitmap size (with scaling, but without small images) */
1736 src_bitmap_width = graphic_info[i].src_image_width;
1737 src_bitmap_height = graphic_info[i].src_image_height;
1739 /* check if first animation frame is inside specified bitmap */
1742 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1744 /* this avoids calculating wrong start position for out-of-bounds frame */
1745 src_x = graphic_info[i].src_x;
1746 src_y = graphic_info[i].src_y;
1748 if (program.headless)
1751 if (src_x < 0 || src_y < 0 ||
1752 src_x + width > src_bitmap_width ||
1753 src_y + height > src_bitmap_height)
1755 Error(ERR_INFO_LINE, "-");
1756 Error(ERR_INFO, "warning: error found in config file:");
1757 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1758 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1759 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1760 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1762 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1763 src_x, src_y, src_bitmap_width, src_bitmap_height);
1764 Error(ERR_INFO, "custom graphic rejected for this element/action");
1766 if (i == fallback_graphic)
1767 Error(ERR_EXIT, "no fallback graphic available");
1769 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1770 Error(ERR_INFO_LINE, "-");
1772 graphic_info[i] = graphic_info[fallback_graphic];
1775 /* check if last animation frame is inside specified bitmap */
1777 last_frame = graphic_info[i].anim_frames - 1;
1778 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1780 if (src_x < 0 || src_y < 0 ||
1781 src_x + width > src_bitmap_width ||
1782 src_y + height > src_bitmap_height)
1784 Error(ERR_INFO_LINE, "-");
1785 Error(ERR_INFO, "warning: error found in config file:");
1786 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1787 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1788 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1789 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1791 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1792 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1793 Error(ERR_INFO, "custom graphic rejected for this element/action");
1795 if (i == fallback_graphic)
1796 Error(ERR_EXIT, "no fallback graphic available");
1798 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1799 Error(ERR_INFO_LINE, "-");
1801 graphic_info[i] = graphic_info[fallback_graphic];
1806 static void InitGraphicCompatibilityInfo()
1808 struct FileInfo *fi_global_door =
1809 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1810 int num_images = getImageListSize();
1813 /* the following compatibility handling is needed for the following case:
1814 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1815 graphics mainly used for door and panel graphics, like editor, tape and
1816 in-game buttons with hard-coded bitmap positions and button sizes; as
1817 these graphics now have individual definitions, redefining "global.door"
1818 to change all these graphics at once like before does not work anymore
1819 (because all those individual definitions still have their default values);
1820 to solve this, remap all those individual definitions that are not
1821 redefined to the new bitmap of "global.door" if it was redefined */
1823 /* special compatibility handling if image "global.door" was redefined */
1824 if (fi_global_door->redefined)
1826 for (i = 0; i < num_images; i++)
1828 struct FileInfo *fi = getImageListEntryFromImageID(i);
1830 /* process only those images that still use the default settings */
1833 /* process all images which default to same image as "global.door" */
1834 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1836 // printf("::: special treatment needed for token '%s'\n", fi->token);
1838 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1839 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1845 InitGraphicCompatibilityInfo_Doors();
1848 static void InitElementSoundInfo()
1850 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1851 int num_property_mappings = getSoundListPropertyMappingSize();
1854 /* set values to -1 to identify later as "uninitialized" values */
1855 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1856 for (act = 0; act < NUM_ACTIONS; act++)
1857 element_info[i].sound[act] = -1;
1859 /* initialize element/sound mapping from static configuration */
1860 for (i = 0; element_to_sound[i].element > -1; i++)
1862 int element = element_to_sound[i].element;
1863 int action = element_to_sound[i].action;
1864 int sound = element_to_sound[i].sound;
1865 boolean is_class = element_to_sound[i].is_class;
1868 action = ACTION_DEFAULT;
1871 element_info[element].sound[action] = sound;
1873 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1874 if (strEqual(element_info[j].class_name,
1875 element_info[element].class_name))
1876 element_info[j].sound[action] = sound;
1879 /* initialize element class/sound mapping from dynamic configuration */
1880 for (i = 0; i < num_property_mappings; i++)
1882 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1883 int action = property_mapping[i].ext1_index;
1884 int sound = property_mapping[i].artwork_index;
1886 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1890 action = ACTION_DEFAULT;
1892 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1893 if (strEqual(element_info[j].class_name,
1894 element_info[element_class].class_name))
1895 element_info[j].sound[action] = sound;
1898 /* initialize element/sound mapping from dynamic configuration */
1899 for (i = 0; i < num_property_mappings; i++)
1901 int element = property_mapping[i].base_index;
1902 int action = property_mapping[i].ext1_index;
1903 int sound = property_mapping[i].artwork_index;
1905 if (element >= MAX_NUM_ELEMENTS)
1909 action = ACTION_DEFAULT;
1911 element_info[element].sound[action] = sound;
1914 /* now set all '-1' values to element specific default values */
1915 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1917 for (act = 0; act < NUM_ACTIONS; act++)
1919 /* generic default action sound (defined by "[default]" directive) */
1920 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1922 /* look for special default action sound (classic game specific) */
1923 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1924 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1925 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1926 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1927 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1928 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1930 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1931 /* !!! make this better !!! */
1932 if (i == EL_EMPTY_SPACE)
1933 default_action_sound = element_info[EL_DEFAULT].sound[act];
1935 /* no sound for this specific action -- use default action sound */
1936 if (element_info[i].sound[act] == -1)
1937 element_info[i].sound[act] = default_action_sound;
1941 /* copy sound settings to some elements that are only stored in level file
1942 in native R'n'D levels, but are used by game engine in native EM levels */
1943 for (i = 0; copy_properties[i][0] != -1; i++)
1944 for (j = 1; j <= 4; j++)
1945 for (act = 0; act < NUM_ACTIONS; act++)
1946 element_info[copy_properties[i][j]].sound[act] =
1947 element_info[copy_properties[i][0]].sound[act];
1950 static void InitGameModeSoundInfo()
1954 /* set values to -1 to identify later as "uninitialized" values */
1955 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1958 /* initialize gamemode/sound mapping from static configuration */
1959 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1961 int gamemode = gamemode_to_sound[i].gamemode;
1962 int sound = gamemode_to_sound[i].sound;
1965 gamemode = GAME_MODE_DEFAULT;
1967 menu.sound[gamemode] = sound;
1970 /* now set all '-1' values to levelset specific default values */
1971 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1972 if (menu.sound[i] == -1)
1973 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1976 static void set_sound_parameters(int sound, char **parameter_raw)
1978 int parameter[NUM_SND_ARGS];
1981 /* get integer values from string parameters */
1982 for (i = 0; i < NUM_SND_ARGS; i++)
1984 get_parameter_value(parameter_raw[i],
1985 sound_config_suffix[i].token,
1986 sound_config_suffix[i].type);
1988 /* explicit loop mode setting in configuration overrides default value */
1989 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1990 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1992 /* sound volume to change the original volume when loading the sound file */
1993 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1995 /* sound priority to give certain sounds a higher or lower priority */
1996 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1999 static void InitSoundInfo()
2001 int *sound_effect_properties;
2002 int num_sounds = getSoundListSize();
2005 checked_free(sound_info);
2007 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2008 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2010 /* initialize sound effect for all elements to "no sound" */
2011 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2012 for (j = 0; j < NUM_ACTIONS; j++)
2013 element_info[i].sound[j] = SND_UNDEFINED;
2015 for (i = 0; i < num_sounds; i++)
2017 struct FileInfo *sound = getSoundListEntry(i);
2018 int len_effect_text = strlen(sound->token);
2020 sound_effect_properties[i] = ACTION_OTHER;
2021 sound_info[i].loop = FALSE; /* default: play sound only once */
2023 /* determine all loop sounds and identify certain sound classes */
2025 for (j = 0; element_action_info[j].suffix; j++)
2027 int len_action_text = strlen(element_action_info[j].suffix);
2029 if (len_action_text < len_effect_text &&
2030 strEqual(&sound->token[len_effect_text - len_action_text],
2031 element_action_info[j].suffix))
2033 sound_effect_properties[i] = element_action_info[j].value;
2034 sound_info[i].loop = element_action_info[j].is_loop_sound;
2040 /* associate elements and some selected sound actions */
2042 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2044 if (element_info[j].class_name)
2046 int len_class_text = strlen(element_info[j].class_name);
2048 if (len_class_text + 1 < len_effect_text &&
2049 strncmp(sound->token,
2050 element_info[j].class_name, len_class_text) == 0 &&
2051 sound->token[len_class_text] == '.')
2053 int sound_action_value = sound_effect_properties[i];
2055 element_info[j].sound[sound_action_value] = i;
2060 set_sound_parameters(i, sound->parameter);
2063 free(sound_effect_properties);
2066 static void InitGameModeMusicInfo()
2068 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2069 int num_property_mappings = getMusicListPropertyMappingSize();
2070 int default_levelset_music = -1;
2073 /* set values to -1 to identify later as "uninitialized" values */
2074 for (i = 0; i < MAX_LEVELS; i++)
2075 levelset.music[i] = -1;
2076 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2079 /* initialize gamemode/music mapping from static configuration */
2080 for (i = 0; gamemode_to_music[i].music > -1; i++)
2082 int gamemode = gamemode_to_music[i].gamemode;
2083 int music = gamemode_to_music[i].music;
2086 gamemode = GAME_MODE_DEFAULT;
2088 menu.music[gamemode] = music;
2091 /* initialize gamemode/music mapping from dynamic configuration */
2092 for (i = 0; i < num_property_mappings; i++)
2094 int prefix = property_mapping[i].base_index;
2095 int gamemode = property_mapping[i].ext2_index;
2096 int level = property_mapping[i].ext3_index;
2097 int music = property_mapping[i].artwork_index;
2099 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2103 gamemode = GAME_MODE_DEFAULT;
2105 /* level specific music only allowed for in-game music */
2106 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2107 gamemode = GAME_MODE_PLAYING;
2112 default_levelset_music = music;
2115 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2116 levelset.music[level] = music;
2117 if (gamemode != GAME_MODE_PLAYING)
2118 menu.music[gamemode] = music;
2121 /* now set all '-1' values to menu specific default values */
2122 /* (undefined values of "levelset.music[]" might stay at "-1" to
2123 allow dynamic selection of music files from music directory!) */
2124 for (i = 0; i < MAX_LEVELS; i++)
2125 if (levelset.music[i] == -1)
2126 levelset.music[i] = default_levelset_music;
2127 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2128 if (menu.music[i] == -1)
2129 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2132 static void set_music_parameters(int music, char **parameter_raw)
2134 int parameter[NUM_MUS_ARGS];
2137 /* get integer values from string parameters */
2138 for (i = 0; i < NUM_MUS_ARGS; i++)
2140 get_parameter_value(parameter_raw[i],
2141 music_config_suffix[i].token,
2142 music_config_suffix[i].type);
2144 /* explicit loop mode setting in configuration overrides default value */
2145 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2146 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2149 static void InitMusicInfo()
2151 int num_music = getMusicListSize();
2154 checked_free(music_info);
2156 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2158 for (i = 0; i < num_music; i++)
2160 struct FileInfo *music = getMusicListEntry(i);
2161 int len_music_text = strlen(music->token);
2163 music_info[i].loop = TRUE; /* default: play music in loop mode */
2165 /* determine all loop music */
2167 for (j = 0; music_prefix_info[j].prefix; j++)
2169 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2171 if (len_prefix_text < len_music_text &&
2172 strncmp(music->token,
2173 music_prefix_info[j].prefix, len_prefix_text) == 0)
2175 music_info[i].loop = music_prefix_info[j].is_loop_music;
2181 set_music_parameters(i, music->parameter);
2185 static void ReinitializeGraphics()
2187 print_timestamp_init("ReinitializeGraphics");
2189 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2191 InitGraphicInfo(); /* graphic properties mapping */
2192 print_timestamp_time("InitGraphicInfo");
2193 InitElementGraphicInfo(); /* element game graphic mapping */
2194 print_timestamp_time("InitElementGraphicInfo");
2195 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2196 print_timestamp_time("InitElementSpecialGraphicInfo");
2198 InitElementSmallImages(); /* scale elements to all needed sizes */
2199 print_timestamp_time("InitElementSmallImages");
2200 InitScaledImages(); /* scale all other images, if needed */
2201 print_timestamp_time("InitScaledImages");
2202 InitBitmapPointers(); /* set standard size bitmap pointers */
2203 print_timestamp_time("InitBitmapPointers");
2204 InitFontGraphicInfo(); /* initialize text drawing functions */
2205 print_timestamp_time("InitFontGraphicInfo");
2206 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2207 print_timestamp_time("InitGlobalAnimGraphicInfo");
2209 InitImageTextures(); /* create textures for certain images */
2210 print_timestamp_time("InitImageTextures");
2212 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2213 print_timestamp_time("InitGraphicInfo_EM");
2215 InitGraphicCompatibilityInfo();
2216 print_timestamp_time("InitGraphicCompatibilityInfo");
2218 SetMainBackgroundImage(IMG_BACKGROUND);
2219 print_timestamp_time("SetMainBackgroundImage");
2220 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2221 print_timestamp_time("SetDoorBackgroundImage");
2224 print_timestamp_time("InitGadgets");
2226 print_timestamp_time("InitDoors");
2228 print_timestamp_done("ReinitializeGraphics");
2231 static void ReinitializeSounds()
2233 InitSoundInfo(); /* sound properties mapping */
2234 InitElementSoundInfo(); /* element game sound mapping */
2235 InitGameModeSoundInfo(); /* game mode sound mapping */
2236 InitGlobalAnimSoundInfo(); /* global animation sound settings */
2238 InitPlayLevelSound(); /* internal game sound settings */
2241 static void ReinitializeMusic()
2243 InitMusicInfo(); /* music properties mapping */
2244 InitGameModeMusicInfo(); /* game mode music mapping */
2245 InitGlobalAnimMusicInfo(); /* global animation music settings */
2248 static int get_special_property_bit(int element, int property_bit_nr)
2250 struct PropertyBitInfo
2256 static struct PropertyBitInfo pb_can_move_into_acid[] =
2258 /* the player may be able fall into acid when gravity is activated */
2263 { EL_SP_MURPHY, 0 },
2264 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2266 /* all elements that can move may be able to also move into acid */
2269 { EL_BUG_RIGHT, 1 },
2272 { EL_SPACESHIP, 2 },
2273 { EL_SPACESHIP_LEFT, 2 },
2274 { EL_SPACESHIP_RIGHT, 2 },
2275 { EL_SPACESHIP_UP, 2 },
2276 { EL_SPACESHIP_DOWN, 2 },
2277 { EL_BD_BUTTERFLY, 3 },
2278 { EL_BD_BUTTERFLY_LEFT, 3 },
2279 { EL_BD_BUTTERFLY_RIGHT, 3 },
2280 { EL_BD_BUTTERFLY_UP, 3 },
2281 { EL_BD_BUTTERFLY_DOWN, 3 },
2282 { EL_BD_FIREFLY, 4 },
2283 { EL_BD_FIREFLY_LEFT, 4 },
2284 { EL_BD_FIREFLY_RIGHT, 4 },
2285 { EL_BD_FIREFLY_UP, 4 },
2286 { EL_BD_FIREFLY_DOWN, 4 },
2288 { EL_YAMYAM_LEFT, 5 },
2289 { EL_YAMYAM_RIGHT, 5 },
2290 { EL_YAMYAM_UP, 5 },
2291 { EL_YAMYAM_DOWN, 5 },
2292 { EL_DARK_YAMYAM, 6 },
2295 { EL_PACMAN_LEFT, 8 },
2296 { EL_PACMAN_RIGHT, 8 },
2297 { EL_PACMAN_UP, 8 },
2298 { EL_PACMAN_DOWN, 8 },
2300 { EL_MOLE_LEFT, 9 },
2301 { EL_MOLE_RIGHT, 9 },
2303 { EL_MOLE_DOWN, 9 },
2307 { EL_SATELLITE, 13 },
2308 { EL_SP_SNIKSNAK, 14 },
2309 { EL_SP_ELECTRON, 15 },
2312 { EL_EMC_ANDROID, 18 },
2317 static struct PropertyBitInfo pb_dont_collide_with[] =
2319 { EL_SP_SNIKSNAK, 0 },
2320 { EL_SP_ELECTRON, 1 },
2328 struct PropertyBitInfo *pb_info;
2331 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2332 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2337 struct PropertyBitInfo *pb_info = NULL;
2340 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2341 if (pb_definition[i].bit_nr == property_bit_nr)
2342 pb_info = pb_definition[i].pb_info;
2344 if (pb_info == NULL)
2347 for (i = 0; pb_info[i].element != -1; i++)
2348 if (pb_info[i].element == element)
2349 return pb_info[i].bit_nr;
2354 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2355 boolean property_value)
2357 int bit_nr = get_special_property_bit(element, property_bit_nr);
2362 *bitfield |= (1 << bit_nr);
2364 *bitfield &= ~(1 << bit_nr);
2368 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2370 int bit_nr = get_special_property_bit(element, property_bit_nr);
2373 return ((*bitfield & (1 << bit_nr)) != 0);
2378 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2380 static int group_nr;
2381 static struct ElementGroupInfo *group;
2382 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2385 if (actual_group == NULL) /* not yet initialized */
2388 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2390 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2391 group_element - EL_GROUP_START + 1);
2393 /* replace element which caused too deep recursion by question mark */
2394 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2399 if (recursion_depth == 0) /* initialization */
2401 group = actual_group;
2402 group_nr = GROUP_NR(group_element);
2404 group->num_elements_resolved = 0;
2405 group->choice_pos = 0;
2407 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2408 element_info[i].in_group[group_nr] = FALSE;
2411 for (i = 0; i < actual_group->num_elements; i++)
2413 int element = actual_group->element[i];
2415 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2418 if (IS_GROUP_ELEMENT(element))
2419 ResolveGroupElementExt(element, recursion_depth + 1);
2422 group->element_resolved[group->num_elements_resolved++] = element;
2423 element_info[element].in_group[group_nr] = TRUE;
2428 void ResolveGroupElement(int group_element)
2430 ResolveGroupElementExt(group_element, 0);
2433 void InitElementPropertiesStatic()
2435 static boolean clipboard_elements_initialized = FALSE;
2437 static int ep_diggable[] =
2442 EL_SP_BUGGY_BASE_ACTIVATING,
2445 EL_INVISIBLE_SAND_ACTIVE,
2448 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2449 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2454 EL_SP_BUGGY_BASE_ACTIVE,
2461 static int ep_collectible_only[] =
2483 EL_DYNABOMB_INCREASE_NUMBER,
2484 EL_DYNABOMB_INCREASE_SIZE,
2485 EL_DYNABOMB_INCREASE_POWER,
2503 /* !!! handle separately !!! */
2504 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2510 static int ep_dont_run_into[] =
2512 /* same elements as in 'ep_dont_touch' */
2518 /* same elements as in 'ep_dont_collide_with' */
2530 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2535 EL_SP_BUGGY_BASE_ACTIVE,
2542 static int ep_dont_collide_with[] =
2544 /* same elements as in 'ep_dont_touch' */
2561 static int ep_dont_touch[] =
2571 static int ep_indestructible[] =
2575 EL_ACID_POOL_TOPLEFT,
2576 EL_ACID_POOL_TOPRIGHT,
2577 EL_ACID_POOL_BOTTOMLEFT,
2578 EL_ACID_POOL_BOTTOM,
2579 EL_ACID_POOL_BOTTOMRIGHT,
2580 EL_SP_HARDWARE_GRAY,
2581 EL_SP_HARDWARE_GREEN,
2582 EL_SP_HARDWARE_BLUE,
2584 EL_SP_HARDWARE_YELLOW,
2585 EL_SP_HARDWARE_BASE_1,
2586 EL_SP_HARDWARE_BASE_2,
2587 EL_SP_HARDWARE_BASE_3,
2588 EL_SP_HARDWARE_BASE_4,
2589 EL_SP_HARDWARE_BASE_5,
2590 EL_SP_HARDWARE_BASE_6,
2591 EL_INVISIBLE_STEELWALL,
2592 EL_INVISIBLE_STEELWALL_ACTIVE,
2593 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2594 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2595 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2596 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2597 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2598 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2599 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2600 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2601 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2602 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2603 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2604 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2606 EL_LIGHT_SWITCH_ACTIVE,
2607 EL_SIGN_EXCLAMATION,
2608 EL_SIGN_RADIOACTIVITY,
2615 EL_SIGN_ENTRY_FORBIDDEN,
2616 EL_SIGN_EMERGENCY_EXIT,
2624 EL_STEEL_EXIT_CLOSED,
2626 EL_STEEL_EXIT_OPENING,
2627 EL_STEEL_EXIT_CLOSING,
2628 EL_EM_STEEL_EXIT_CLOSED,
2629 EL_EM_STEEL_EXIT_OPEN,
2630 EL_EM_STEEL_EXIT_OPENING,
2631 EL_EM_STEEL_EXIT_CLOSING,
2632 EL_DC_STEELWALL_1_LEFT,
2633 EL_DC_STEELWALL_1_RIGHT,
2634 EL_DC_STEELWALL_1_TOP,
2635 EL_DC_STEELWALL_1_BOTTOM,
2636 EL_DC_STEELWALL_1_HORIZONTAL,
2637 EL_DC_STEELWALL_1_VERTICAL,
2638 EL_DC_STEELWALL_1_TOPLEFT,
2639 EL_DC_STEELWALL_1_TOPRIGHT,
2640 EL_DC_STEELWALL_1_BOTTOMLEFT,
2641 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2642 EL_DC_STEELWALL_1_TOPLEFT_2,
2643 EL_DC_STEELWALL_1_TOPRIGHT_2,
2644 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2645 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2646 EL_DC_STEELWALL_2_LEFT,
2647 EL_DC_STEELWALL_2_RIGHT,
2648 EL_DC_STEELWALL_2_TOP,
2649 EL_DC_STEELWALL_2_BOTTOM,
2650 EL_DC_STEELWALL_2_HORIZONTAL,
2651 EL_DC_STEELWALL_2_VERTICAL,
2652 EL_DC_STEELWALL_2_MIDDLE,
2653 EL_DC_STEELWALL_2_SINGLE,
2654 EL_STEELWALL_SLIPPERY,
2668 EL_GATE_1_GRAY_ACTIVE,
2669 EL_GATE_2_GRAY_ACTIVE,
2670 EL_GATE_3_GRAY_ACTIVE,
2671 EL_GATE_4_GRAY_ACTIVE,
2680 EL_EM_GATE_1_GRAY_ACTIVE,
2681 EL_EM_GATE_2_GRAY_ACTIVE,
2682 EL_EM_GATE_3_GRAY_ACTIVE,
2683 EL_EM_GATE_4_GRAY_ACTIVE,
2692 EL_EMC_GATE_5_GRAY_ACTIVE,
2693 EL_EMC_GATE_6_GRAY_ACTIVE,
2694 EL_EMC_GATE_7_GRAY_ACTIVE,
2695 EL_EMC_GATE_8_GRAY_ACTIVE,
2697 EL_DC_GATE_WHITE_GRAY,
2698 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2699 EL_DC_GATE_FAKE_GRAY,
2701 EL_SWITCHGATE_OPENING,
2702 EL_SWITCHGATE_CLOSED,
2703 EL_SWITCHGATE_CLOSING,
2704 EL_DC_SWITCHGATE_SWITCH_UP,
2705 EL_DC_SWITCHGATE_SWITCH_DOWN,
2707 EL_TIMEGATE_OPENING,
2709 EL_TIMEGATE_CLOSING,
2710 EL_DC_TIMEGATE_SWITCH,
2711 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2715 EL_TUBE_VERTICAL_LEFT,
2716 EL_TUBE_VERTICAL_RIGHT,
2717 EL_TUBE_HORIZONTAL_UP,
2718 EL_TUBE_HORIZONTAL_DOWN,
2723 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2724 EL_EXPANDABLE_STEELWALL_VERTICAL,
2725 EL_EXPANDABLE_STEELWALL_ANY,
2730 static int ep_slippery[] =
2744 EL_ROBOT_WHEEL_ACTIVE,
2750 EL_ACID_POOL_TOPLEFT,
2751 EL_ACID_POOL_TOPRIGHT,
2761 EL_STEELWALL_SLIPPERY,
2764 EL_EMC_WALL_SLIPPERY_1,
2765 EL_EMC_WALL_SLIPPERY_2,
2766 EL_EMC_WALL_SLIPPERY_3,
2767 EL_EMC_WALL_SLIPPERY_4,
2769 EL_EMC_MAGIC_BALL_ACTIVE,
2774 static int ep_can_change[] =
2779 static int ep_can_move[] =
2781 /* same elements as in 'pb_can_move_into_acid' */
2804 static int ep_can_fall[] =
2818 EL_QUICKSAND_FAST_FULL,
2820 EL_BD_MAGIC_WALL_FULL,
2821 EL_DC_MAGIC_WALL_FULL,
2835 static int ep_can_smash_player[] =
2861 static int ep_can_smash_enemies[] =
2870 static int ep_can_smash_everything[] =
2879 static int ep_explodes_by_fire[] =
2881 /* same elements as in 'ep_explodes_impact' */
2886 /* same elements as in 'ep_explodes_smashed' */
2896 EL_EM_DYNAMITE_ACTIVE,
2897 EL_DYNABOMB_PLAYER_1_ACTIVE,
2898 EL_DYNABOMB_PLAYER_2_ACTIVE,
2899 EL_DYNABOMB_PLAYER_3_ACTIVE,
2900 EL_DYNABOMB_PLAYER_4_ACTIVE,
2901 EL_DYNABOMB_INCREASE_NUMBER,
2902 EL_DYNABOMB_INCREASE_SIZE,
2903 EL_DYNABOMB_INCREASE_POWER,
2904 EL_SP_DISK_RED_ACTIVE,
2918 static int ep_explodes_smashed[] =
2920 /* same elements as in 'ep_explodes_impact' */
2934 static int ep_explodes_impact[] =
2943 static int ep_walkable_over[] =
2947 EL_SOKOBAN_FIELD_EMPTY,
2954 EL_EM_STEEL_EXIT_OPEN,
2955 EL_EM_STEEL_EXIT_OPENING,
2964 EL_GATE_1_GRAY_ACTIVE,
2965 EL_GATE_2_GRAY_ACTIVE,
2966 EL_GATE_3_GRAY_ACTIVE,
2967 EL_GATE_4_GRAY_ACTIVE,
2975 static int ep_walkable_inside[] =
2980 EL_TUBE_VERTICAL_LEFT,
2981 EL_TUBE_VERTICAL_RIGHT,
2982 EL_TUBE_HORIZONTAL_UP,
2983 EL_TUBE_HORIZONTAL_DOWN,
2992 static int ep_walkable_under[] =
2997 static int ep_passable_over[] =
3007 EL_EM_GATE_1_GRAY_ACTIVE,
3008 EL_EM_GATE_2_GRAY_ACTIVE,
3009 EL_EM_GATE_3_GRAY_ACTIVE,
3010 EL_EM_GATE_4_GRAY_ACTIVE,
3019 EL_EMC_GATE_5_GRAY_ACTIVE,
3020 EL_EMC_GATE_6_GRAY_ACTIVE,
3021 EL_EMC_GATE_7_GRAY_ACTIVE,
3022 EL_EMC_GATE_8_GRAY_ACTIVE,
3024 EL_DC_GATE_WHITE_GRAY,
3025 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3032 static int ep_passable_inside[] =
3038 EL_SP_PORT_HORIZONTAL,
3039 EL_SP_PORT_VERTICAL,
3041 EL_SP_GRAVITY_PORT_LEFT,
3042 EL_SP_GRAVITY_PORT_RIGHT,
3043 EL_SP_GRAVITY_PORT_UP,
3044 EL_SP_GRAVITY_PORT_DOWN,
3045 EL_SP_GRAVITY_ON_PORT_LEFT,
3046 EL_SP_GRAVITY_ON_PORT_RIGHT,
3047 EL_SP_GRAVITY_ON_PORT_UP,
3048 EL_SP_GRAVITY_ON_PORT_DOWN,
3049 EL_SP_GRAVITY_OFF_PORT_LEFT,
3050 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3051 EL_SP_GRAVITY_OFF_PORT_UP,
3052 EL_SP_GRAVITY_OFF_PORT_DOWN,
3057 static int ep_passable_under[] =
3062 static int ep_droppable[] =
3067 static int ep_explodes_1x1_old[] =
3072 static int ep_pushable[] =
3084 EL_SOKOBAN_FIELD_FULL,
3093 static int ep_explodes_cross_old[] =
3098 static int ep_protected[] =
3100 /* same elements as in 'ep_walkable_inside' */
3104 EL_TUBE_VERTICAL_LEFT,
3105 EL_TUBE_VERTICAL_RIGHT,
3106 EL_TUBE_HORIZONTAL_UP,
3107 EL_TUBE_HORIZONTAL_DOWN,
3113 /* same elements as in 'ep_passable_over' */
3122 EL_EM_GATE_1_GRAY_ACTIVE,
3123 EL_EM_GATE_2_GRAY_ACTIVE,
3124 EL_EM_GATE_3_GRAY_ACTIVE,
3125 EL_EM_GATE_4_GRAY_ACTIVE,
3134 EL_EMC_GATE_5_GRAY_ACTIVE,
3135 EL_EMC_GATE_6_GRAY_ACTIVE,
3136 EL_EMC_GATE_7_GRAY_ACTIVE,
3137 EL_EMC_GATE_8_GRAY_ACTIVE,
3139 EL_DC_GATE_WHITE_GRAY,
3140 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3144 /* same elements as in 'ep_passable_inside' */
3149 EL_SP_PORT_HORIZONTAL,
3150 EL_SP_PORT_VERTICAL,
3152 EL_SP_GRAVITY_PORT_LEFT,
3153 EL_SP_GRAVITY_PORT_RIGHT,
3154 EL_SP_GRAVITY_PORT_UP,
3155 EL_SP_GRAVITY_PORT_DOWN,
3156 EL_SP_GRAVITY_ON_PORT_LEFT,
3157 EL_SP_GRAVITY_ON_PORT_RIGHT,
3158 EL_SP_GRAVITY_ON_PORT_UP,
3159 EL_SP_GRAVITY_ON_PORT_DOWN,
3160 EL_SP_GRAVITY_OFF_PORT_LEFT,
3161 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3162 EL_SP_GRAVITY_OFF_PORT_UP,
3163 EL_SP_GRAVITY_OFF_PORT_DOWN,
3168 static int ep_throwable[] =
3173 static int ep_can_explode[] =
3175 /* same elements as in 'ep_explodes_impact' */
3180 /* same elements as in 'ep_explodes_smashed' */
3186 /* elements that can explode by explosion or by dragonfire */
3190 EL_EM_DYNAMITE_ACTIVE,
3191 EL_DYNABOMB_PLAYER_1_ACTIVE,
3192 EL_DYNABOMB_PLAYER_2_ACTIVE,
3193 EL_DYNABOMB_PLAYER_3_ACTIVE,
3194 EL_DYNABOMB_PLAYER_4_ACTIVE,
3195 EL_DYNABOMB_INCREASE_NUMBER,
3196 EL_DYNABOMB_INCREASE_SIZE,
3197 EL_DYNABOMB_INCREASE_POWER,
3198 EL_SP_DISK_RED_ACTIVE,
3206 /* elements that can explode only by explosion */
3212 static int ep_gravity_reachable[] =
3218 EL_INVISIBLE_SAND_ACTIVE,
3223 EL_SP_PORT_HORIZONTAL,
3224 EL_SP_PORT_VERTICAL,
3226 EL_SP_GRAVITY_PORT_LEFT,
3227 EL_SP_GRAVITY_PORT_RIGHT,
3228 EL_SP_GRAVITY_PORT_UP,
3229 EL_SP_GRAVITY_PORT_DOWN,
3230 EL_SP_GRAVITY_ON_PORT_LEFT,
3231 EL_SP_GRAVITY_ON_PORT_RIGHT,
3232 EL_SP_GRAVITY_ON_PORT_UP,
3233 EL_SP_GRAVITY_ON_PORT_DOWN,
3234 EL_SP_GRAVITY_OFF_PORT_LEFT,
3235 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3236 EL_SP_GRAVITY_OFF_PORT_UP,
3237 EL_SP_GRAVITY_OFF_PORT_DOWN,
3243 static int ep_player[] =
3250 EL_SOKOBAN_FIELD_PLAYER,
3256 static int ep_can_pass_magic_wall[] =
3270 static int ep_can_pass_dc_magic_wall[] =
3286 static int ep_switchable[] =
3290 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3291 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3292 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3293 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3294 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3295 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3296 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3297 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3298 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3299 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3300 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3301 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3302 EL_SWITCHGATE_SWITCH_UP,
3303 EL_SWITCHGATE_SWITCH_DOWN,
3304 EL_DC_SWITCHGATE_SWITCH_UP,
3305 EL_DC_SWITCHGATE_SWITCH_DOWN,
3307 EL_LIGHT_SWITCH_ACTIVE,
3309 EL_DC_TIMEGATE_SWITCH,
3310 EL_BALLOON_SWITCH_LEFT,
3311 EL_BALLOON_SWITCH_RIGHT,
3312 EL_BALLOON_SWITCH_UP,
3313 EL_BALLOON_SWITCH_DOWN,
3314 EL_BALLOON_SWITCH_ANY,
3315 EL_BALLOON_SWITCH_NONE,
3318 EL_EMC_MAGIC_BALL_SWITCH,
3319 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3324 static int ep_bd_element[] =
3358 static int ep_sp_element[] =
3360 /* should always be valid */
3363 /* standard classic Supaplex elements */
3370 EL_SP_HARDWARE_GRAY,
3378 EL_SP_GRAVITY_PORT_RIGHT,
3379 EL_SP_GRAVITY_PORT_DOWN,
3380 EL_SP_GRAVITY_PORT_LEFT,
3381 EL_SP_GRAVITY_PORT_UP,
3386 EL_SP_PORT_VERTICAL,
3387 EL_SP_PORT_HORIZONTAL,
3393 EL_SP_HARDWARE_BASE_1,
3394 EL_SP_HARDWARE_GREEN,
3395 EL_SP_HARDWARE_BLUE,
3397 EL_SP_HARDWARE_YELLOW,
3398 EL_SP_HARDWARE_BASE_2,
3399 EL_SP_HARDWARE_BASE_3,
3400 EL_SP_HARDWARE_BASE_4,
3401 EL_SP_HARDWARE_BASE_5,
3402 EL_SP_HARDWARE_BASE_6,
3406 /* additional elements that appeared in newer Supaplex levels */
3409 /* additional gravity port elements (not switching, but setting gravity) */
3410 EL_SP_GRAVITY_ON_PORT_LEFT,
3411 EL_SP_GRAVITY_ON_PORT_RIGHT,
3412 EL_SP_GRAVITY_ON_PORT_UP,
3413 EL_SP_GRAVITY_ON_PORT_DOWN,
3414 EL_SP_GRAVITY_OFF_PORT_LEFT,
3415 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3416 EL_SP_GRAVITY_OFF_PORT_UP,
3417 EL_SP_GRAVITY_OFF_PORT_DOWN,
3419 /* more than one Murphy in a level results in an inactive clone */
3422 /* runtime Supaplex elements */
3423 EL_SP_DISK_RED_ACTIVE,
3424 EL_SP_TERMINAL_ACTIVE,
3425 EL_SP_BUGGY_BASE_ACTIVATING,
3426 EL_SP_BUGGY_BASE_ACTIVE,
3433 static int ep_sb_element[] =
3438 EL_SOKOBAN_FIELD_EMPTY,
3439 EL_SOKOBAN_FIELD_FULL,
3440 EL_SOKOBAN_FIELD_PLAYER,
3445 EL_INVISIBLE_STEELWALL,
3450 static int ep_gem[] =
3462 static int ep_food_dark_yamyam[] =
3490 static int ep_food_penguin[] =
3504 static int ep_food_pig[] =
3516 static int ep_historic_wall[] =
3527 EL_GATE_1_GRAY_ACTIVE,
3528 EL_GATE_2_GRAY_ACTIVE,
3529 EL_GATE_3_GRAY_ACTIVE,
3530 EL_GATE_4_GRAY_ACTIVE,
3539 EL_EM_GATE_1_GRAY_ACTIVE,
3540 EL_EM_GATE_2_GRAY_ACTIVE,
3541 EL_EM_GATE_3_GRAY_ACTIVE,
3542 EL_EM_GATE_4_GRAY_ACTIVE,
3549 EL_EXPANDABLE_WALL_HORIZONTAL,
3550 EL_EXPANDABLE_WALL_VERTICAL,
3551 EL_EXPANDABLE_WALL_ANY,
3552 EL_EXPANDABLE_WALL_GROWING,
3553 EL_BD_EXPANDABLE_WALL,
3560 EL_SP_HARDWARE_GRAY,
3561 EL_SP_HARDWARE_GREEN,
3562 EL_SP_HARDWARE_BLUE,
3564 EL_SP_HARDWARE_YELLOW,
3565 EL_SP_HARDWARE_BASE_1,
3566 EL_SP_HARDWARE_BASE_2,
3567 EL_SP_HARDWARE_BASE_3,
3568 EL_SP_HARDWARE_BASE_4,
3569 EL_SP_HARDWARE_BASE_5,
3570 EL_SP_HARDWARE_BASE_6,
3572 EL_SP_TERMINAL_ACTIVE,
3575 EL_INVISIBLE_STEELWALL,
3576 EL_INVISIBLE_STEELWALL_ACTIVE,
3578 EL_INVISIBLE_WALL_ACTIVE,
3579 EL_STEELWALL_SLIPPERY,
3596 static int ep_historic_solid[] =
3600 EL_EXPANDABLE_WALL_HORIZONTAL,
3601 EL_EXPANDABLE_WALL_VERTICAL,
3602 EL_EXPANDABLE_WALL_ANY,
3603 EL_BD_EXPANDABLE_WALL,
3616 EL_QUICKSAND_FILLING,
3617 EL_QUICKSAND_EMPTYING,
3619 EL_MAGIC_WALL_ACTIVE,
3620 EL_MAGIC_WALL_EMPTYING,
3621 EL_MAGIC_WALL_FILLING,
3625 EL_BD_MAGIC_WALL_ACTIVE,
3626 EL_BD_MAGIC_WALL_EMPTYING,
3627 EL_BD_MAGIC_WALL_FULL,
3628 EL_BD_MAGIC_WALL_FILLING,
3629 EL_BD_MAGIC_WALL_DEAD,
3638 EL_SP_TERMINAL_ACTIVE,
3642 EL_INVISIBLE_WALL_ACTIVE,
3643 EL_SWITCHGATE_SWITCH_UP,
3644 EL_SWITCHGATE_SWITCH_DOWN,
3645 EL_DC_SWITCHGATE_SWITCH_UP,
3646 EL_DC_SWITCHGATE_SWITCH_DOWN,
3648 EL_TIMEGATE_SWITCH_ACTIVE,
3649 EL_DC_TIMEGATE_SWITCH,
3650 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3662 /* the following elements are a direct copy of "indestructible" elements,
3663 except "EL_ACID", which is "indestructible", but not "solid"! */
3668 EL_ACID_POOL_TOPLEFT,
3669 EL_ACID_POOL_TOPRIGHT,
3670 EL_ACID_POOL_BOTTOMLEFT,
3671 EL_ACID_POOL_BOTTOM,
3672 EL_ACID_POOL_BOTTOMRIGHT,
3673 EL_SP_HARDWARE_GRAY,
3674 EL_SP_HARDWARE_GREEN,
3675 EL_SP_HARDWARE_BLUE,
3677 EL_SP_HARDWARE_YELLOW,
3678 EL_SP_HARDWARE_BASE_1,
3679 EL_SP_HARDWARE_BASE_2,
3680 EL_SP_HARDWARE_BASE_3,
3681 EL_SP_HARDWARE_BASE_4,
3682 EL_SP_HARDWARE_BASE_5,
3683 EL_SP_HARDWARE_BASE_6,
3684 EL_INVISIBLE_STEELWALL,
3685 EL_INVISIBLE_STEELWALL_ACTIVE,
3686 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3687 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3688 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3689 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3690 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3691 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3692 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3693 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3694 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3695 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3696 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3697 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3699 EL_LIGHT_SWITCH_ACTIVE,
3700 EL_SIGN_EXCLAMATION,
3701 EL_SIGN_RADIOACTIVITY,
3708 EL_SIGN_ENTRY_FORBIDDEN,
3709 EL_SIGN_EMERGENCY_EXIT,
3717 EL_STEEL_EXIT_CLOSED,
3719 EL_DC_STEELWALL_1_LEFT,
3720 EL_DC_STEELWALL_1_RIGHT,
3721 EL_DC_STEELWALL_1_TOP,
3722 EL_DC_STEELWALL_1_BOTTOM,
3723 EL_DC_STEELWALL_1_HORIZONTAL,
3724 EL_DC_STEELWALL_1_VERTICAL,
3725 EL_DC_STEELWALL_1_TOPLEFT,
3726 EL_DC_STEELWALL_1_TOPRIGHT,
3727 EL_DC_STEELWALL_1_BOTTOMLEFT,
3728 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3729 EL_DC_STEELWALL_1_TOPLEFT_2,
3730 EL_DC_STEELWALL_1_TOPRIGHT_2,
3731 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3732 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3733 EL_DC_STEELWALL_2_LEFT,
3734 EL_DC_STEELWALL_2_RIGHT,
3735 EL_DC_STEELWALL_2_TOP,
3736 EL_DC_STEELWALL_2_BOTTOM,
3737 EL_DC_STEELWALL_2_HORIZONTAL,
3738 EL_DC_STEELWALL_2_VERTICAL,
3739 EL_DC_STEELWALL_2_MIDDLE,
3740 EL_DC_STEELWALL_2_SINGLE,
3741 EL_STEELWALL_SLIPPERY,
3755 EL_GATE_1_GRAY_ACTIVE,
3756 EL_GATE_2_GRAY_ACTIVE,
3757 EL_GATE_3_GRAY_ACTIVE,
3758 EL_GATE_4_GRAY_ACTIVE,
3767 EL_EM_GATE_1_GRAY_ACTIVE,
3768 EL_EM_GATE_2_GRAY_ACTIVE,
3769 EL_EM_GATE_3_GRAY_ACTIVE,
3770 EL_EM_GATE_4_GRAY_ACTIVE,
3772 EL_SWITCHGATE_OPENING,
3773 EL_SWITCHGATE_CLOSED,
3774 EL_SWITCHGATE_CLOSING,
3776 EL_TIMEGATE_OPENING,
3778 EL_TIMEGATE_CLOSING,
3782 EL_TUBE_VERTICAL_LEFT,
3783 EL_TUBE_VERTICAL_RIGHT,
3784 EL_TUBE_HORIZONTAL_UP,
3785 EL_TUBE_HORIZONTAL_DOWN,
3794 static int ep_classic_enemy[] =
3811 static int ep_belt[] =
3813 EL_CONVEYOR_BELT_1_LEFT,
3814 EL_CONVEYOR_BELT_1_MIDDLE,
3815 EL_CONVEYOR_BELT_1_RIGHT,
3816 EL_CONVEYOR_BELT_2_LEFT,
3817 EL_CONVEYOR_BELT_2_MIDDLE,
3818 EL_CONVEYOR_BELT_2_RIGHT,
3819 EL_CONVEYOR_BELT_3_LEFT,
3820 EL_CONVEYOR_BELT_3_MIDDLE,
3821 EL_CONVEYOR_BELT_3_RIGHT,
3822 EL_CONVEYOR_BELT_4_LEFT,
3823 EL_CONVEYOR_BELT_4_MIDDLE,
3824 EL_CONVEYOR_BELT_4_RIGHT,
3829 static int ep_belt_active[] =
3831 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3832 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3833 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3834 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3835 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3836 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3837 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3838 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3839 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3840 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3841 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3842 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3847 static int ep_belt_switch[] =
3849 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3850 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3851 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3852 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3853 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3854 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3855 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3856 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3857 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3858 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3859 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3860 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3865 static int ep_tube[] =
3872 EL_TUBE_HORIZONTAL_UP,
3873 EL_TUBE_HORIZONTAL_DOWN,
3875 EL_TUBE_VERTICAL_LEFT,
3876 EL_TUBE_VERTICAL_RIGHT,
3882 static int ep_acid_pool[] =
3884 EL_ACID_POOL_TOPLEFT,
3885 EL_ACID_POOL_TOPRIGHT,
3886 EL_ACID_POOL_BOTTOMLEFT,
3887 EL_ACID_POOL_BOTTOM,
3888 EL_ACID_POOL_BOTTOMRIGHT,
3893 static int ep_keygate[] =
3903 EL_GATE_1_GRAY_ACTIVE,
3904 EL_GATE_2_GRAY_ACTIVE,
3905 EL_GATE_3_GRAY_ACTIVE,
3906 EL_GATE_4_GRAY_ACTIVE,
3915 EL_EM_GATE_1_GRAY_ACTIVE,
3916 EL_EM_GATE_2_GRAY_ACTIVE,
3917 EL_EM_GATE_3_GRAY_ACTIVE,
3918 EL_EM_GATE_4_GRAY_ACTIVE,
3927 EL_EMC_GATE_5_GRAY_ACTIVE,
3928 EL_EMC_GATE_6_GRAY_ACTIVE,
3929 EL_EMC_GATE_7_GRAY_ACTIVE,
3930 EL_EMC_GATE_8_GRAY_ACTIVE,
3932 EL_DC_GATE_WHITE_GRAY,
3933 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3938 static int ep_amoeboid[] =
3950 static int ep_amoebalive[] =
3961 static int ep_has_editor_content[] =
3967 EL_SOKOBAN_FIELD_PLAYER,
3984 static int ep_can_turn_each_move[] =
3986 /* !!! do something with this one !!! */
3990 static int ep_can_grow[] =
4004 static int ep_active_bomb[] =
4007 EL_EM_DYNAMITE_ACTIVE,
4008 EL_DYNABOMB_PLAYER_1_ACTIVE,
4009 EL_DYNABOMB_PLAYER_2_ACTIVE,
4010 EL_DYNABOMB_PLAYER_3_ACTIVE,
4011 EL_DYNABOMB_PLAYER_4_ACTIVE,
4012 EL_SP_DISK_RED_ACTIVE,
4017 static int ep_inactive[] =
4027 EL_QUICKSAND_FAST_EMPTY,
4050 EL_GATE_1_GRAY_ACTIVE,
4051 EL_GATE_2_GRAY_ACTIVE,
4052 EL_GATE_3_GRAY_ACTIVE,
4053 EL_GATE_4_GRAY_ACTIVE,
4062 EL_EM_GATE_1_GRAY_ACTIVE,
4063 EL_EM_GATE_2_GRAY_ACTIVE,
4064 EL_EM_GATE_3_GRAY_ACTIVE,
4065 EL_EM_GATE_4_GRAY_ACTIVE,
4074 EL_EMC_GATE_5_GRAY_ACTIVE,
4075 EL_EMC_GATE_6_GRAY_ACTIVE,
4076 EL_EMC_GATE_7_GRAY_ACTIVE,
4077 EL_EMC_GATE_8_GRAY_ACTIVE,
4079 EL_DC_GATE_WHITE_GRAY,
4080 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4081 EL_DC_GATE_FAKE_GRAY,
4084 EL_INVISIBLE_STEELWALL,
4092 EL_WALL_EMERALD_YELLOW,
4093 EL_DYNABOMB_INCREASE_NUMBER,
4094 EL_DYNABOMB_INCREASE_SIZE,
4095 EL_DYNABOMB_INCREASE_POWER,
4099 EL_SOKOBAN_FIELD_EMPTY,
4100 EL_SOKOBAN_FIELD_FULL,
4101 EL_WALL_EMERALD_RED,
4102 EL_WALL_EMERALD_PURPLE,
4103 EL_ACID_POOL_TOPLEFT,
4104 EL_ACID_POOL_TOPRIGHT,
4105 EL_ACID_POOL_BOTTOMLEFT,
4106 EL_ACID_POOL_BOTTOM,
4107 EL_ACID_POOL_BOTTOMRIGHT,
4111 EL_BD_MAGIC_WALL_DEAD,
4113 EL_DC_MAGIC_WALL_DEAD,
4114 EL_AMOEBA_TO_DIAMOND,
4122 EL_SP_GRAVITY_PORT_RIGHT,
4123 EL_SP_GRAVITY_PORT_DOWN,
4124 EL_SP_GRAVITY_PORT_LEFT,
4125 EL_SP_GRAVITY_PORT_UP,
4126 EL_SP_PORT_HORIZONTAL,
4127 EL_SP_PORT_VERTICAL,
4138 EL_SP_HARDWARE_GRAY,
4139 EL_SP_HARDWARE_GREEN,
4140 EL_SP_HARDWARE_BLUE,
4142 EL_SP_HARDWARE_YELLOW,
4143 EL_SP_HARDWARE_BASE_1,
4144 EL_SP_HARDWARE_BASE_2,
4145 EL_SP_HARDWARE_BASE_3,
4146 EL_SP_HARDWARE_BASE_4,
4147 EL_SP_HARDWARE_BASE_5,
4148 EL_SP_HARDWARE_BASE_6,
4149 EL_SP_GRAVITY_ON_PORT_LEFT,
4150 EL_SP_GRAVITY_ON_PORT_RIGHT,
4151 EL_SP_GRAVITY_ON_PORT_UP,
4152 EL_SP_GRAVITY_ON_PORT_DOWN,
4153 EL_SP_GRAVITY_OFF_PORT_LEFT,
4154 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4155 EL_SP_GRAVITY_OFF_PORT_UP,
4156 EL_SP_GRAVITY_OFF_PORT_DOWN,
4157 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4158 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4159 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4160 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4161 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4162 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4163 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4164 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4165 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4166 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4167 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4168 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4169 EL_SIGN_EXCLAMATION,
4170 EL_SIGN_RADIOACTIVITY,
4177 EL_SIGN_ENTRY_FORBIDDEN,
4178 EL_SIGN_EMERGENCY_EXIT,
4186 EL_DC_STEELWALL_1_LEFT,
4187 EL_DC_STEELWALL_1_RIGHT,
4188 EL_DC_STEELWALL_1_TOP,
4189 EL_DC_STEELWALL_1_BOTTOM,
4190 EL_DC_STEELWALL_1_HORIZONTAL,
4191 EL_DC_STEELWALL_1_VERTICAL,
4192 EL_DC_STEELWALL_1_TOPLEFT,
4193 EL_DC_STEELWALL_1_TOPRIGHT,
4194 EL_DC_STEELWALL_1_BOTTOMLEFT,
4195 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4196 EL_DC_STEELWALL_1_TOPLEFT_2,
4197 EL_DC_STEELWALL_1_TOPRIGHT_2,
4198 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4199 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4200 EL_DC_STEELWALL_2_LEFT,
4201 EL_DC_STEELWALL_2_RIGHT,
4202 EL_DC_STEELWALL_2_TOP,
4203 EL_DC_STEELWALL_2_BOTTOM,
4204 EL_DC_STEELWALL_2_HORIZONTAL,
4205 EL_DC_STEELWALL_2_VERTICAL,
4206 EL_DC_STEELWALL_2_MIDDLE,
4207 EL_DC_STEELWALL_2_SINGLE,
4208 EL_STEELWALL_SLIPPERY,
4213 EL_EMC_WALL_SLIPPERY_1,
4214 EL_EMC_WALL_SLIPPERY_2,
4215 EL_EMC_WALL_SLIPPERY_3,
4216 EL_EMC_WALL_SLIPPERY_4,
4237 static int ep_em_slippery_wall[] =
4242 static int ep_gfx_crumbled[] =
4253 static int ep_editor_cascade_active[] =
4255 EL_INTERNAL_CASCADE_BD_ACTIVE,
4256 EL_INTERNAL_CASCADE_EM_ACTIVE,
4257 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4258 EL_INTERNAL_CASCADE_RND_ACTIVE,
4259 EL_INTERNAL_CASCADE_SB_ACTIVE,
4260 EL_INTERNAL_CASCADE_SP_ACTIVE,
4261 EL_INTERNAL_CASCADE_DC_ACTIVE,
4262 EL_INTERNAL_CASCADE_DX_ACTIVE,
4263 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4264 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4265 EL_INTERNAL_CASCADE_CE_ACTIVE,
4266 EL_INTERNAL_CASCADE_GE_ACTIVE,
4267 EL_INTERNAL_CASCADE_REF_ACTIVE,
4268 EL_INTERNAL_CASCADE_USER_ACTIVE,
4269 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4274 static int ep_editor_cascade_inactive[] =
4276 EL_INTERNAL_CASCADE_BD,
4277 EL_INTERNAL_CASCADE_EM,
4278 EL_INTERNAL_CASCADE_EMC,
4279 EL_INTERNAL_CASCADE_RND,
4280 EL_INTERNAL_CASCADE_SB,
4281 EL_INTERNAL_CASCADE_SP,
4282 EL_INTERNAL_CASCADE_DC,
4283 EL_INTERNAL_CASCADE_DX,
4284 EL_INTERNAL_CASCADE_CHARS,
4285 EL_INTERNAL_CASCADE_STEEL_CHARS,
4286 EL_INTERNAL_CASCADE_CE,
4287 EL_INTERNAL_CASCADE_GE,
4288 EL_INTERNAL_CASCADE_REF,
4289 EL_INTERNAL_CASCADE_USER,
4290 EL_INTERNAL_CASCADE_DYNAMIC,
4295 static int ep_obsolete[] =
4299 EL_EM_KEY_1_FILE_OBSOLETE,
4300 EL_EM_KEY_2_FILE_OBSOLETE,
4301 EL_EM_KEY_3_FILE_OBSOLETE,
4302 EL_EM_KEY_4_FILE_OBSOLETE,
4303 EL_ENVELOPE_OBSOLETE,
4312 } element_properties[] =
4314 { ep_diggable, EP_DIGGABLE },
4315 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4316 { ep_dont_run_into, EP_DONT_RUN_INTO },
4317 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4318 { ep_dont_touch, EP_DONT_TOUCH },
4319 { ep_indestructible, EP_INDESTRUCTIBLE },
4320 { ep_slippery, EP_SLIPPERY },
4321 { ep_can_change, EP_CAN_CHANGE },
4322 { ep_can_move, EP_CAN_MOVE },
4323 { ep_can_fall, EP_CAN_FALL },
4324 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4325 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4326 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4327 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4328 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4329 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4330 { ep_walkable_over, EP_WALKABLE_OVER },
4331 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4332 { ep_walkable_under, EP_WALKABLE_UNDER },
4333 { ep_passable_over, EP_PASSABLE_OVER },
4334 { ep_passable_inside, EP_PASSABLE_INSIDE },
4335 { ep_passable_under, EP_PASSABLE_UNDER },
4336 { ep_droppable, EP_DROPPABLE },
4337 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4338 { ep_pushable, EP_PUSHABLE },
4339 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4340 { ep_protected, EP_PROTECTED },
4341 { ep_throwable, EP_THROWABLE },
4342 { ep_can_explode, EP_CAN_EXPLODE },
4343 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4345 { ep_player, EP_PLAYER },
4346 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4347 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4348 { ep_switchable, EP_SWITCHABLE },
4349 { ep_bd_element, EP_BD_ELEMENT },
4350 { ep_sp_element, EP_SP_ELEMENT },
4351 { ep_sb_element, EP_SB_ELEMENT },
4353 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4354 { ep_food_penguin, EP_FOOD_PENGUIN },
4355 { ep_food_pig, EP_FOOD_PIG },
4356 { ep_historic_wall, EP_HISTORIC_WALL },
4357 { ep_historic_solid, EP_HISTORIC_SOLID },
4358 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4359 { ep_belt, EP_BELT },
4360 { ep_belt_active, EP_BELT_ACTIVE },
4361 { ep_belt_switch, EP_BELT_SWITCH },
4362 { ep_tube, EP_TUBE },
4363 { ep_acid_pool, EP_ACID_POOL },
4364 { ep_keygate, EP_KEYGATE },
4365 { ep_amoeboid, EP_AMOEBOID },
4366 { ep_amoebalive, EP_AMOEBALIVE },
4367 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4368 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4369 { ep_can_grow, EP_CAN_GROW },
4370 { ep_active_bomb, EP_ACTIVE_BOMB },
4371 { ep_inactive, EP_INACTIVE },
4373 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4375 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4377 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4378 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4380 { ep_obsolete, EP_OBSOLETE },
4387 /* always start with reliable default values (element has no properties) */
4388 /* (but never initialize clipboard elements after the very first time) */
4389 /* (to be able to use clipboard elements between several levels) */
4390 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4391 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4392 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4393 SET_PROPERTY(i, j, FALSE);
4395 /* set all base element properties from above array definitions */
4396 for (i = 0; element_properties[i].elements != NULL; i++)
4397 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4398 SET_PROPERTY((element_properties[i].elements)[j],
4399 element_properties[i].property, TRUE);
4401 /* copy properties to some elements that are only stored in level file */
4402 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4403 for (j = 0; copy_properties[j][0] != -1; j++)
4404 if (HAS_PROPERTY(copy_properties[j][0], i))
4405 for (k = 1; k <= 4; k++)
4406 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4408 /* set static element properties that are not listed in array definitions */
4409 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4410 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4412 clipboard_elements_initialized = TRUE;
4415 void InitElementPropertiesEngine(int engine_version)
4417 static int no_wall_properties[] =
4420 EP_COLLECTIBLE_ONLY,
4422 EP_DONT_COLLIDE_WITH,
4425 EP_CAN_SMASH_PLAYER,
4426 EP_CAN_SMASH_ENEMIES,
4427 EP_CAN_SMASH_EVERYTHING,
4432 EP_FOOD_DARK_YAMYAM,
4448 /* important: after initialization in InitElementPropertiesStatic(), the
4449 elements are not again initialized to a default value; therefore all
4450 changes have to make sure that they leave the element with a defined
4451 property (which means that conditional property changes must be set to
4452 a reliable default value before) */
4454 /* resolve group elements */
4455 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4456 ResolveGroupElement(EL_GROUP_START + i);
4458 /* set all special, combined or engine dependent element properties */
4459 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4461 /* do not change (already initialized) clipboard elements here */
4462 if (IS_CLIPBOARD_ELEMENT(i))
4465 /* ---------- INACTIVE ------------------------------------------------- */
4466 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4467 i <= EL_CHAR_END) ||
4468 (i >= EL_STEEL_CHAR_START &&
4469 i <= EL_STEEL_CHAR_END)));
4471 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4472 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4473 IS_WALKABLE_INSIDE(i) ||
4474 IS_WALKABLE_UNDER(i)));
4476 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4477 IS_PASSABLE_INSIDE(i) ||
4478 IS_PASSABLE_UNDER(i)));
4480 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4481 IS_PASSABLE_OVER(i)));
4483 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4484 IS_PASSABLE_INSIDE(i)));
4486 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4487 IS_PASSABLE_UNDER(i)));
4489 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4492 /* ---------- COLLECTIBLE ---------------------------------------------- */
4493 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4497 /* ---------- SNAPPABLE ------------------------------------------------ */
4498 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4499 IS_COLLECTIBLE(i) ||
4503 /* ---------- WALL ----------------------------------------------------- */
4504 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4506 for (j = 0; no_wall_properties[j] != -1; j++)
4507 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4508 i >= EL_FIRST_RUNTIME_UNREAL)
4509 SET_PROPERTY(i, EP_WALL, FALSE);
4511 if (IS_HISTORIC_WALL(i))
4512 SET_PROPERTY(i, EP_WALL, TRUE);
4514 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4515 if (engine_version < VERSION_IDENT(2,2,0,0))
4516 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4518 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4520 !IS_COLLECTIBLE(i)));
4522 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4523 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4524 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4526 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4527 IS_INDESTRUCTIBLE(i)));
4529 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4531 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4532 else if (engine_version < VERSION_IDENT(2,2,0,0))
4533 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4535 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4539 if (IS_CUSTOM_ELEMENT(i))
4541 /* these are additional properties which are initially false when set */
4543 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4545 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4546 if (DONT_COLLIDE_WITH(i))
4547 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4549 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4550 if (CAN_SMASH_EVERYTHING(i))
4551 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4552 if (CAN_SMASH_ENEMIES(i))
4553 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4556 /* ---------- CAN_SMASH ------------------------------------------------ */
4557 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4558 CAN_SMASH_ENEMIES(i) ||
4559 CAN_SMASH_EVERYTHING(i)));
4561 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4562 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4563 EXPLODES_BY_FIRE(i)));
4565 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4566 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4567 EXPLODES_SMASHED(i)));
4569 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4570 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4571 EXPLODES_IMPACT(i)));
4573 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4574 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4576 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4577 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4578 i == EL_BLACK_ORB));
4580 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4581 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4583 IS_CUSTOM_ELEMENT(i)));
4585 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4586 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4587 i == EL_SP_ELECTRON));
4589 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4590 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4591 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4592 getMoveIntoAcidProperty(&level, i));
4594 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4595 if (MAYBE_DONT_COLLIDE_WITH(i))
4596 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4597 getDontCollideWithProperty(&level, i));
4599 /* ---------- SP_PORT -------------------------------------------------- */
4600 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4601 IS_PASSABLE_INSIDE(i)));
4603 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4604 for (j = 0; j < level.num_android_clone_elements; j++)
4605 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4607 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4609 /* ---------- CAN_CHANGE ----------------------------------------------- */
4610 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4611 for (j = 0; j < element_info[i].num_change_pages; j++)
4612 if (element_info[i].change_page[j].can_change)
4613 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4615 /* ---------- HAS_ACTION ----------------------------------------------- */
4616 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4617 for (j = 0; j < element_info[i].num_change_pages; j++)
4618 if (element_info[i].change_page[j].has_action)
4619 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4621 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4622 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4625 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4626 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4627 element_info[i].crumbled[ACTION_DEFAULT] !=
4628 element_info[i].graphic[ACTION_DEFAULT]);
4630 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4631 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4632 IS_EDITOR_CASCADE_INACTIVE(i)));
4635 /* dynamically adjust element properties according to game engine version */
4637 static int ep_em_slippery_wall[] =
4642 EL_EXPANDABLE_WALL_HORIZONTAL,
4643 EL_EXPANDABLE_WALL_VERTICAL,
4644 EL_EXPANDABLE_WALL_ANY,
4645 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4646 EL_EXPANDABLE_STEELWALL_VERTICAL,
4647 EL_EXPANDABLE_STEELWALL_ANY,
4648 EL_EXPANDABLE_STEELWALL_GROWING,
4652 static int ep_em_explodes_by_fire[] =
4655 EL_EM_DYNAMITE_ACTIVE,
4660 /* special EM style gems behaviour */
4661 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4662 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4663 level.em_slippery_gems);
4665 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4666 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4667 (level.em_slippery_gems &&
4668 engine_version > VERSION_IDENT(2,0,1,0)));
4670 /* special EM style explosion behaviour regarding chain reactions */
4671 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4672 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4673 level.em_explodes_by_fire);
4676 /* this is needed because some graphics depend on element properties */
4677 if (game_status == GAME_MODE_PLAYING)
4678 InitElementGraphicInfo();
4681 void InitElementPropertiesAfterLoading(int engine_version)
4685 /* set some other uninitialized values of custom elements in older levels */
4686 if (engine_version < VERSION_IDENT(3,1,0,0))
4688 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4690 int element = EL_CUSTOM_START + i;
4692 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4694 element_info[element].explosion_delay = 17;
4695 element_info[element].ignition_delay = 8;
4700 void InitElementPropertiesGfxElement()
4704 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4706 struct ElementInfo *ei = &element_info[i];
4708 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4712 static void InitGlobal()
4717 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4719 /* check if element_name_info entry defined for each element in "main.h" */
4720 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4721 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4723 element_info[i].token_name = element_name_info[i].token_name;
4724 element_info[i].class_name = element_name_info[i].class_name;
4725 element_info[i].editor_description= element_name_info[i].editor_description;
4728 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4730 /* check if global_anim_name_info defined for each entry in "main.h" */
4731 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4732 global_anim_name_info[i].token_name == NULL)
4733 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4735 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4738 /* create hash from image config list */
4739 image_config_hash = newSetupFileHash();
4740 for (i = 0; image_config[i].token != NULL; i++)
4741 setHashEntry(image_config_hash,
4742 image_config[i].token,
4743 image_config[i].value);
4745 /* create hash from element token list */
4746 element_token_hash = newSetupFileHash();
4747 for (i = 0; element_name_info[i].token_name != NULL; i++)
4748 setHashEntry(element_token_hash,
4749 element_name_info[i].token_name,
4752 /* create hash from graphic token list */
4753 graphic_token_hash = newSetupFileHash();
4754 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4755 if (strSuffix(image_config[i].value, ".png") ||
4756 strSuffix(image_config[i].value, ".pcx") ||
4757 strSuffix(image_config[i].value, ".wav") ||
4758 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4759 setHashEntry(graphic_token_hash,
4760 image_config[i].token,
4761 int2str(graphic++, 0));
4763 /* create hash from font token list */
4764 font_token_hash = newSetupFileHash();
4765 for (i = 0; font_info[i].token_name != NULL; i++)
4766 setHashEntry(font_token_hash,
4767 font_info[i].token_name,
4770 /* set default filenames for all cloned graphics in static configuration */
4771 for (i = 0; image_config[i].token != NULL; i++)
4773 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4775 char *token = image_config[i].token;
4776 char *token_clone_from = getStringCat2(token, ".clone_from");
4777 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4779 if (token_cloned != NULL)
4781 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4783 if (value_cloned != NULL)
4785 /* set default filename in static configuration */
4786 image_config[i].value = value_cloned;
4788 /* set default filename in image config hash */
4789 setHashEntry(image_config_hash, token, value_cloned);
4793 free(token_clone_from);
4797 /* always start with reliable default values (all elements) */
4798 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4799 ActiveElement[i] = i;
4801 /* now add all entries that have an active state (active elements) */
4802 for (i = 0; element_with_active_state[i].element != -1; i++)
4804 int element = element_with_active_state[i].element;
4805 int element_active = element_with_active_state[i].element_active;
4807 ActiveElement[element] = element_active;
4810 /* always start with reliable default values (all buttons) */
4811 for (i = 0; i < NUM_IMAGE_FILES; i++)
4812 ActiveButton[i] = i;
4814 /* now add all entries that have an active state (active buttons) */
4815 for (i = 0; button_with_active_state[i].button != -1; i++)
4817 int button = button_with_active_state[i].button;
4818 int button_active = button_with_active_state[i].button_active;
4820 ActiveButton[button] = button_active;
4823 /* always start with reliable default values (all fonts) */
4824 for (i = 0; i < NUM_FONTS; i++)
4827 /* now add all entries that have an active state (active fonts) */
4828 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4830 int font = font_with_active_state[i].font_nr;
4831 int font_active = font_with_active_state[i].font_nr_active;
4833 ActiveFont[font] = font_active;
4836 global.autoplay_leveldir = NULL;
4837 global.convert_leveldir = NULL;
4838 global.create_images_dir = NULL;
4840 global.frames_per_second = 0;
4841 global.show_frames_per_second = FALSE;
4843 global.border_status = GAME_MODE_LOADING;
4844 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4846 global.use_envelope_request = FALSE;
4849 void Execute_Command(char *command)
4853 if (strEqual(command, "print graphicsinfo.conf"))
4855 Print("# You can configure additional/alternative image files here.\n");
4856 Print("# (The entries below are default and therefore commented out.)\n");
4858 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4860 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4863 for (i = 0; image_config[i].token != NULL; i++)
4864 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4865 image_config[i].value));
4869 else if (strEqual(command, "print soundsinfo.conf"))
4871 Print("# You can configure additional/alternative sound files here.\n");
4872 Print("# (The entries below are default and therefore commented out.)\n");
4874 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4876 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4879 for (i = 0; sound_config[i].token != NULL; i++)
4880 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4881 sound_config[i].value));
4885 else if (strEqual(command, "print musicinfo.conf"))
4887 Print("# You can configure additional/alternative music files here.\n");
4888 Print("# (The entries below are default and therefore commented out.)\n");
4890 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4892 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4895 for (i = 0; music_config[i].token != NULL; i++)
4896 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4897 music_config[i].value));
4901 else if (strEqual(command, "print editorsetup.conf"))
4903 Print("# You can configure your personal editor element list here.\n");
4904 Print("# (The entries below are default and therefore commented out.)\n");
4907 /* this is needed to be able to check element list for cascade elements */
4908 InitElementPropertiesStatic();
4909 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4911 PrintEditorElementList();
4915 else if (strEqual(command, "print helpanim.conf"))
4917 Print("# You can configure different element help animations here.\n");
4918 Print("# (The entries below are default and therefore commented out.)\n");
4921 for (i = 0; helpanim_config[i].token != NULL; i++)
4923 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4924 helpanim_config[i].value));
4926 if (strEqual(helpanim_config[i].token, "end"))
4932 else if (strEqual(command, "print helptext.conf"))
4934 Print("# You can configure different element help text here.\n");
4935 Print("# (The entries below are default and therefore commented out.)\n");
4938 for (i = 0; helptext_config[i].token != NULL; i++)
4939 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4940 helptext_config[i].value));
4944 else if (strPrefix(command, "dump level "))
4946 char *filename = &command[11];
4948 if (!fileExists(filename))
4949 Error(ERR_EXIT, "cannot open file '%s'", filename);
4951 LoadLevelFromFilename(&level, filename);
4956 else if (strPrefix(command, "dump tape "))
4958 char *filename = &command[10];
4960 if (!fileExists(filename))
4961 Error(ERR_EXIT, "cannot open file '%s'", filename);
4963 LoadTapeFromFilename(filename);
4968 else if (strPrefix(command, "autotest ") ||
4969 strPrefix(command, "autoplay ") ||
4970 strPrefix(command, "autoffwd ") ||
4971 strPrefix(command, "autowarp "))
4973 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4975 global.autoplay_mode =
4976 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
4977 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
4978 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
4979 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
4980 AUTOPLAY_MODE_NONE);
4982 while (*str_ptr != '\0') /* continue parsing string */
4984 /* cut leading whitespace from string, replace it by string terminator */
4985 while (*str_ptr == ' ' || *str_ptr == '\t')
4988 if (*str_ptr == '\0') /* end of string reached */
4991 if (global.autoplay_leveldir == NULL) /* read level set string */
4993 global.autoplay_leveldir = str_ptr;
4994 global.autoplay_all = TRUE; /* default: play all tapes */
4996 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4997 global.autoplay_level[i] = FALSE;
4999 else /* read level number string */
5001 int level_nr = atoi(str_ptr); /* get level_nr value */
5003 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5004 global.autoplay_level[level_nr] = TRUE;
5006 global.autoplay_all = FALSE;
5009 /* advance string pointer to the next whitespace (or end of string) */
5010 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5014 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5015 program.headless = TRUE;
5017 else if (strPrefix(command, "convert "))
5019 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5020 char *str_ptr = strchr(str_copy, ' ');
5022 global.convert_leveldir = str_copy;
5023 global.convert_level_nr = -1;
5025 if (str_ptr != NULL) /* level number follows */
5027 *str_ptr++ = '\0'; /* terminate leveldir string */
5028 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5031 program.headless = TRUE;
5033 else if (strPrefix(command, "create images "))
5035 global.create_images_dir = getStringCopy(&command[14]);
5037 if (access(global.create_images_dir, W_OK) != 0)
5038 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5039 global.create_images_dir);
5041 else if (strPrefix(command, "create CE image "))
5043 CreateCustomElementImages(&command[16]);
5049 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5053 static void InitSetup()
5055 LoadSetup(); /* global setup info */
5057 /* set some options from setup file */
5059 if (setup.options.verbose)
5060 options.verbose = TRUE;
5062 if (setup.debug.show_frames_per_second)
5063 global.show_frames_per_second = TRUE;
5066 static void InitGameInfo()
5068 game.restart_level = FALSE;
5071 static void InitPlayerInfo()
5075 /* choose default local player */
5076 local_player = &stored_player[0];
5078 for (i = 0; i < MAX_PLAYERS; i++)
5079 stored_player[i].connected = FALSE;
5081 local_player->connected = TRUE;
5084 static void InitArtworkInfo()
5089 static char *get_string_in_brackets(char *string)
5091 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5093 sprintf(string_in_brackets, "[%s]", string);
5095 return string_in_brackets;
5098 static char *get_level_id_suffix(int id_nr)
5100 char *id_suffix = checked_malloc(1 + 3 + 1);
5102 if (id_nr < 0 || id_nr > 999)
5105 sprintf(id_suffix, ".%03d", id_nr);
5110 static void InitArtworkConfig()
5112 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5114 NUM_GLOBAL_ANIM_TOKENS + 1];
5115 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5116 NUM_GLOBAL_ANIM_TOKENS + 1];
5117 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5118 NUM_GLOBAL_ANIM_TOKENS + 1];
5119 static char *action_id_suffix[NUM_ACTIONS + 1];
5120 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5121 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5122 static char *level_id_suffix[MAX_LEVELS + 1];
5123 static char *dummy[1] = { NULL };
5124 static char *ignore_generic_tokens[] =
5130 static char **ignore_image_tokens;
5131 static char **ignore_sound_tokens;
5132 static char **ignore_music_tokens;
5133 int num_ignore_generic_tokens;
5134 int num_ignore_image_tokens;
5135 int num_ignore_sound_tokens;
5136 int num_ignore_music_tokens;
5139 /* dynamically determine list of generic tokens to be ignored */
5140 num_ignore_generic_tokens = 0;
5141 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5142 num_ignore_generic_tokens++;
5144 /* dynamically determine list of image tokens to be ignored */
5145 num_ignore_image_tokens = num_ignore_generic_tokens;
5146 for (i = 0; image_config_vars[i].token != NULL; i++)
5147 num_ignore_image_tokens++;
5148 ignore_image_tokens =
5149 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5150 for (i = 0; i < num_ignore_generic_tokens; i++)
5151 ignore_image_tokens[i] = ignore_generic_tokens[i];
5152 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5153 ignore_image_tokens[num_ignore_generic_tokens + i] =
5154 image_config_vars[i].token;
5155 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5157 /* dynamically determine list of sound tokens to be ignored */
5158 num_ignore_sound_tokens = num_ignore_generic_tokens;
5159 ignore_sound_tokens =
5160 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5161 for (i = 0; i < num_ignore_generic_tokens; i++)
5162 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5163 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5165 /* dynamically determine list of music tokens to be ignored */
5166 num_ignore_music_tokens = num_ignore_generic_tokens;
5167 ignore_music_tokens =
5168 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5169 for (i = 0; i < num_ignore_generic_tokens; i++)
5170 ignore_music_tokens[i] = ignore_generic_tokens[i];
5171 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5173 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5174 image_id_prefix[i] = element_info[i].token_name;
5175 for (i = 0; i < NUM_FONTS; i++)
5176 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5177 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5178 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5179 global_anim_info[i].token_name;
5180 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5182 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5183 sound_id_prefix[i] = element_info[i].token_name;
5184 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5185 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5186 get_string_in_brackets(element_info[i].class_name);
5187 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5188 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5189 global_anim_info[i].token_name;
5190 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5192 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5193 music_id_prefix[i] = music_prefix_info[i].prefix;
5194 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5195 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5196 global_anim_info[i].token_name;
5197 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5199 for (i = 0; i < NUM_ACTIONS; i++)
5200 action_id_suffix[i] = element_action_info[i].suffix;
5201 action_id_suffix[NUM_ACTIONS] = NULL;
5203 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5204 direction_id_suffix[i] = element_direction_info[i].suffix;
5205 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5207 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5208 special_id_suffix[i] = special_suffix_info[i].suffix;
5209 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5211 for (i = 0; i < MAX_LEVELS; i++)
5212 level_id_suffix[i] = get_level_id_suffix(i);
5213 level_id_suffix[MAX_LEVELS] = NULL;
5215 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5216 image_id_prefix, action_id_suffix, direction_id_suffix,
5217 special_id_suffix, ignore_image_tokens);
5218 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5219 sound_id_prefix, action_id_suffix, dummy,
5220 special_id_suffix, ignore_sound_tokens);
5221 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5222 music_id_prefix, action_id_suffix, special_id_suffix,
5223 level_id_suffix, ignore_music_tokens);
5226 static void InitMixer()
5233 void InitGfxBuffers()
5235 static int win_xsize_last = -1;
5236 static int win_ysize_last = -1;
5238 /* create additional image buffers for double-buffering and cross-fading */
5240 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5242 /* used to temporarily store the backbuffer -- only re-create if changed */
5243 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5244 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5246 win_xsize_last = WIN_XSIZE;
5247 win_ysize_last = WIN_YSIZE;
5250 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5251 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5252 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5253 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5255 /* initialize screen properties */
5256 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5257 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5259 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5260 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5261 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5262 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5263 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5264 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5266 /* required if door size definitions have changed */
5267 InitGraphicCompatibilityInfo_Doors();
5269 InitGfxBuffers_EM();
5270 InitGfxBuffers_SP();
5275 struct GraphicInfo *graphic_info_last = graphic_info;
5276 char *filename_font_initial = NULL;
5277 char *filename_anim_initial = NULL;
5278 Bitmap *bitmap_font_initial = NULL;
5282 /* determine settings for initial font (for displaying startup messages) */
5283 for (i = 0; image_config[i].token != NULL; i++)
5285 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5287 char font_token[128];
5290 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5291 len_font_token = strlen(font_token);
5293 if (strEqual(image_config[i].token, font_token))
5294 filename_font_initial = image_config[i].value;
5295 else if (strlen(image_config[i].token) > len_font_token &&
5296 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5298 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5299 font_initial[j].src_x = atoi(image_config[i].value);
5300 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5301 font_initial[j].src_y = atoi(image_config[i].value);
5302 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5303 font_initial[j].width = atoi(image_config[i].value);
5304 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5305 font_initial[j].height = atoi(image_config[i].value);
5310 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5312 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5313 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5316 if (filename_font_initial == NULL) /* should not happen */
5317 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5320 InitGfxCustomArtworkInfo();
5321 InitGfxOtherSettings();
5323 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5325 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5326 font_initial[j].bitmap = bitmap_font_initial;
5328 InitFontGraphicInfo();
5330 font_height = getFontHeight(FC_RED);
5332 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5333 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5334 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5337 DrawInitText("Loading graphics", 120, FC_GREEN);
5339 /* initialize settings for busy animation with default values */
5340 int parameter[NUM_GFX_ARGS];
5341 for (i = 0; i < NUM_GFX_ARGS; i++)
5342 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5343 image_config_suffix[i].token,
5344 image_config_suffix[i].type);
5346 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5347 int len_anim_token = strlen(anim_token);
5349 /* read settings for busy animation from default custom artwork config */
5350 char *gfx_config_filename = getPath3(options.graphics_directory,
5352 GRAPHICSINFO_FILENAME);
5354 if (fileExists(gfx_config_filename))
5356 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5358 if (setup_file_hash)
5360 char *filename = getHashEntry(setup_file_hash, anim_token);
5364 filename_anim_initial = getStringCopy(filename);
5366 for (j = 0; image_config_suffix[j].token != NULL; j++)
5368 int type = image_config_suffix[j].type;
5369 char *suffix = image_config_suffix[j].token;
5370 char *token = getStringCat2(anim_token, suffix);
5371 char *value = getHashEntry(setup_file_hash, token);
5373 checked_free(token);
5376 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5380 freeSetupFileHash(setup_file_hash);
5384 if (filename_anim_initial == NULL)
5386 /* read settings for busy animation from static default artwork config */
5387 for (i = 0; image_config[i].token != NULL; i++)
5389 if (strEqual(image_config[i].token, anim_token))
5390 filename_anim_initial = getStringCopy(image_config[i].value);
5391 else if (strlen(image_config[i].token) > len_anim_token &&
5392 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5394 for (j = 0; image_config_suffix[j].token != NULL; j++)
5396 if (strEqual(&image_config[i].token[len_anim_token],
5397 image_config_suffix[j].token))
5399 get_graphic_parameter_value(image_config[i].value,
5400 image_config_suffix[j].token,
5401 image_config_suffix[j].type);
5407 if (filename_anim_initial == NULL) /* should not happen */
5408 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5410 anim_initial.bitmaps =
5411 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5413 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5414 LoadCustomImage(filename_anim_initial);
5416 checked_free(filename_anim_initial);
5418 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5420 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5422 graphic_info = graphic_info_last;
5424 init.busy.width = anim_initial.width;
5425 init.busy.height = anim_initial.height;
5427 InitMenuDesignSettings_Static();
5429 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5430 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5431 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5433 gfx.fade_border_source_status = global.border_status;
5434 gfx.fade_border_target_status = global.border_status;
5435 gfx.masked_border_bitmap_ptr = backbuffer;
5437 /* use copy of busy animation to prevent change while reloading artwork */
5441 void InitGfxBackground()
5443 fieldbuffer = bitmap_db_field;
5444 SetDrawtoField(DRAW_TO_BACKBUFFER);
5446 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5448 redraw_mask = REDRAW_ALL;
5451 static void InitLevelInfo()
5453 LoadLevelInfo(); /* global level info */
5454 LoadLevelSetup_LastSeries(); /* last played series info */
5455 LoadLevelSetup_SeriesInfo(); /* last played level info */
5457 if (global.autoplay_leveldir &&
5458 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5460 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5461 global.autoplay_leveldir);
5462 if (leveldir_current == NULL)
5463 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5467 static void InitLevelArtworkInfo()
5469 LoadLevelArtworkInfo();
5472 static void InitImages()
5474 print_timestamp_init("InitImages");
5477 printf("::: leveldir_current->identifier == '%s'\n",
5478 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5479 printf("::: leveldir_current->graphics_path == '%s'\n",
5480 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5481 printf("::: leveldir_current->graphics_set == '%s'\n",
5482 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5483 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5484 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5487 setLevelArtworkDir(artwork.gfx_first);
5490 printf("::: leveldir_current->identifier == '%s'\n",
5491 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5492 printf("::: leveldir_current->graphics_path == '%s'\n",
5493 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5494 printf("::: leveldir_current->graphics_set == '%s'\n",
5495 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5496 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5497 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5501 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5502 leveldir_current->identifier,
5503 artwork.gfx_current_identifier,
5504 artwork.gfx_current->identifier,
5505 leveldir_current->graphics_set,
5506 leveldir_current->graphics_path);
5509 UPDATE_BUSY_STATE();
5511 ReloadCustomImages();
5512 print_timestamp_time("ReloadCustomImages");
5514 UPDATE_BUSY_STATE();
5516 LoadCustomElementDescriptions();
5517 print_timestamp_time("LoadCustomElementDescriptions");
5519 UPDATE_BUSY_STATE();
5521 LoadMenuDesignSettings();
5522 print_timestamp_time("LoadMenuDesignSettings");
5524 UPDATE_BUSY_STATE();
5526 ReinitializeGraphics();
5527 print_timestamp_time("ReinitializeGraphics");
5529 LoadMenuDesignSettings_AfterGraphics();
5530 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5532 UPDATE_BUSY_STATE();
5534 print_timestamp_done("InitImages");
5537 static void InitSound(char *identifier)
5539 print_timestamp_init("InitSound");
5541 if (identifier == NULL)
5542 identifier = artwork.snd_current->identifier;
5544 /* set artwork path to send it to the sound server process */
5545 setLevelArtworkDir(artwork.snd_first);
5547 InitReloadCustomSounds(identifier);
5548 print_timestamp_time("InitReloadCustomSounds");
5550 ReinitializeSounds();
5551 print_timestamp_time("ReinitializeSounds");
5553 print_timestamp_done("InitSound");
5556 static void InitMusic(char *identifier)
5558 print_timestamp_init("InitMusic");
5560 if (identifier == NULL)
5561 identifier = artwork.mus_current->identifier;
5563 /* set artwork path to send it to the sound server process */
5564 setLevelArtworkDir(artwork.mus_first);
5566 InitReloadCustomMusic(identifier);
5567 print_timestamp_time("InitReloadCustomMusic");
5569 ReinitializeMusic();
5570 print_timestamp_time("ReinitializeMusic");
5572 print_timestamp_done("InitMusic");
5575 static void InitArtworkDone()
5577 if (program.headless)
5580 InitGlobalAnimations();
5583 void InitNetworkServer()
5585 #if defined(NETWORK_AVALIABLE)
5589 if (!options.network)
5592 #if defined(NETWORK_AVALIABLE)
5593 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5595 if (!ConnectToServer(options.server_host, options.server_port))
5596 Error(ERR_EXIT, "cannot connect to network game server");
5598 SendToServer_PlayerName(setup.player_name);
5599 SendToServer_ProtocolVersion();
5602 SendToServer_NrWanted(nr_wanted);
5606 static boolean CheckArtworkConfigForCustomElements(char *filename)
5608 SetupFileHash *setup_file_hash;
5609 boolean redefined_ce_found = FALSE;
5611 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5613 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5615 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5617 char *token = HASH_ITERATION_TOKEN(itr);
5619 if (strPrefix(token, "custom_"))
5621 redefined_ce_found = TRUE;
5626 END_HASH_ITERATION(setup_file_hash, itr)
5628 freeSetupFileHash(setup_file_hash);
5631 return redefined_ce_found;
5634 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5636 char *filename_base, *filename_local;
5637 boolean redefined_ce_found = FALSE;
5639 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5642 printf("::: leveldir_current->identifier == '%s'\n",
5643 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5644 printf("::: leveldir_current->graphics_path == '%s'\n",
5645 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5646 printf("::: leveldir_current->graphics_set == '%s'\n",
5647 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5648 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5649 leveldir_current == NULL ? "[NULL]" :
5650 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5653 /* first look for special artwork configured in level series config */
5654 filename_base = getCustomArtworkLevelConfigFilename(type);
5657 printf("::: filename_base == '%s'\n", filename_base);
5660 if (fileExists(filename_base))
5661 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5663 filename_local = getCustomArtworkConfigFilename(type);
5666 printf("::: filename_local == '%s'\n", filename_local);
5669 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5670 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5673 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5676 return redefined_ce_found;
5679 static void InitOverrideArtwork()
5681 boolean redefined_ce_found = FALSE;
5683 /* to check if this level set redefines any CEs, do not use overriding */
5684 gfx.override_level_graphics = FALSE;
5685 gfx.override_level_sounds = FALSE;
5686 gfx.override_level_music = FALSE;
5688 /* now check if this level set has definitions for custom elements */
5689 if (setup.override_level_graphics == AUTO ||
5690 setup.override_level_sounds == AUTO ||
5691 setup.override_level_music == AUTO)
5692 redefined_ce_found =
5693 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5694 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5695 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5698 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5701 if (redefined_ce_found)
5703 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5704 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5705 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5706 gfx.override_level_music = (setup.override_level_music == TRUE);
5710 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5711 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5712 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5713 gfx.override_level_music = (setup.override_level_music != FALSE);
5717 printf("::: => %d, %d, %d\n",
5718 gfx.override_level_graphics,
5719 gfx.override_level_sounds,
5720 gfx.override_level_music);
5724 static char *getNewArtworkIdentifier(int type)
5726 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5727 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5728 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5729 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5730 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5731 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5732 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5733 char *leveldir_identifier = leveldir_current->identifier;
5734 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5735 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5736 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5737 char *artwork_current_identifier;
5738 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5740 /* leveldir_current may be invalid (level group, parent link) */
5741 if (!validLevelSeries(leveldir_current))
5744 /* 1st step: determine artwork set to be activated in descending order:
5745 --------------------------------------------------------------------
5746 1. setup artwork (when configured to override everything else)
5747 2. artwork set configured in "levelinfo.conf" of current level set
5748 (artwork in level directory will have priority when loading later)
5749 3. artwork in level directory (stored in artwork sub-directory)
5750 4. setup artwork (currently configured in setup menu) */
5752 if (setup_override_artwork)
5753 artwork_current_identifier = setup_artwork_set;
5754 else if (leveldir_artwork_set != NULL)
5755 artwork_current_identifier = leveldir_artwork_set;
5756 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5757 artwork_current_identifier = leveldir_identifier;
5759 artwork_current_identifier = setup_artwork_set;
5762 /* 2nd step: check if it is really needed to reload artwork set
5763 ------------------------------------------------------------ */
5765 /* ---------- reload if level set and also artwork set has changed ------- */
5766 if (leveldir_current_identifier[type] != leveldir_identifier &&
5767 (last_has_level_artwork_set[type] || has_level_artwork_set))
5768 artwork_new_identifier = artwork_current_identifier;
5770 leveldir_current_identifier[type] = leveldir_identifier;
5771 last_has_level_artwork_set[type] = has_level_artwork_set;
5773 /* ---------- reload if "override artwork" setting has changed ----------- */
5774 if (last_override_level_artwork[type] != setup_override_artwork)
5775 artwork_new_identifier = artwork_current_identifier;
5777 last_override_level_artwork[type] = setup_override_artwork;
5779 /* ---------- reload if current artwork identifier has changed ----------- */
5780 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5781 artwork_current_identifier))
5782 artwork_new_identifier = artwork_current_identifier;
5784 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5786 /* ---------- do not reload directly after starting ---------------------- */
5787 if (!initialized[type])
5788 artwork_new_identifier = NULL;
5790 initialized[type] = TRUE;
5792 return artwork_new_identifier;
5795 void ReloadCustomArtwork(int force_reload)
5797 int last_game_status = game_status; /* save current game status */
5798 char *gfx_new_identifier;
5799 char *snd_new_identifier;
5800 char *mus_new_identifier;
5801 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5802 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5803 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5804 boolean reload_needed;
5806 InitOverrideArtwork();
5808 force_reload_gfx |= AdjustGraphicsForEMC();
5810 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5811 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5812 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5814 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5815 snd_new_identifier != NULL || force_reload_snd ||
5816 mus_new_identifier != NULL || force_reload_mus);
5821 print_timestamp_init("ReloadCustomArtwork");
5823 SetGameStatus(GAME_MODE_LOADING);
5825 FadeOut(REDRAW_ALL);
5827 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5828 print_timestamp_time("ClearRectangle");
5832 if (gfx_new_identifier != NULL || force_reload_gfx)
5835 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5836 artwork.gfx_current_identifier,
5838 artwork.gfx_current->identifier,
5839 leveldir_current->graphics_set);
5843 print_timestamp_time("InitImages");
5846 if (snd_new_identifier != NULL || force_reload_snd)
5848 InitSound(snd_new_identifier);
5849 print_timestamp_time("InitSound");
5852 if (mus_new_identifier != NULL || force_reload_mus)
5854 InitMusic(mus_new_identifier);
5855 print_timestamp_time("InitMusic");
5860 SetGameStatus(last_game_status); /* restore current game status */
5862 init_last = init; /* switch to new busy animation */
5864 FadeOut(REDRAW_ALL);
5866 RedrawGlobalBorder();
5868 /* force redraw of (open or closed) door graphics */
5869 SetDoorState(DOOR_OPEN_ALL);
5870 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5872 FadeSetEnterScreen();
5873 FadeSkipNextFadeOut();
5875 print_timestamp_done("ReloadCustomArtwork");
5877 LimitScreenUpdates(FALSE);
5880 void KeyboardAutoRepeatOffUnlessAutoplay()
5882 if (global.autoplay_leveldir == NULL)
5883 KeyboardAutoRepeatOff();
5886 void DisplayExitMessage(char *format, va_list ap)
5888 // check if draw buffer and fonts for exit message are already available
5889 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5892 int font_1 = FC_RED;
5893 int font_2 = FC_YELLOW;
5894 int font_3 = FC_BLUE;
5895 int font_width = getFontWidth(font_2);
5896 int font_height = getFontHeight(font_2);
5899 int sxsize = WIN_XSIZE - 2 * sx;
5900 int sysize = WIN_YSIZE - 2 * sy;
5901 int line_length = sxsize / font_width;
5902 int max_lines = sysize / font_height;
5903 int num_lines_printed;
5907 gfx.sxsize = sxsize;
5908 gfx.sysize = sysize;
5912 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5914 DrawTextSCentered(sy, font_1, "Fatal error:");
5915 sy += 3 * font_height;;
5918 DrawTextBufferVA(sx, sy, format, ap, font_2,
5919 line_length, line_length, max_lines,
5920 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5921 sy += (num_lines_printed + 3) * font_height;
5923 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5924 sy += 3 * font_height;
5927 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5928 line_length, line_length, max_lines,
5929 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5931 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5933 redraw_mask = REDRAW_ALL;
5935 /* force drawing exit message even if screen updates are currently limited */
5936 LimitScreenUpdates(FALSE);
5940 /* deactivate toons on error message screen */
5941 setup.toons = FALSE;
5943 WaitForEventToContinue();
5947 /* ========================================================================= */
5949 /* ========================================================================= */
5953 print_timestamp_init("OpenAll");
5955 SetGameStatus(GAME_MODE_LOADING);
5959 InitGlobal(); /* initialize some global variables */
5961 print_timestamp_time("[init global stuff]");
5965 print_timestamp_time("[init setup/config stuff (1)]");
5969 if (options.execute_command)
5970 Execute_Command(options.execute_command);
5972 if (options.serveronly)
5974 #if defined(PLATFORM_UNIX)
5975 NetworkServer(options.server_port, options.serveronly);
5977 Error(ERR_WARN, "networking only supported in Unix version");
5980 exit(0); /* never reached, server loops forever */
5984 print_timestamp_time("[init setup/config stuff (2)]");
5986 print_timestamp_time("[init setup/config stuff (3)]");
5987 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5988 print_timestamp_time("[init setup/config stuff (4)]");
5989 InitArtworkConfig(); /* needed before forking sound child process */
5990 print_timestamp_time("[init setup/config stuff (5)]");
5992 print_timestamp_time("[init setup/config stuff (6)]");
5994 InitRND(NEW_RANDOMIZE);
5995 InitSimpleRandom(NEW_RANDOMIZE);
5999 print_timestamp_time("[init setup/config stuff]");
6002 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6006 print_timestamp_time("[init video stuff]");
6008 InitElementPropertiesStatic();
6009 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6010 InitElementPropertiesGfxElement();
6012 print_timestamp_time("[init element properties stuff]");
6016 print_timestamp_time("InitGfx");
6019 print_timestamp_time("InitLevelInfo");
6021 InitLevelArtworkInfo();
6022 print_timestamp_time("InitLevelArtworkInfo");
6024 InitOverrideArtwork(); /* needs to know current level directory */
6025 print_timestamp_time("InitOverrideArtwork");
6027 InitImages(); /* needs to know current level directory */
6028 print_timestamp_time("InitImages");
6030 InitSound(NULL); /* needs to know current level directory */
6031 print_timestamp_time("InitSound");
6033 InitMusic(NULL); /* needs to know current level directory */
6034 print_timestamp_time("InitMusic");
6038 InitGfxBackground();
6043 if (global.autoplay_leveldir)
6048 else if (global.convert_leveldir)
6053 else if (global.create_images_dir)
6055 CreateLevelSketchImages();
6059 SetGameStatus(GAME_MODE_MAIN);
6061 FadeSetEnterScreen();
6062 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6063 FadeSkipNextFadeOut();
6065 print_timestamp_time("[post-artwork]");
6067 print_timestamp_done("OpenAll");
6071 InitNetworkServer();
6074 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6076 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6077 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6078 #if defined(PLATFORM_ANDROID)
6079 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6080 SDL_AndroidGetInternalStoragePath());
6081 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6082 SDL_AndroidGetExternalStoragePath());
6083 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6084 (SDL_AndroidGetExternalStorageState() &
6085 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6086 SDL_AndroidGetExternalStorageState() &
6087 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6092 void CloseAllAndExit(int exit_value)
6097 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6104 #if defined(TARGET_SDL)
6105 #if defined(TARGET_SDL2)
6107 // set a flag to tell the network server thread to quit and wait for it
6108 // using SDL_WaitThread()
6110 if (network_server) /* terminate network server */
6111 SDL_KillThread(server_thread);
6115 CloseVideoDisplay();
6116 ClosePlatformDependentStuff();
6118 if (exit_value != 0 && !options.execute_command)
6120 /* fall back to default level set (current set may have caused an error) */
6121 SaveLevelSetup_LastSeries_Deactivate();
6123 /* tell user where to find error log file which may contain more details */
6124 // (error notification now directly displayed on screen inside R'n'D
6125 // NotifyUserAboutErrorFile(); /* currently only works for Windows */