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++)
1720 Bitmap *src_bitmap = graphic_info[i].bitmap;
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 */
1741 /* do not use getGraphicSourceXY() here to get position of first frame; */
1742 /* this avoids calculating wrong start position for out-of-bounds frame */
1743 src_x = graphic_info[i].src_x;
1744 src_y = graphic_info[i].src_y;
1746 if (program.headless)
1749 if (src_x < 0 || src_y < 0 ||
1750 src_x + width > src_bitmap_width ||
1751 src_y + height > src_bitmap_height)
1753 Error(ERR_INFO_LINE, "-");
1754 Error(ERR_INFO, "warning: error found in config file:");
1755 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1756 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1757 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1758 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1760 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1761 src_x, src_y, src_bitmap_width, src_bitmap_height);
1762 Error(ERR_INFO, "custom graphic rejected for this element/action");
1764 if (i == fallback_graphic)
1765 Error(ERR_EXIT, "no fallback graphic available");
1767 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1768 Error(ERR_INFO_LINE, "-");
1770 graphic_info[i] = graphic_info[fallback_graphic];
1772 /* if first frame out of bounds, do not check last frame anymore */
1776 /* check if last animation frame is inside specified bitmap */
1778 last_frame = graphic_info[i].anim_frames - 1;
1779 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1781 if (src_x < 0 || src_y < 0 ||
1782 src_x + width > src_bitmap_width ||
1783 src_y + height > src_bitmap_height)
1785 Error(ERR_INFO_LINE, "-");
1786 Error(ERR_INFO, "warning: error found in config file:");
1787 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1788 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1789 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1790 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1792 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1793 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1794 Error(ERR_INFO, "custom graphic rejected for this element/action");
1796 if (i == fallback_graphic)
1797 Error(ERR_EXIT, "no fallback graphic available");
1799 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1800 Error(ERR_INFO_LINE, "-");
1802 graphic_info[i] = graphic_info[fallback_graphic];
1807 static void InitGraphicCompatibilityInfo()
1809 struct FileInfo *fi_global_door =
1810 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1811 int num_images = getImageListSize();
1814 /* the following compatibility handling is needed for the following case:
1815 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1816 graphics mainly used for door and panel graphics, like editor, tape and
1817 in-game buttons with hard-coded bitmap positions and button sizes; as
1818 these graphics now have individual definitions, redefining "global.door"
1819 to change all these graphics at once like before does not work anymore
1820 (because all those individual definitions still have their default values);
1821 to solve this, remap all those individual definitions that are not
1822 redefined to the new bitmap of "global.door" if it was redefined */
1824 /* special compatibility handling if image "global.door" was redefined */
1825 if (fi_global_door->redefined)
1827 for (i = 0; i < num_images; i++)
1829 struct FileInfo *fi = getImageListEntryFromImageID(i);
1831 /* process only those images that still use the default settings */
1834 /* process all images which default to same image as "global.door" */
1835 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1837 // printf("::: special treatment needed for token '%s'\n", fi->token);
1839 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1840 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1846 InitGraphicCompatibilityInfo_Doors();
1849 static void InitElementSoundInfo()
1851 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1852 int num_property_mappings = getSoundListPropertyMappingSize();
1855 /* set values to -1 to identify later as "uninitialized" values */
1856 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1857 for (act = 0; act < NUM_ACTIONS; act++)
1858 element_info[i].sound[act] = -1;
1860 /* initialize element/sound mapping from static configuration */
1861 for (i = 0; element_to_sound[i].element > -1; i++)
1863 int element = element_to_sound[i].element;
1864 int action = element_to_sound[i].action;
1865 int sound = element_to_sound[i].sound;
1866 boolean is_class = element_to_sound[i].is_class;
1869 action = ACTION_DEFAULT;
1872 element_info[element].sound[action] = sound;
1874 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1875 if (strEqual(element_info[j].class_name,
1876 element_info[element].class_name))
1877 element_info[j].sound[action] = sound;
1880 /* initialize element class/sound mapping from dynamic configuration */
1881 for (i = 0; i < num_property_mappings; i++)
1883 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1884 int action = property_mapping[i].ext1_index;
1885 int sound = property_mapping[i].artwork_index;
1887 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1891 action = ACTION_DEFAULT;
1893 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1894 if (strEqual(element_info[j].class_name,
1895 element_info[element_class].class_name))
1896 element_info[j].sound[action] = sound;
1899 /* initialize element/sound mapping from dynamic configuration */
1900 for (i = 0; i < num_property_mappings; i++)
1902 int element = property_mapping[i].base_index;
1903 int action = property_mapping[i].ext1_index;
1904 int sound = property_mapping[i].artwork_index;
1906 if (element >= MAX_NUM_ELEMENTS)
1910 action = ACTION_DEFAULT;
1912 element_info[element].sound[action] = sound;
1915 /* now set all '-1' values to element specific default values */
1916 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1918 for (act = 0; act < NUM_ACTIONS; act++)
1920 /* generic default action sound (defined by "[default]" directive) */
1921 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1923 /* look for special default action sound (classic game specific) */
1924 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1925 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1926 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1927 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1928 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1929 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1931 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1932 /* !!! make this better !!! */
1933 if (i == EL_EMPTY_SPACE)
1934 default_action_sound = element_info[EL_DEFAULT].sound[act];
1936 /* no sound for this specific action -- use default action sound */
1937 if (element_info[i].sound[act] == -1)
1938 element_info[i].sound[act] = default_action_sound;
1942 /* copy sound settings to some elements that are only stored in level file
1943 in native R'n'D levels, but are used by game engine in native EM levels */
1944 for (i = 0; copy_properties[i][0] != -1; i++)
1945 for (j = 1; j <= 4; j++)
1946 for (act = 0; act < NUM_ACTIONS; act++)
1947 element_info[copy_properties[i][j]].sound[act] =
1948 element_info[copy_properties[i][0]].sound[act];
1951 static void InitGameModeSoundInfo()
1955 /* set values to -1 to identify later as "uninitialized" values */
1956 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1959 /* initialize gamemode/sound mapping from static configuration */
1960 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1962 int gamemode = gamemode_to_sound[i].gamemode;
1963 int sound = gamemode_to_sound[i].sound;
1966 gamemode = GAME_MODE_DEFAULT;
1968 menu.sound[gamemode] = sound;
1971 /* now set all '-1' values to levelset specific default values */
1972 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1973 if (menu.sound[i] == -1)
1974 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1977 static void set_sound_parameters(int sound, char **parameter_raw)
1979 int parameter[NUM_SND_ARGS];
1982 /* get integer values from string parameters */
1983 for (i = 0; i < NUM_SND_ARGS; i++)
1985 get_parameter_value(parameter_raw[i],
1986 sound_config_suffix[i].token,
1987 sound_config_suffix[i].type);
1989 /* explicit loop mode setting in configuration overrides default value */
1990 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1991 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1993 /* sound volume to change the original volume when loading the sound file */
1994 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1996 /* sound priority to give certain sounds a higher or lower priority */
1997 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2000 static void InitSoundInfo()
2002 int *sound_effect_properties;
2003 int num_sounds = getSoundListSize();
2006 checked_free(sound_info);
2008 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2009 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2011 /* initialize sound effect for all elements to "no sound" */
2012 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2013 for (j = 0; j < NUM_ACTIONS; j++)
2014 element_info[i].sound[j] = SND_UNDEFINED;
2016 for (i = 0; i < num_sounds; i++)
2018 struct FileInfo *sound = getSoundListEntry(i);
2019 int len_effect_text = strlen(sound->token);
2021 sound_effect_properties[i] = ACTION_OTHER;
2022 sound_info[i].loop = FALSE; /* default: play sound only once */
2024 /* determine all loop sounds and identify certain sound classes */
2026 for (j = 0; element_action_info[j].suffix; j++)
2028 int len_action_text = strlen(element_action_info[j].suffix);
2030 if (len_action_text < len_effect_text &&
2031 strEqual(&sound->token[len_effect_text - len_action_text],
2032 element_action_info[j].suffix))
2034 sound_effect_properties[i] = element_action_info[j].value;
2035 sound_info[i].loop = element_action_info[j].is_loop_sound;
2041 /* associate elements and some selected sound actions */
2043 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2045 if (element_info[j].class_name)
2047 int len_class_text = strlen(element_info[j].class_name);
2049 if (len_class_text + 1 < len_effect_text &&
2050 strncmp(sound->token,
2051 element_info[j].class_name, len_class_text) == 0 &&
2052 sound->token[len_class_text] == '.')
2054 int sound_action_value = sound_effect_properties[i];
2056 element_info[j].sound[sound_action_value] = i;
2061 set_sound_parameters(i, sound->parameter);
2064 free(sound_effect_properties);
2067 static void InitGameModeMusicInfo()
2069 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2070 int num_property_mappings = getMusicListPropertyMappingSize();
2071 int default_levelset_music = -1;
2074 /* set values to -1 to identify later as "uninitialized" values */
2075 for (i = 0; i < MAX_LEVELS; i++)
2076 levelset.music[i] = -1;
2077 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2080 /* initialize gamemode/music mapping from static configuration */
2081 for (i = 0; gamemode_to_music[i].music > -1; i++)
2083 int gamemode = gamemode_to_music[i].gamemode;
2084 int music = gamemode_to_music[i].music;
2087 gamemode = GAME_MODE_DEFAULT;
2089 menu.music[gamemode] = music;
2092 /* initialize gamemode/music mapping from dynamic configuration */
2093 for (i = 0; i < num_property_mappings; i++)
2095 int prefix = property_mapping[i].base_index;
2096 int gamemode = property_mapping[i].ext2_index;
2097 int level = property_mapping[i].ext3_index;
2098 int music = property_mapping[i].artwork_index;
2100 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2104 gamemode = GAME_MODE_DEFAULT;
2106 /* level specific music only allowed for in-game music */
2107 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2108 gamemode = GAME_MODE_PLAYING;
2113 default_levelset_music = music;
2116 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2117 levelset.music[level] = music;
2118 if (gamemode != GAME_MODE_PLAYING)
2119 menu.music[gamemode] = music;
2122 /* now set all '-1' values to menu specific default values */
2123 /* (undefined values of "levelset.music[]" might stay at "-1" to
2124 allow dynamic selection of music files from music directory!) */
2125 for (i = 0; i < MAX_LEVELS; i++)
2126 if (levelset.music[i] == -1)
2127 levelset.music[i] = default_levelset_music;
2128 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2129 if (menu.music[i] == -1)
2130 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2133 static void set_music_parameters(int music, char **parameter_raw)
2135 int parameter[NUM_MUS_ARGS];
2138 /* get integer values from string parameters */
2139 for (i = 0; i < NUM_MUS_ARGS; i++)
2141 get_parameter_value(parameter_raw[i],
2142 music_config_suffix[i].token,
2143 music_config_suffix[i].type);
2145 /* explicit loop mode setting in configuration overrides default value */
2146 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2147 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2150 static void InitMusicInfo()
2152 int num_music = getMusicListSize();
2155 checked_free(music_info);
2157 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2159 for (i = 0; i < num_music; i++)
2161 struct FileInfo *music = getMusicListEntry(i);
2162 int len_music_text = strlen(music->token);
2164 music_info[i].loop = TRUE; /* default: play music in loop mode */
2166 /* determine all loop music */
2168 for (j = 0; music_prefix_info[j].prefix; j++)
2170 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2172 if (len_prefix_text < len_music_text &&
2173 strncmp(music->token,
2174 music_prefix_info[j].prefix, len_prefix_text) == 0)
2176 music_info[i].loop = music_prefix_info[j].is_loop_music;
2182 set_music_parameters(i, music->parameter);
2186 static void ReinitializeGraphics()
2188 print_timestamp_init("ReinitializeGraphics");
2190 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2192 InitGraphicInfo(); /* graphic properties mapping */
2193 print_timestamp_time("InitGraphicInfo");
2194 InitElementGraphicInfo(); /* element game graphic mapping */
2195 print_timestamp_time("InitElementGraphicInfo");
2196 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2197 print_timestamp_time("InitElementSpecialGraphicInfo");
2199 InitElementSmallImages(); /* scale elements to all needed sizes */
2200 print_timestamp_time("InitElementSmallImages");
2201 InitScaledImages(); /* scale all other images, if needed */
2202 print_timestamp_time("InitScaledImages");
2203 InitBitmapPointers(); /* set standard size bitmap pointers */
2204 print_timestamp_time("InitBitmapPointers");
2205 InitFontGraphicInfo(); /* initialize text drawing functions */
2206 print_timestamp_time("InitFontGraphicInfo");
2207 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2208 print_timestamp_time("InitGlobalAnimGraphicInfo");
2210 InitImageTextures(); /* create textures for certain images */
2211 print_timestamp_time("InitImageTextures");
2213 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2214 print_timestamp_time("InitGraphicInfo_EM");
2216 InitGraphicCompatibilityInfo();
2217 print_timestamp_time("InitGraphicCompatibilityInfo");
2219 SetMainBackgroundImage(IMG_BACKGROUND);
2220 print_timestamp_time("SetMainBackgroundImage");
2221 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2222 print_timestamp_time("SetDoorBackgroundImage");
2225 print_timestamp_time("InitGadgets");
2227 print_timestamp_time("InitDoors");
2229 print_timestamp_done("ReinitializeGraphics");
2232 static void ReinitializeSounds()
2234 InitSoundInfo(); /* sound properties mapping */
2235 InitElementSoundInfo(); /* element game sound mapping */
2236 InitGameModeSoundInfo(); /* game mode sound mapping */
2237 InitGlobalAnimSoundInfo(); /* global animation sound settings */
2239 InitPlayLevelSound(); /* internal game sound settings */
2242 static void ReinitializeMusic()
2244 InitMusicInfo(); /* music properties mapping */
2245 InitGameModeMusicInfo(); /* game mode music mapping */
2246 InitGlobalAnimMusicInfo(); /* global animation music settings */
2249 static int get_special_property_bit(int element, int property_bit_nr)
2251 struct PropertyBitInfo
2257 static struct PropertyBitInfo pb_can_move_into_acid[] =
2259 /* the player may be able fall into acid when gravity is activated */
2264 { EL_SP_MURPHY, 0 },
2265 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2267 /* all elements that can move may be able to also move into acid */
2270 { EL_BUG_RIGHT, 1 },
2273 { EL_SPACESHIP, 2 },
2274 { EL_SPACESHIP_LEFT, 2 },
2275 { EL_SPACESHIP_RIGHT, 2 },
2276 { EL_SPACESHIP_UP, 2 },
2277 { EL_SPACESHIP_DOWN, 2 },
2278 { EL_BD_BUTTERFLY, 3 },
2279 { EL_BD_BUTTERFLY_LEFT, 3 },
2280 { EL_BD_BUTTERFLY_RIGHT, 3 },
2281 { EL_BD_BUTTERFLY_UP, 3 },
2282 { EL_BD_BUTTERFLY_DOWN, 3 },
2283 { EL_BD_FIREFLY, 4 },
2284 { EL_BD_FIREFLY_LEFT, 4 },
2285 { EL_BD_FIREFLY_RIGHT, 4 },
2286 { EL_BD_FIREFLY_UP, 4 },
2287 { EL_BD_FIREFLY_DOWN, 4 },
2289 { EL_YAMYAM_LEFT, 5 },
2290 { EL_YAMYAM_RIGHT, 5 },
2291 { EL_YAMYAM_UP, 5 },
2292 { EL_YAMYAM_DOWN, 5 },
2293 { EL_DARK_YAMYAM, 6 },
2296 { EL_PACMAN_LEFT, 8 },
2297 { EL_PACMAN_RIGHT, 8 },
2298 { EL_PACMAN_UP, 8 },
2299 { EL_PACMAN_DOWN, 8 },
2301 { EL_MOLE_LEFT, 9 },
2302 { EL_MOLE_RIGHT, 9 },
2304 { EL_MOLE_DOWN, 9 },
2308 { EL_SATELLITE, 13 },
2309 { EL_SP_SNIKSNAK, 14 },
2310 { EL_SP_ELECTRON, 15 },
2313 { EL_EMC_ANDROID, 18 },
2318 static struct PropertyBitInfo pb_dont_collide_with[] =
2320 { EL_SP_SNIKSNAK, 0 },
2321 { EL_SP_ELECTRON, 1 },
2329 struct PropertyBitInfo *pb_info;
2332 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2333 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2338 struct PropertyBitInfo *pb_info = NULL;
2341 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2342 if (pb_definition[i].bit_nr == property_bit_nr)
2343 pb_info = pb_definition[i].pb_info;
2345 if (pb_info == NULL)
2348 for (i = 0; pb_info[i].element != -1; i++)
2349 if (pb_info[i].element == element)
2350 return pb_info[i].bit_nr;
2355 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2356 boolean property_value)
2358 int bit_nr = get_special_property_bit(element, property_bit_nr);
2363 *bitfield |= (1 << bit_nr);
2365 *bitfield &= ~(1 << bit_nr);
2369 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2371 int bit_nr = get_special_property_bit(element, property_bit_nr);
2374 return ((*bitfield & (1 << bit_nr)) != 0);
2379 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2381 static int group_nr;
2382 static struct ElementGroupInfo *group;
2383 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2386 if (actual_group == NULL) /* not yet initialized */
2389 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2391 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2392 group_element - EL_GROUP_START + 1);
2394 /* replace element which caused too deep recursion by question mark */
2395 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2400 if (recursion_depth == 0) /* initialization */
2402 group = actual_group;
2403 group_nr = GROUP_NR(group_element);
2405 group->num_elements_resolved = 0;
2406 group->choice_pos = 0;
2408 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2409 element_info[i].in_group[group_nr] = FALSE;
2412 for (i = 0; i < actual_group->num_elements; i++)
2414 int element = actual_group->element[i];
2416 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2419 if (IS_GROUP_ELEMENT(element))
2420 ResolveGroupElementExt(element, recursion_depth + 1);
2423 group->element_resolved[group->num_elements_resolved++] = element;
2424 element_info[element].in_group[group_nr] = TRUE;
2429 void ResolveGroupElement(int group_element)
2431 ResolveGroupElementExt(group_element, 0);
2434 void InitElementPropertiesStatic()
2436 static boolean clipboard_elements_initialized = FALSE;
2438 static int ep_diggable[] =
2443 EL_SP_BUGGY_BASE_ACTIVATING,
2446 EL_INVISIBLE_SAND_ACTIVE,
2449 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2450 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2455 EL_SP_BUGGY_BASE_ACTIVE,
2462 static int ep_collectible_only[] =
2484 EL_DYNABOMB_INCREASE_NUMBER,
2485 EL_DYNABOMB_INCREASE_SIZE,
2486 EL_DYNABOMB_INCREASE_POWER,
2504 /* !!! handle separately !!! */
2505 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2511 static int ep_dont_run_into[] =
2513 /* same elements as in 'ep_dont_touch' */
2519 /* same elements as in 'ep_dont_collide_with' */
2531 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2536 EL_SP_BUGGY_BASE_ACTIVE,
2543 static int ep_dont_collide_with[] =
2545 /* same elements as in 'ep_dont_touch' */
2562 static int ep_dont_touch[] =
2572 static int ep_indestructible[] =
2576 EL_ACID_POOL_TOPLEFT,
2577 EL_ACID_POOL_TOPRIGHT,
2578 EL_ACID_POOL_BOTTOMLEFT,
2579 EL_ACID_POOL_BOTTOM,
2580 EL_ACID_POOL_BOTTOMRIGHT,
2581 EL_SP_HARDWARE_GRAY,
2582 EL_SP_HARDWARE_GREEN,
2583 EL_SP_HARDWARE_BLUE,
2585 EL_SP_HARDWARE_YELLOW,
2586 EL_SP_HARDWARE_BASE_1,
2587 EL_SP_HARDWARE_BASE_2,
2588 EL_SP_HARDWARE_BASE_3,
2589 EL_SP_HARDWARE_BASE_4,
2590 EL_SP_HARDWARE_BASE_5,
2591 EL_SP_HARDWARE_BASE_6,
2592 EL_INVISIBLE_STEELWALL,
2593 EL_INVISIBLE_STEELWALL_ACTIVE,
2594 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2595 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2596 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2597 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2598 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2599 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2600 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2601 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2602 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2603 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2604 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2605 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2607 EL_LIGHT_SWITCH_ACTIVE,
2608 EL_SIGN_EXCLAMATION,
2609 EL_SIGN_RADIOACTIVITY,
2616 EL_SIGN_ENTRY_FORBIDDEN,
2617 EL_SIGN_EMERGENCY_EXIT,
2625 EL_STEEL_EXIT_CLOSED,
2627 EL_STEEL_EXIT_OPENING,
2628 EL_STEEL_EXIT_CLOSING,
2629 EL_EM_STEEL_EXIT_CLOSED,
2630 EL_EM_STEEL_EXIT_OPEN,
2631 EL_EM_STEEL_EXIT_OPENING,
2632 EL_EM_STEEL_EXIT_CLOSING,
2633 EL_DC_STEELWALL_1_LEFT,
2634 EL_DC_STEELWALL_1_RIGHT,
2635 EL_DC_STEELWALL_1_TOP,
2636 EL_DC_STEELWALL_1_BOTTOM,
2637 EL_DC_STEELWALL_1_HORIZONTAL,
2638 EL_DC_STEELWALL_1_VERTICAL,
2639 EL_DC_STEELWALL_1_TOPLEFT,
2640 EL_DC_STEELWALL_1_TOPRIGHT,
2641 EL_DC_STEELWALL_1_BOTTOMLEFT,
2642 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2643 EL_DC_STEELWALL_1_TOPLEFT_2,
2644 EL_DC_STEELWALL_1_TOPRIGHT_2,
2645 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2646 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2647 EL_DC_STEELWALL_2_LEFT,
2648 EL_DC_STEELWALL_2_RIGHT,
2649 EL_DC_STEELWALL_2_TOP,
2650 EL_DC_STEELWALL_2_BOTTOM,
2651 EL_DC_STEELWALL_2_HORIZONTAL,
2652 EL_DC_STEELWALL_2_VERTICAL,
2653 EL_DC_STEELWALL_2_MIDDLE,
2654 EL_DC_STEELWALL_2_SINGLE,
2655 EL_STEELWALL_SLIPPERY,
2669 EL_GATE_1_GRAY_ACTIVE,
2670 EL_GATE_2_GRAY_ACTIVE,
2671 EL_GATE_3_GRAY_ACTIVE,
2672 EL_GATE_4_GRAY_ACTIVE,
2681 EL_EM_GATE_1_GRAY_ACTIVE,
2682 EL_EM_GATE_2_GRAY_ACTIVE,
2683 EL_EM_GATE_3_GRAY_ACTIVE,
2684 EL_EM_GATE_4_GRAY_ACTIVE,
2693 EL_EMC_GATE_5_GRAY_ACTIVE,
2694 EL_EMC_GATE_6_GRAY_ACTIVE,
2695 EL_EMC_GATE_7_GRAY_ACTIVE,
2696 EL_EMC_GATE_8_GRAY_ACTIVE,
2698 EL_DC_GATE_WHITE_GRAY,
2699 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2700 EL_DC_GATE_FAKE_GRAY,
2702 EL_SWITCHGATE_OPENING,
2703 EL_SWITCHGATE_CLOSED,
2704 EL_SWITCHGATE_CLOSING,
2705 EL_DC_SWITCHGATE_SWITCH_UP,
2706 EL_DC_SWITCHGATE_SWITCH_DOWN,
2708 EL_TIMEGATE_OPENING,
2710 EL_TIMEGATE_CLOSING,
2711 EL_DC_TIMEGATE_SWITCH,
2712 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2716 EL_TUBE_VERTICAL_LEFT,
2717 EL_TUBE_VERTICAL_RIGHT,
2718 EL_TUBE_HORIZONTAL_UP,
2719 EL_TUBE_HORIZONTAL_DOWN,
2724 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2725 EL_EXPANDABLE_STEELWALL_VERTICAL,
2726 EL_EXPANDABLE_STEELWALL_ANY,
2731 static int ep_slippery[] =
2745 EL_ROBOT_WHEEL_ACTIVE,
2751 EL_ACID_POOL_TOPLEFT,
2752 EL_ACID_POOL_TOPRIGHT,
2762 EL_STEELWALL_SLIPPERY,
2765 EL_EMC_WALL_SLIPPERY_1,
2766 EL_EMC_WALL_SLIPPERY_2,
2767 EL_EMC_WALL_SLIPPERY_3,
2768 EL_EMC_WALL_SLIPPERY_4,
2770 EL_EMC_MAGIC_BALL_ACTIVE,
2775 static int ep_can_change[] =
2780 static int ep_can_move[] =
2782 /* same elements as in 'pb_can_move_into_acid' */
2805 static int ep_can_fall[] =
2819 EL_QUICKSAND_FAST_FULL,
2821 EL_BD_MAGIC_WALL_FULL,
2822 EL_DC_MAGIC_WALL_FULL,
2836 static int ep_can_smash_player[] =
2862 static int ep_can_smash_enemies[] =
2871 static int ep_can_smash_everything[] =
2880 static int ep_explodes_by_fire[] =
2882 /* same elements as in 'ep_explodes_impact' */
2887 /* same elements as in 'ep_explodes_smashed' */
2897 EL_EM_DYNAMITE_ACTIVE,
2898 EL_DYNABOMB_PLAYER_1_ACTIVE,
2899 EL_DYNABOMB_PLAYER_2_ACTIVE,
2900 EL_DYNABOMB_PLAYER_3_ACTIVE,
2901 EL_DYNABOMB_PLAYER_4_ACTIVE,
2902 EL_DYNABOMB_INCREASE_NUMBER,
2903 EL_DYNABOMB_INCREASE_SIZE,
2904 EL_DYNABOMB_INCREASE_POWER,
2905 EL_SP_DISK_RED_ACTIVE,
2919 static int ep_explodes_smashed[] =
2921 /* same elements as in 'ep_explodes_impact' */
2935 static int ep_explodes_impact[] =
2944 static int ep_walkable_over[] =
2948 EL_SOKOBAN_FIELD_EMPTY,
2955 EL_EM_STEEL_EXIT_OPEN,
2956 EL_EM_STEEL_EXIT_OPENING,
2965 EL_GATE_1_GRAY_ACTIVE,
2966 EL_GATE_2_GRAY_ACTIVE,
2967 EL_GATE_3_GRAY_ACTIVE,
2968 EL_GATE_4_GRAY_ACTIVE,
2976 static int ep_walkable_inside[] =
2981 EL_TUBE_VERTICAL_LEFT,
2982 EL_TUBE_VERTICAL_RIGHT,
2983 EL_TUBE_HORIZONTAL_UP,
2984 EL_TUBE_HORIZONTAL_DOWN,
2993 static int ep_walkable_under[] =
2998 static int ep_passable_over[] =
3008 EL_EM_GATE_1_GRAY_ACTIVE,
3009 EL_EM_GATE_2_GRAY_ACTIVE,
3010 EL_EM_GATE_3_GRAY_ACTIVE,
3011 EL_EM_GATE_4_GRAY_ACTIVE,
3020 EL_EMC_GATE_5_GRAY_ACTIVE,
3021 EL_EMC_GATE_6_GRAY_ACTIVE,
3022 EL_EMC_GATE_7_GRAY_ACTIVE,
3023 EL_EMC_GATE_8_GRAY_ACTIVE,
3025 EL_DC_GATE_WHITE_GRAY,
3026 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3033 static int ep_passable_inside[] =
3039 EL_SP_PORT_HORIZONTAL,
3040 EL_SP_PORT_VERTICAL,
3042 EL_SP_GRAVITY_PORT_LEFT,
3043 EL_SP_GRAVITY_PORT_RIGHT,
3044 EL_SP_GRAVITY_PORT_UP,
3045 EL_SP_GRAVITY_PORT_DOWN,
3046 EL_SP_GRAVITY_ON_PORT_LEFT,
3047 EL_SP_GRAVITY_ON_PORT_RIGHT,
3048 EL_SP_GRAVITY_ON_PORT_UP,
3049 EL_SP_GRAVITY_ON_PORT_DOWN,
3050 EL_SP_GRAVITY_OFF_PORT_LEFT,
3051 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3052 EL_SP_GRAVITY_OFF_PORT_UP,
3053 EL_SP_GRAVITY_OFF_PORT_DOWN,
3058 static int ep_passable_under[] =
3063 static int ep_droppable[] =
3068 static int ep_explodes_1x1_old[] =
3073 static int ep_pushable[] =
3085 EL_SOKOBAN_FIELD_FULL,
3094 static int ep_explodes_cross_old[] =
3099 static int ep_protected[] =
3101 /* same elements as in 'ep_walkable_inside' */
3105 EL_TUBE_VERTICAL_LEFT,
3106 EL_TUBE_VERTICAL_RIGHT,
3107 EL_TUBE_HORIZONTAL_UP,
3108 EL_TUBE_HORIZONTAL_DOWN,
3114 /* same elements as in 'ep_passable_over' */
3123 EL_EM_GATE_1_GRAY_ACTIVE,
3124 EL_EM_GATE_2_GRAY_ACTIVE,
3125 EL_EM_GATE_3_GRAY_ACTIVE,
3126 EL_EM_GATE_4_GRAY_ACTIVE,
3135 EL_EMC_GATE_5_GRAY_ACTIVE,
3136 EL_EMC_GATE_6_GRAY_ACTIVE,
3137 EL_EMC_GATE_7_GRAY_ACTIVE,
3138 EL_EMC_GATE_8_GRAY_ACTIVE,
3140 EL_DC_GATE_WHITE_GRAY,
3141 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3145 /* same elements as in 'ep_passable_inside' */
3150 EL_SP_PORT_HORIZONTAL,
3151 EL_SP_PORT_VERTICAL,
3153 EL_SP_GRAVITY_PORT_LEFT,
3154 EL_SP_GRAVITY_PORT_RIGHT,
3155 EL_SP_GRAVITY_PORT_UP,
3156 EL_SP_GRAVITY_PORT_DOWN,
3157 EL_SP_GRAVITY_ON_PORT_LEFT,
3158 EL_SP_GRAVITY_ON_PORT_RIGHT,
3159 EL_SP_GRAVITY_ON_PORT_UP,
3160 EL_SP_GRAVITY_ON_PORT_DOWN,
3161 EL_SP_GRAVITY_OFF_PORT_LEFT,
3162 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3163 EL_SP_GRAVITY_OFF_PORT_UP,
3164 EL_SP_GRAVITY_OFF_PORT_DOWN,
3169 static int ep_throwable[] =
3174 static int ep_can_explode[] =
3176 /* same elements as in 'ep_explodes_impact' */
3181 /* same elements as in 'ep_explodes_smashed' */
3187 /* elements that can explode by explosion or by dragonfire */
3191 EL_EM_DYNAMITE_ACTIVE,
3192 EL_DYNABOMB_PLAYER_1_ACTIVE,
3193 EL_DYNABOMB_PLAYER_2_ACTIVE,
3194 EL_DYNABOMB_PLAYER_3_ACTIVE,
3195 EL_DYNABOMB_PLAYER_4_ACTIVE,
3196 EL_DYNABOMB_INCREASE_NUMBER,
3197 EL_DYNABOMB_INCREASE_SIZE,
3198 EL_DYNABOMB_INCREASE_POWER,
3199 EL_SP_DISK_RED_ACTIVE,
3207 /* elements that can explode only by explosion */
3213 static int ep_gravity_reachable[] =
3219 EL_INVISIBLE_SAND_ACTIVE,
3224 EL_SP_PORT_HORIZONTAL,
3225 EL_SP_PORT_VERTICAL,
3227 EL_SP_GRAVITY_PORT_LEFT,
3228 EL_SP_GRAVITY_PORT_RIGHT,
3229 EL_SP_GRAVITY_PORT_UP,
3230 EL_SP_GRAVITY_PORT_DOWN,
3231 EL_SP_GRAVITY_ON_PORT_LEFT,
3232 EL_SP_GRAVITY_ON_PORT_RIGHT,
3233 EL_SP_GRAVITY_ON_PORT_UP,
3234 EL_SP_GRAVITY_ON_PORT_DOWN,
3235 EL_SP_GRAVITY_OFF_PORT_LEFT,
3236 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3237 EL_SP_GRAVITY_OFF_PORT_UP,
3238 EL_SP_GRAVITY_OFF_PORT_DOWN,
3244 static int ep_player[] =
3251 EL_SOKOBAN_FIELD_PLAYER,
3257 static int ep_can_pass_magic_wall[] =
3271 static int ep_can_pass_dc_magic_wall[] =
3287 static int ep_switchable[] =
3291 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3292 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3293 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3294 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3295 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3296 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3297 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3298 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3299 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3300 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3301 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3302 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3303 EL_SWITCHGATE_SWITCH_UP,
3304 EL_SWITCHGATE_SWITCH_DOWN,
3305 EL_DC_SWITCHGATE_SWITCH_UP,
3306 EL_DC_SWITCHGATE_SWITCH_DOWN,
3308 EL_LIGHT_SWITCH_ACTIVE,
3310 EL_DC_TIMEGATE_SWITCH,
3311 EL_BALLOON_SWITCH_LEFT,
3312 EL_BALLOON_SWITCH_RIGHT,
3313 EL_BALLOON_SWITCH_UP,
3314 EL_BALLOON_SWITCH_DOWN,
3315 EL_BALLOON_SWITCH_ANY,
3316 EL_BALLOON_SWITCH_NONE,
3319 EL_EMC_MAGIC_BALL_SWITCH,
3320 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3325 static int ep_bd_element[] =
3359 static int ep_sp_element[] =
3361 /* should always be valid */
3364 /* standard classic Supaplex elements */
3371 EL_SP_HARDWARE_GRAY,
3379 EL_SP_GRAVITY_PORT_RIGHT,
3380 EL_SP_GRAVITY_PORT_DOWN,
3381 EL_SP_GRAVITY_PORT_LEFT,
3382 EL_SP_GRAVITY_PORT_UP,
3387 EL_SP_PORT_VERTICAL,
3388 EL_SP_PORT_HORIZONTAL,
3394 EL_SP_HARDWARE_BASE_1,
3395 EL_SP_HARDWARE_GREEN,
3396 EL_SP_HARDWARE_BLUE,
3398 EL_SP_HARDWARE_YELLOW,
3399 EL_SP_HARDWARE_BASE_2,
3400 EL_SP_HARDWARE_BASE_3,
3401 EL_SP_HARDWARE_BASE_4,
3402 EL_SP_HARDWARE_BASE_5,
3403 EL_SP_HARDWARE_BASE_6,
3407 /* additional elements that appeared in newer Supaplex levels */
3410 /* additional gravity port elements (not switching, but setting gravity) */
3411 EL_SP_GRAVITY_ON_PORT_LEFT,
3412 EL_SP_GRAVITY_ON_PORT_RIGHT,
3413 EL_SP_GRAVITY_ON_PORT_UP,
3414 EL_SP_GRAVITY_ON_PORT_DOWN,
3415 EL_SP_GRAVITY_OFF_PORT_LEFT,
3416 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3417 EL_SP_GRAVITY_OFF_PORT_UP,
3418 EL_SP_GRAVITY_OFF_PORT_DOWN,
3420 /* more than one Murphy in a level results in an inactive clone */
3423 /* runtime Supaplex elements */
3424 EL_SP_DISK_RED_ACTIVE,
3425 EL_SP_TERMINAL_ACTIVE,
3426 EL_SP_BUGGY_BASE_ACTIVATING,
3427 EL_SP_BUGGY_BASE_ACTIVE,
3434 static int ep_sb_element[] =
3439 EL_SOKOBAN_FIELD_EMPTY,
3440 EL_SOKOBAN_FIELD_FULL,
3441 EL_SOKOBAN_FIELD_PLAYER,
3446 EL_INVISIBLE_STEELWALL,
3451 static int ep_gem[] =
3463 static int ep_food_dark_yamyam[] =
3491 static int ep_food_penguin[] =
3505 static int ep_food_pig[] =
3517 static int ep_historic_wall[] =
3528 EL_GATE_1_GRAY_ACTIVE,
3529 EL_GATE_2_GRAY_ACTIVE,
3530 EL_GATE_3_GRAY_ACTIVE,
3531 EL_GATE_4_GRAY_ACTIVE,
3540 EL_EM_GATE_1_GRAY_ACTIVE,
3541 EL_EM_GATE_2_GRAY_ACTIVE,
3542 EL_EM_GATE_3_GRAY_ACTIVE,
3543 EL_EM_GATE_4_GRAY_ACTIVE,
3550 EL_EXPANDABLE_WALL_HORIZONTAL,
3551 EL_EXPANDABLE_WALL_VERTICAL,
3552 EL_EXPANDABLE_WALL_ANY,
3553 EL_EXPANDABLE_WALL_GROWING,
3554 EL_BD_EXPANDABLE_WALL,
3561 EL_SP_HARDWARE_GRAY,
3562 EL_SP_HARDWARE_GREEN,
3563 EL_SP_HARDWARE_BLUE,
3565 EL_SP_HARDWARE_YELLOW,
3566 EL_SP_HARDWARE_BASE_1,
3567 EL_SP_HARDWARE_BASE_2,
3568 EL_SP_HARDWARE_BASE_3,
3569 EL_SP_HARDWARE_BASE_4,
3570 EL_SP_HARDWARE_BASE_5,
3571 EL_SP_HARDWARE_BASE_6,
3573 EL_SP_TERMINAL_ACTIVE,
3576 EL_INVISIBLE_STEELWALL,
3577 EL_INVISIBLE_STEELWALL_ACTIVE,
3579 EL_INVISIBLE_WALL_ACTIVE,
3580 EL_STEELWALL_SLIPPERY,
3597 static int ep_historic_solid[] =
3601 EL_EXPANDABLE_WALL_HORIZONTAL,
3602 EL_EXPANDABLE_WALL_VERTICAL,
3603 EL_EXPANDABLE_WALL_ANY,
3604 EL_BD_EXPANDABLE_WALL,
3617 EL_QUICKSAND_FILLING,
3618 EL_QUICKSAND_EMPTYING,
3620 EL_MAGIC_WALL_ACTIVE,
3621 EL_MAGIC_WALL_EMPTYING,
3622 EL_MAGIC_WALL_FILLING,
3626 EL_BD_MAGIC_WALL_ACTIVE,
3627 EL_BD_MAGIC_WALL_EMPTYING,
3628 EL_BD_MAGIC_WALL_FULL,
3629 EL_BD_MAGIC_WALL_FILLING,
3630 EL_BD_MAGIC_WALL_DEAD,
3639 EL_SP_TERMINAL_ACTIVE,
3643 EL_INVISIBLE_WALL_ACTIVE,
3644 EL_SWITCHGATE_SWITCH_UP,
3645 EL_SWITCHGATE_SWITCH_DOWN,
3646 EL_DC_SWITCHGATE_SWITCH_UP,
3647 EL_DC_SWITCHGATE_SWITCH_DOWN,
3649 EL_TIMEGATE_SWITCH_ACTIVE,
3650 EL_DC_TIMEGATE_SWITCH,
3651 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3663 /* the following elements are a direct copy of "indestructible" elements,
3664 except "EL_ACID", which is "indestructible", but not "solid"! */
3669 EL_ACID_POOL_TOPLEFT,
3670 EL_ACID_POOL_TOPRIGHT,
3671 EL_ACID_POOL_BOTTOMLEFT,
3672 EL_ACID_POOL_BOTTOM,
3673 EL_ACID_POOL_BOTTOMRIGHT,
3674 EL_SP_HARDWARE_GRAY,
3675 EL_SP_HARDWARE_GREEN,
3676 EL_SP_HARDWARE_BLUE,
3678 EL_SP_HARDWARE_YELLOW,
3679 EL_SP_HARDWARE_BASE_1,
3680 EL_SP_HARDWARE_BASE_2,
3681 EL_SP_HARDWARE_BASE_3,
3682 EL_SP_HARDWARE_BASE_4,
3683 EL_SP_HARDWARE_BASE_5,
3684 EL_SP_HARDWARE_BASE_6,
3685 EL_INVISIBLE_STEELWALL,
3686 EL_INVISIBLE_STEELWALL_ACTIVE,
3687 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3688 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3689 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3690 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3691 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3692 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3693 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3694 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3695 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3696 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3697 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3698 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3700 EL_LIGHT_SWITCH_ACTIVE,
3701 EL_SIGN_EXCLAMATION,
3702 EL_SIGN_RADIOACTIVITY,
3709 EL_SIGN_ENTRY_FORBIDDEN,
3710 EL_SIGN_EMERGENCY_EXIT,
3718 EL_STEEL_EXIT_CLOSED,
3720 EL_DC_STEELWALL_1_LEFT,
3721 EL_DC_STEELWALL_1_RIGHT,
3722 EL_DC_STEELWALL_1_TOP,
3723 EL_DC_STEELWALL_1_BOTTOM,
3724 EL_DC_STEELWALL_1_HORIZONTAL,
3725 EL_DC_STEELWALL_1_VERTICAL,
3726 EL_DC_STEELWALL_1_TOPLEFT,
3727 EL_DC_STEELWALL_1_TOPRIGHT,
3728 EL_DC_STEELWALL_1_BOTTOMLEFT,
3729 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3730 EL_DC_STEELWALL_1_TOPLEFT_2,
3731 EL_DC_STEELWALL_1_TOPRIGHT_2,
3732 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3733 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3734 EL_DC_STEELWALL_2_LEFT,
3735 EL_DC_STEELWALL_2_RIGHT,
3736 EL_DC_STEELWALL_2_TOP,
3737 EL_DC_STEELWALL_2_BOTTOM,
3738 EL_DC_STEELWALL_2_HORIZONTAL,
3739 EL_DC_STEELWALL_2_VERTICAL,
3740 EL_DC_STEELWALL_2_MIDDLE,
3741 EL_DC_STEELWALL_2_SINGLE,
3742 EL_STEELWALL_SLIPPERY,
3756 EL_GATE_1_GRAY_ACTIVE,
3757 EL_GATE_2_GRAY_ACTIVE,
3758 EL_GATE_3_GRAY_ACTIVE,
3759 EL_GATE_4_GRAY_ACTIVE,
3768 EL_EM_GATE_1_GRAY_ACTIVE,
3769 EL_EM_GATE_2_GRAY_ACTIVE,
3770 EL_EM_GATE_3_GRAY_ACTIVE,
3771 EL_EM_GATE_4_GRAY_ACTIVE,
3773 EL_SWITCHGATE_OPENING,
3774 EL_SWITCHGATE_CLOSED,
3775 EL_SWITCHGATE_CLOSING,
3777 EL_TIMEGATE_OPENING,
3779 EL_TIMEGATE_CLOSING,
3783 EL_TUBE_VERTICAL_LEFT,
3784 EL_TUBE_VERTICAL_RIGHT,
3785 EL_TUBE_HORIZONTAL_UP,
3786 EL_TUBE_HORIZONTAL_DOWN,
3795 static int ep_classic_enemy[] =
3812 static int ep_belt[] =
3814 EL_CONVEYOR_BELT_1_LEFT,
3815 EL_CONVEYOR_BELT_1_MIDDLE,
3816 EL_CONVEYOR_BELT_1_RIGHT,
3817 EL_CONVEYOR_BELT_2_LEFT,
3818 EL_CONVEYOR_BELT_2_MIDDLE,
3819 EL_CONVEYOR_BELT_2_RIGHT,
3820 EL_CONVEYOR_BELT_3_LEFT,
3821 EL_CONVEYOR_BELT_3_MIDDLE,
3822 EL_CONVEYOR_BELT_3_RIGHT,
3823 EL_CONVEYOR_BELT_4_LEFT,
3824 EL_CONVEYOR_BELT_4_MIDDLE,
3825 EL_CONVEYOR_BELT_4_RIGHT,
3830 static int ep_belt_active[] =
3832 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3833 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3834 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3835 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3836 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3837 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3838 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3839 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3840 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3841 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3842 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3843 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3848 static int ep_belt_switch[] =
3850 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3851 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3852 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3853 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3854 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3855 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3856 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3857 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3858 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3859 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3860 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3861 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3866 static int ep_tube[] =
3873 EL_TUBE_HORIZONTAL_UP,
3874 EL_TUBE_HORIZONTAL_DOWN,
3876 EL_TUBE_VERTICAL_LEFT,
3877 EL_TUBE_VERTICAL_RIGHT,
3883 static int ep_acid_pool[] =
3885 EL_ACID_POOL_TOPLEFT,
3886 EL_ACID_POOL_TOPRIGHT,
3887 EL_ACID_POOL_BOTTOMLEFT,
3888 EL_ACID_POOL_BOTTOM,
3889 EL_ACID_POOL_BOTTOMRIGHT,
3894 static int ep_keygate[] =
3904 EL_GATE_1_GRAY_ACTIVE,
3905 EL_GATE_2_GRAY_ACTIVE,
3906 EL_GATE_3_GRAY_ACTIVE,
3907 EL_GATE_4_GRAY_ACTIVE,
3916 EL_EM_GATE_1_GRAY_ACTIVE,
3917 EL_EM_GATE_2_GRAY_ACTIVE,
3918 EL_EM_GATE_3_GRAY_ACTIVE,
3919 EL_EM_GATE_4_GRAY_ACTIVE,
3928 EL_EMC_GATE_5_GRAY_ACTIVE,
3929 EL_EMC_GATE_6_GRAY_ACTIVE,
3930 EL_EMC_GATE_7_GRAY_ACTIVE,
3931 EL_EMC_GATE_8_GRAY_ACTIVE,
3933 EL_DC_GATE_WHITE_GRAY,
3934 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3939 static int ep_amoeboid[] =
3951 static int ep_amoebalive[] =
3962 static int ep_has_editor_content[] =
3968 EL_SOKOBAN_FIELD_PLAYER,
3985 static int ep_can_turn_each_move[] =
3987 /* !!! do something with this one !!! */
3991 static int ep_can_grow[] =
4005 static int ep_active_bomb[] =
4008 EL_EM_DYNAMITE_ACTIVE,
4009 EL_DYNABOMB_PLAYER_1_ACTIVE,
4010 EL_DYNABOMB_PLAYER_2_ACTIVE,
4011 EL_DYNABOMB_PLAYER_3_ACTIVE,
4012 EL_DYNABOMB_PLAYER_4_ACTIVE,
4013 EL_SP_DISK_RED_ACTIVE,
4018 static int ep_inactive[] =
4028 EL_QUICKSAND_FAST_EMPTY,
4051 EL_GATE_1_GRAY_ACTIVE,
4052 EL_GATE_2_GRAY_ACTIVE,
4053 EL_GATE_3_GRAY_ACTIVE,
4054 EL_GATE_4_GRAY_ACTIVE,
4063 EL_EM_GATE_1_GRAY_ACTIVE,
4064 EL_EM_GATE_2_GRAY_ACTIVE,
4065 EL_EM_GATE_3_GRAY_ACTIVE,
4066 EL_EM_GATE_4_GRAY_ACTIVE,
4075 EL_EMC_GATE_5_GRAY_ACTIVE,
4076 EL_EMC_GATE_6_GRAY_ACTIVE,
4077 EL_EMC_GATE_7_GRAY_ACTIVE,
4078 EL_EMC_GATE_8_GRAY_ACTIVE,
4080 EL_DC_GATE_WHITE_GRAY,
4081 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4082 EL_DC_GATE_FAKE_GRAY,
4085 EL_INVISIBLE_STEELWALL,
4093 EL_WALL_EMERALD_YELLOW,
4094 EL_DYNABOMB_INCREASE_NUMBER,
4095 EL_DYNABOMB_INCREASE_SIZE,
4096 EL_DYNABOMB_INCREASE_POWER,
4100 EL_SOKOBAN_FIELD_EMPTY,
4101 EL_SOKOBAN_FIELD_FULL,
4102 EL_WALL_EMERALD_RED,
4103 EL_WALL_EMERALD_PURPLE,
4104 EL_ACID_POOL_TOPLEFT,
4105 EL_ACID_POOL_TOPRIGHT,
4106 EL_ACID_POOL_BOTTOMLEFT,
4107 EL_ACID_POOL_BOTTOM,
4108 EL_ACID_POOL_BOTTOMRIGHT,
4112 EL_BD_MAGIC_WALL_DEAD,
4114 EL_DC_MAGIC_WALL_DEAD,
4115 EL_AMOEBA_TO_DIAMOND,
4123 EL_SP_GRAVITY_PORT_RIGHT,
4124 EL_SP_GRAVITY_PORT_DOWN,
4125 EL_SP_GRAVITY_PORT_LEFT,
4126 EL_SP_GRAVITY_PORT_UP,
4127 EL_SP_PORT_HORIZONTAL,
4128 EL_SP_PORT_VERTICAL,
4139 EL_SP_HARDWARE_GRAY,
4140 EL_SP_HARDWARE_GREEN,
4141 EL_SP_HARDWARE_BLUE,
4143 EL_SP_HARDWARE_YELLOW,
4144 EL_SP_HARDWARE_BASE_1,
4145 EL_SP_HARDWARE_BASE_2,
4146 EL_SP_HARDWARE_BASE_3,
4147 EL_SP_HARDWARE_BASE_4,
4148 EL_SP_HARDWARE_BASE_5,
4149 EL_SP_HARDWARE_BASE_6,
4150 EL_SP_GRAVITY_ON_PORT_LEFT,
4151 EL_SP_GRAVITY_ON_PORT_RIGHT,
4152 EL_SP_GRAVITY_ON_PORT_UP,
4153 EL_SP_GRAVITY_ON_PORT_DOWN,
4154 EL_SP_GRAVITY_OFF_PORT_LEFT,
4155 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4156 EL_SP_GRAVITY_OFF_PORT_UP,
4157 EL_SP_GRAVITY_OFF_PORT_DOWN,
4158 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4159 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4160 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4161 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4162 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4163 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4164 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4165 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4166 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4167 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4168 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4169 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4170 EL_SIGN_EXCLAMATION,
4171 EL_SIGN_RADIOACTIVITY,
4178 EL_SIGN_ENTRY_FORBIDDEN,
4179 EL_SIGN_EMERGENCY_EXIT,
4187 EL_DC_STEELWALL_1_LEFT,
4188 EL_DC_STEELWALL_1_RIGHT,
4189 EL_DC_STEELWALL_1_TOP,
4190 EL_DC_STEELWALL_1_BOTTOM,
4191 EL_DC_STEELWALL_1_HORIZONTAL,
4192 EL_DC_STEELWALL_1_VERTICAL,
4193 EL_DC_STEELWALL_1_TOPLEFT,
4194 EL_DC_STEELWALL_1_TOPRIGHT,
4195 EL_DC_STEELWALL_1_BOTTOMLEFT,
4196 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4197 EL_DC_STEELWALL_1_TOPLEFT_2,
4198 EL_DC_STEELWALL_1_TOPRIGHT_2,
4199 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4200 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4201 EL_DC_STEELWALL_2_LEFT,
4202 EL_DC_STEELWALL_2_RIGHT,
4203 EL_DC_STEELWALL_2_TOP,
4204 EL_DC_STEELWALL_2_BOTTOM,
4205 EL_DC_STEELWALL_2_HORIZONTAL,
4206 EL_DC_STEELWALL_2_VERTICAL,
4207 EL_DC_STEELWALL_2_MIDDLE,
4208 EL_DC_STEELWALL_2_SINGLE,
4209 EL_STEELWALL_SLIPPERY,
4214 EL_EMC_WALL_SLIPPERY_1,
4215 EL_EMC_WALL_SLIPPERY_2,
4216 EL_EMC_WALL_SLIPPERY_3,
4217 EL_EMC_WALL_SLIPPERY_4,
4238 static int ep_em_slippery_wall[] =
4243 static int ep_gfx_crumbled[] =
4254 static int ep_editor_cascade_active[] =
4256 EL_INTERNAL_CASCADE_BD_ACTIVE,
4257 EL_INTERNAL_CASCADE_EM_ACTIVE,
4258 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4259 EL_INTERNAL_CASCADE_RND_ACTIVE,
4260 EL_INTERNAL_CASCADE_SB_ACTIVE,
4261 EL_INTERNAL_CASCADE_SP_ACTIVE,
4262 EL_INTERNAL_CASCADE_DC_ACTIVE,
4263 EL_INTERNAL_CASCADE_DX_ACTIVE,
4264 EL_INTERNAL_CASCADE_MM_ACTIVE,
4265 EL_INTERNAL_CASCADE_DF_ACTIVE,
4266 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4267 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4268 EL_INTERNAL_CASCADE_CE_ACTIVE,
4269 EL_INTERNAL_CASCADE_GE_ACTIVE,
4270 EL_INTERNAL_CASCADE_REF_ACTIVE,
4271 EL_INTERNAL_CASCADE_USER_ACTIVE,
4272 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4277 static int ep_editor_cascade_inactive[] =
4279 EL_INTERNAL_CASCADE_BD,
4280 EL_INTERNAL_CASCADE_EM,
4281 EL_INTERNAL_CASCADE_EMC,
4282 EL_INTERNAL_CASCADE_RND,
4283 EL_INTERNAL_CASCADE_SB,
4284 EL_INTERNAL_CASCADE_SP,
4285 EL_INTERNAL_CASCADE_DC,
4286 EL_INTERNAL_CASCADE_DX,
4287 EL_INTERNAL_CASCADE_MM,
4288 EL_INTERNAL_CASCADE_DF,
4289 EL_INTERNAL_CASCADE_CHARS,
4290 EL_INTERNAL_CASCADE_STEEL_CHARS,
4291 EL_INTERNAL_CASCADE_CE,
4292 EL_INTERNAL_CASCADE_GE,
4293 EL_INTERNAL_CASCADE_REF,
4294 EL_INTERNAL_CASCADE_USER,
4295 EL_INTERNAL_CASCADE_DYNAMIC,
4300 static int ep_obsolete[] =
4304 EL_EM_KEY_1_FILE_OBSOLETE,
4305 EL_EM_KEY_2_FILE_OBSOLETE,
4306 EL_EM_KEY_3_FILE_OBSOLETE,
4307 EL_EM_KEY_4_FILE_OBSOLETE,
4308 EL_ENVELOPE_OBSOLETE,
4317 } element_properties[] =
4319 { ep_diggable, EP_DIGGABLE },
4320 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4321 { ep_dont_run_into, EP_DONT_RUN_INTO },
4322 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4323 { ep_dont_touch, EP_DONT_TOUCH },
4324 { ep_indestructible, EP_INDESTRUCTIBLE },
4325 { ep_slippery, EP_SLIPPERY },
4326 { ep_can_change, EP_CAN_CHANGE },
4327 { ep_can_move, EP_CAN_MOVE },
4328 { ep_can_fall, EP_CAN_FALL },
4329 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4330 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4331 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4332 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4333 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4334 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4335 { ep_walkable_over, EP_WALKABLE_OVER },
4336 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4337 { ep_walkable_under, EP_WALKABLE_UNDER },
4338 { ep_passable_over, EP_PASSABLE_OVER },
4339 { ep_passable_inside, EP_PASSABLE_INSIDE },
4340 { ep_passable_under, EP_PASSABLE_UNDER },
4341 { ep_droppable, EP_DROPPABLE },
4342 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4343 { ep_pushable, EP_PUSHABLE },
4344 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4345 { ep_protected, EP_PROTECTED },
4346 { ep_throwable, EP_THROWABLE },
4347 { ep_can_explode, EP_CAN_EXPLODE },
4348 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4350 { ep_player, EP_PLAYER },
4351 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4352 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4353 { ep_switchable, EP_SWITCHABLE },
4354 { ep_bd_element, EP_BD_ELEMENT },
4355 { ep_sp_element, EP_SP_ELEMENT },
4356 { ep_sb_element, EP_SB_ELEMENT },
4358 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4359 { ep_food_penguin, EP_FOOD_PENGUIN },
4360 { ep_food_pig, EP_FOOD_PIG },
4361 { ep_historic_wall, EP_HISTORIC_WALL },
4362 { ep_historic_solid, EP_HISTORIC_SOLID },
4363 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4364 { ep_belt, EP_BELT },
4365 { ep_belt_active, EP_BELT_ACTIVE },
4366 { ep_belt_switch, EP_BELT_SWITCH },
4367 { ep_tube, EP_TUBE },
4368 { ep_acid_pool, EP_ACID_POOL },
4369 { ep_keygate, EP_KEYGATE },
4370 { ep_amoeboid, EP_AMOEBOID },
4371 { ep_amoebalive, EP_AMOEBALIVE },
4372 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4373 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4374 { ep_can_grow, EP_CAN_GROW },
4375 { ep_active_bomb, EP_ACTIVE_BOMB },
4376 { ep_inactive, EP_INACTIVE },
4378 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4380 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4382 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4383 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4385 { ep_obsolete, EP_OBSOLETE },
4392 /* always start with reliable default values (element has no properties) */
4393 /* (but never initialize clipboard elements after the very first time) */
4394 /* (to be able to use clipboard elements between several levels) */
4395 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4396 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4397 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4398 SET_PROPERTY(i, j, FALSE);
4400 /* set all base element properties from above array definitions */
4401 for (i = 0; element_properties[i].elements != NULL; i++)
4402 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4403 SET_PROPERTY((element_properties[i].elements)[j],
4404 element_properties[i].property, TRUE);
4406 /* copy properties to some elements that are only stored in level file */
4407 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4408 for (j = 0; copy_properties[j][0] != -1; j++)
4409 if (HAS_PROPERTY(copy_properties[j][0], i))
4410 for (k = 1; k <= 4; k++)
4411 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4413 /* set static element properties that are not listed in array definitions */
4414 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4415 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4417 clipboard_elements_initialized = TRUE;
4420 void InitElementPropertiesEngine(int engine_version)
4422 static int no_wall_properties[] =
4425 EP_COLLECTIBLE_ONLY,
4427 EP_DONT_COLLIDE_WITH,
4430 EP_CAN_SMASH_PLAYER,
4431 EP_CAN_SMASH_ENEMIES,
4432 EP_CAN_SMASH_EVERYTHING,
4437 EP_FOOD_DARK_YAMYAM,
4453 /* important: after initialization in InitElementPropertiesStatic(), the
4454 elements are not again initialized to a default value; therefore all
4455 changes have to make sure that they leave the element with a defined
4456 property (which means that conditional property changes must be set to
4457 a reliable default value before) */
4459 /* resolve group elements */
4460 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4461 ResolveGroupElement(EL_GROUP_START + i);
4463 /* set all special, combined or engine dependent element properties */
4464 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4466 /* do not change (already initialized) clipboard elements here */
4467 if (IS_CLIPBOARD_ELEMENT(i))
4470 /* ---------- INACTIVE ------------------------------------------------- */
4471 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4472 i <= EL_CHAR_END) ||
4473 (i >= EL_STEEL_CHAR_START &&
4474 i <= EL_STEEL_CHAR_END)));
4476 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4477 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4478 IS_WALKABLE_INSIDE(i) ||
4479 IS_WALKABLE_UNDER(i)));
4481 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4482 IS_PASSABLE_INSIDE(i) ||
4483 IS_PASSABLE_UNDER(i)));
4485 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4486 IS_PASSABLE_OVER(i)));
4488 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4489 IS_PASSABLE_INSIDE(i)));
4491 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4492 IS_PASSABLE_UNDER(i)));
4494 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4497 /* ---------- COLLECTIBLE ---------------------------------------------- */
4498 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4502 /* ---------- SNAPPABLE ------------------------------------------------ */
4503 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4504 IS_COLLECTIBLE(i) ||
4508 /* ---------- WALL ----------------------------------------------------- */
4509 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4511 for (j = 0; no_wall_properties[j] != -1; j++)
4512 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4513 i >= EL_FIRST_RUNTIME_UNREAL)
4514 SET_PROPERTY(i, EP_WALL, FALSE);
4516 if (IS_HISTORIC_WALL(i))
4517 SET_PROPERTY(i, EP_WALL, TRUE);
4519 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4520 if (engine_version < VERSION_IDENT(2,2,0,0))
4521 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4523 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4525 !IS_COLLECTIBLE(i)));
4527 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4528 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4529 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4531 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4532 IS_INDESTRUCTIBLE(i)));
4534 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4536 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4537 else if (engine_version < VERSION_IDENT(2,2,0,0))
4538 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4540 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4544 if (IS_CUSTOM_ELEMENT(i))
4546 /* these are additional properties which are initially false when set */
4548 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4550 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4551 if (DONT_COLLIDE_WITH(i))
4552 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4554 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4555 if (CAN_SMASH_EVERYTHING(i))
4556 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4557 if (CAN_SMASH_ENEMIES(i))
4558 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4561 /* ---------- CAN_SMASH ------------------------------------------------ */
4562 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4563 CAN_SMASH_ENEMIES(i) ||
4564 CAN_SMASH_EVERYTHING(i)));
4566 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4567 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4568 EXPLODES_BY_FIRE(i)));
4570 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4571 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4572 EXPLODES_SMASHED(i)));
4574 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4575 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4576 EXPLODES_IMPACT(i)));
4578 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4579 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4581 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4582 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4583 i == EL_BLACK_ORB));
4585 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4586 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4588 IS_CUSTOM_ELEMENT(i)));
4590 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4591 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4592 i == EL_SP_ELECTRON));
4594 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4595 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4596 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4597 getMoveIntoAcidProperty(&level, i));
4599 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4600 if (MAYBE_DONT_COLLIDE_WITH(i))
4601 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4602 getDontCollideWithProperty(&level, i));
4604 /* ---------- SP_PORT -------------------------------------------------- */
4605 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4606 IS_PASSABLE_INSIDE(i)));
4608 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4609 for (j = 0; j < level.num_android_clone_elements; j++)
4610 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4612 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4614 /* ---------- CAN_CHANGE ----------------------------------------------- */
4615 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4616 for (j = 0; j < element_info[i].num_change_pages; j++)
4617 if (element_info[i].change_page[j].can_change)
4618 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4620 /* ---------- HAS_ACTION ----------------------------------------------- */
4621 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4622 for (j = 0; j < element_info[i].num_change_pages; j++)
4623 if (element_info[i].change_page[j].has_action)
4624 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4626 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4627 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4630 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4631 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4632 element_info[i].crumbled[ACTION_DEFAULT] !=
4633 element_info[i].graphic[ACTION_DEFAULT]);
4635 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4636 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4637 IS_EDITOR_CASCADE_INACTIVE(i)));
4640 /* dynamically adjust element properties according to game engine version */
4642 static int ep_em_slippery_wall[] =
4647 EL_EXPANDABLE_WALL_HORIZONTAL,
4648 EL_EXPANDABLE_WALL_VERTICAL,
4649 EL_EXPANDABLE_WALL_ANY,
4650 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4651 EL_EXPANDABLE_STEELWALL_VERTICAL,
4652 EL_EXPANDABLE_STEELWALL_ANY,
4653 EL_EXPANDABLE_STEELWALL_GROWING,
4657 static int ep_em_explodes_by_fire[] =
4660 EL_EM_DYNAMITE_ACTIVE,
4665 /* special EM style gems behaviour */
4666 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4667 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4668 level.em_slippery_gems);
4670 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4671 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4672 (level.em_slippery_gems &&
4673 engine_version > VERSION_IDENT(2,0,1,0)));
4675 /* special EM style explosion behaviour regarding chain reactions */
4676 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4677 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4678 level.em_explodes_by_fire);
4681 /* this is needed because some graphics depend on element properties */
4682 if (game_status == GAME_MODE_PLAYING)
4683 InitElementGraphicInfo();
4686 void InitElementPropertiesAfterLoading(int engine_version)
4690 /* set some other uninitialized values of custom elements in older levels */
4691 if (engine_version < VERSION_IDENT(3,1,0,0))
4693 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4695 int element = EL_CUSTOM_START + i;
4697 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4699 element_info[element].explosion_delay = 17;
4700 element_info[element].ignition_delay = 8;
4705 void InitElementPropertiesGfxElement()
4709 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4711 struct ElementInfo *ei = &element_info[i];
4713 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4717 static void InitGlobal()
4722 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4724 /* check if element_name_info entry defined for each element in "main.h" */
4725 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4726 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4728 element_info[i].token_name = element_name_info[i].token_name;
4729 element_info[i].class_name = element_name_info[i].class_name;
4730 element_info[i].editor_description= element_name_info[i].editor_description;
4733 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4735 /* check if global_anim_name_info defined for each entry in "main.h" */
4736 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4737 global_anim_name_info[i].token_name == NULL)
4738 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4740 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4743 /* create hash from image config list */
4744 image_config_hash = newSetupFileHash();
4745 for (i = 0; image_config[i].token != NULL; i++)
4746 setHashEntry(image_config_hash,
4747 image_config[i].token,
4748 image_config[i].value);
4750 /* create hash from element token list */
4751 element_token_hash = newSetupFileHash();
4752 for (i = 0; element_name_info[i].token_name != NULL; i++)
4753 setHashEntry(element_token_hash,
4754 element_name_info[i].token_name,
4757 /* create hash from graphic token list */
4758 graphic_token_hash = newSetupFileHash();
4759 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4760 if (strSuffix(image_config[i].value, ".png") ||
4761 strSuffix(image_config[i].value, ".pcx") ||
4762 strSuffix(image_config[i].value, ".wav") ||
4763 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4764 setHashEntry(graphic_token_hash,
4765 image_config[i].token,
4766 int2str(graphic++, 0));
4768 /* create hash from font token list */
4769 font_token_hash = newSetupFileHash();
4770 for (i = 0; font_info[i].token_name != NULL; i++)
4771 setHashEntry(font_token_hash,
4772 font_info[i].token_name,
4775 /* set default filenames for all cloned graphics in static configuration */
4776 for (i = 0; image_config[i].token != NULL; i++)
4778 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4780 char *token = image_config[i].token;
4781 char *token_clone_from = getStringCat2(token, ".clone_from");
4782 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4784 if (token_cloned != NULL)
4786 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4788 if (value_cloned != NULL)
4790 /* set default filename in static configuration */
4791 image_config[i].value = value_cloned;
4793 /* set default filename in image config hash */
4794 setHashEntry(image_config_hash, token, value_cloned);
4798 free(token_clone_from);
4802 /* always start with reliable default values (all elements) */
4803 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4804 ActiveElement[i] = i;
4806 /* now add all entries that have an active state (active elements) */
4807 for (i = 0; element_with_active_state[i].element != -1; i++)
4809 int element = element_with_active_state[i].element;
4810 int element_active = element_with_active_state[i].element_active;
4812 ActiveElement[element] = element_active;
4815 /* always start with reliable default values (all buttons) */
4816 for (i = 0; i < NUM_IMAGE_FILES; i++)
4817 ActiveButton[i] = i;
4819 /* now add all entries that have an active state (active buttons) */
4820 for (i = 0; button_with_active_state[i].button != -1; i++)
4822 int button = button_with_active_state[i].button;
4823 int button_active = button_with_active_state[i].button_active;
4825 ActiveButton[button] = button_active;
4828 /* always start with reliable default values (all fonts) */
4829 for (i = 0; i < NUM_FONTS; i++)
4832 /* now add all entries that have an active state (active fonts) */
4833 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4835 int font = font_with_active_state[i].font_nr;
4836 int font_active = font_with_active_state[i].font_nr_active;
4838 ActiveFont[font] = font_active;
4841 global.autoplay_leveldir = NULL;
4842 global.convert_leveldir = NULL;
4843 global.create_images_dir = NULL;
4845 global.frames_per_second = 0;
4846 global.show_frames_per_second = FALSE;
4848 global.border_status = GAME_MODE_LOADING;
4849 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4851 global.use_envelope_request = FALSE;
4854 void Execute_Command(char *command)
4858 if (strEqual(command, "print graphicsinfo.conf"))
4860 Print("# You can configure additional/alternative image files here.\n");
4861 Print("# (The entries below are default and therefore commented out.)\n");
4863 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4865 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4868 for (i = 0; image_config[i].token != NULL; i++)
4869 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4870 image_config[i].value));
4874 else if (strEqual(command, "print soundsinfo.conf"))
4876 Print("# You can configure additional/alternative sound files here.\n");
4877 Print("# (The entries below are default and therefore commented out.)\n");
4879 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4881 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4884 for (i = 0; sound_config[i].token != NULL; i++)
4885 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4886 sound_config[i].value));
4890 else if (strEqual(command, "print musicinfo.conf"))
4892 Print("# You can configure additional/alternative music files here.\n");
4893 Print("# (The entries below are default and therefore commented out.)\n");
4895 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4897 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4900 for (i = 0; music_config[i].token != NULL; i++)
4901 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4902 music_config[i].value));
4906 else if (strEqual(command, "print editorsetup.conf"))
4908 Print("# You can configure your personal editor element list here.\n");
4909 Print("# (The entries below are default and therefore commented out.)\n");
4912 /* this is needed to be able to check element list for cascade elements */
4913 InitElementPropertiesStatic();
4914 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4916 PrintEditorElementList();
4920 else if (strEqual(command, "print helpanim.conf"))
4922 Print("# You can configure different element help animations here.\n");
4923 Print("# (The entries below are default and therefore commented out.)\n");
4926 for (i = 0; helpanim_config[i].token != NULL; i++)
4928 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4929 helpanim_config[i].value));
4931 if (strEqual(helpanim_config[i].token, "end"))
4937 else if (strEqual(command, "print helptext.conf"))
4939 Print("# You can configure different element help text here.\n");
4940 Print("# (The entries below are default and therefore commented out.)\n");
4943 for (i = 0; helptext_config[i].token != NULL; i++)
4944 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4945 helptext_config[i].value));
4949 else if (strPrefix(command, "dump level "))
4951 char *filename = &command[11];
4953 if (!fileExists(filename))
4954 Error(ERR_EXIT, "cannot open file '%s'", filename);
4956 LoadLevelFromFilename(&level, filename);
4961 else if (strPrefix(command, "dump tape "))
4963 char *filename = &command[10];
4965 if (!fileExists(filename))
4966 Error(ERR_EXIT, "cannot open file '%s'", filename);
4968 LoadTapeFromFilename(filename);
4973 else if (strPrefix(command, "autotest ") ||
4974 strPrefix(command, "autoplay ") ||
4975 strPrefix(command, "autoffwd ") ||
4976 strPrefix(command, "autowarp "))
4978 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4980 global.autoplay_mode =
4981 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
4982 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
4983 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
4984 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
4985 AUTOPLAY_MODE_NONE);
4987 while (*str_ptr != '\0') /* continue parsing string */
4989 /* cut leading whitespace from string, replace it by string terminator */
4990 while (*str_ptr == ' ' || *str_ptr == '\t')
4993 if (*str_ptr == '\0') /* end of string reached */
4996 if (global.autoplay_leveldir == NULL) /* read level set string */
4998 global.autoplay_leveldir = str_ptr;
4999 global.autoplay_all = TRUE; /* default: play all tapes */
5001 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5002 global.autoplay_level[i] = FALSE;
5004 else /* read level number string */
5006 int level_nr = atoi(str_ptr); /* get level_nr value */
5008 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5009 global.autoplay_level[level_nr] = TRUE;
5011 global.autoplay_all = FALSE;
5014 /* advance string pointer to the next whitespace (or end of string) */
5015 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5019 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5020 program.headless = TRUE;
5022 else if (strPrefix(command, "convert "))
5024 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5025 char *str_ptr = strchr(str_copy, ' ');
5027 global.convert_leveldir = str_copy;
5028 global.convert_level_nr = -1;
5030 if (str_ptr != NULL) /* level number follows */
5032 *str_ptr++ = '\0'; /* terminate leveldir string */
5033 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5036 program.headless = TRUE;
5038 else if (strPrefix(command, "create images "))
5040 global.create_images_dir = getStringCopy(&command[14]);
5042 if (access(global.create_images_dir, W_OK) != 0)
5043 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5044 global.create_images_dir);
5046 else if (strPrefix(command, "create CE image "))
5048 CreateCustomElementImages(&command[16]);
5054 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5058 static void InitSetup()
5060 LoadSetup(); /* global setup info */
5062 /* set some options from setup file */
5064 if (setup.options.verbose)
5065 options.verbose = TRUE;
5067 if (setup.debug.show_frames_per_second)
5068 global.show_frames_per_second = TRUE;
5071 static void InitGameInfo()
5073 game.restart_level = FALSE;
5076 static void InitPlayerInfo()
5080 /* choose default local player */
5081 local_player = &stored_player[0];
5083 for (i = 0; i < MAX_PLAYERS; i++)
5084 stored_player[i].connected = FALSE;
5086 local_player->connected = TRUE;
5089 static void InitArtworkInfo()
5094 static char *get_string_in_brackets(char *string)
5096 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5098 sprintf(string_in_brackets, "[%s]", string);
5100 return string_in_brackets;
5103 static char *get_level_id_suffix(int id_nr)
5105 char *id_suffix = checked_malloc(1 + 3 + 1);
5107 if (id_nr < 0 || id_nr > 999)
5110 sprintf(id_suffix, ".%03d", id_nr);
5115 static void InitArtworkConfig()
5117 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5119 NUM_GLOBAL_ANIM_TOKENS + 1];
5120 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5121 NUM_GLOBAL_ANIM_TOKENS + 1];
5122 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5123 NUM_GLOBAL_ANIM_TOKENS + 1];
5124 static char *action_id_suffix[NUM_ACTIONS + 1];
5125 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5126 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5127 static char *level_id_suffix[MAX_LEVELS + 1];
5128 static char *dummy[1] = { NULL };
5129 static char *ignore_generic_tokens[] =
5135 static char **ignore_image_tokens;
5136 static char **ignore_sound_tokens;
5137 static char **ignore_music_tokens;
5138 int num_ignore_generic_tokens;
5139 int num_ignore_image_tokens;
5140 int num_ignore_sound_tokens;
5141 int num_ignore_music_tokens;
5144 /* dynamically determine list of generic tokens to be ignored */
5145 num_ignore_generic_tokens = 0;
5146 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5147 num_ignore_generic_tokens++;
5149 /* dynamically determine list of image tokens to be ignored */
5150 num_ignore_image_tokens = num_ignore_generic_tokens;
5151 for (i = 0; image_config_vars[i].token != NULL; i++)
5152 num_ignore_image_tokens++;
5153 ignore_image_tokens =
5154 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5155 for (i = 0; i < num_ignore_generic_tokens; i++)
5156 ignore_image_tokens[i] = ignore_generic_tokens[i];
5157 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5158 ignore_image_tokens[num_ignore_generic_tokens + i] =
5159 image_config_vars[i].token;
5160 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5162 /* dynamically determine list of sound tokens to be ignored */
5163 num_ignore_sound_tokens = num_ignore_generic_tokens;
5164 ignore_sound_tokens =
5165 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5166 for (i = 0; i < num_ignore_generic_tokens; i++)
5167 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5168 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5170 /* dynamically determine list of music tokens to be ignored */
5171 num_ignore_music_tokens = num_ignore_generic_tokens;
5172 ignore_music_tokens =
5173 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5174 for (i = 0; i < num_ignore_generic_tokens; i++)
5175 ignore_music_tokens[i] = ignore_generic_tokens[i];
5176 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5178 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5179 image_id_prefix[i] = element_info[i].token_name;
5180 for (i = 0; i < NUM_FONTS; i++)
5181 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5182 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5183 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5184 global_anim_info[i].token_name;
5185 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5187 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5188 sound_id_prefix[i] = element_info[i].token_name;
5189 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5190 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5191 get_string_in_brackets(element_info[i].class_name);
5192 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5193 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5194 global_anim_info[i].token_name;
5195 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5197 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5198 music_id_prefix[i] = music_prefix_info[i].prefix;
5199 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5200 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5201 global_anim_info[i].token_name;
5202 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5204 for (i = 0; i < NUM_ACTIONS; i++)
5205 action_id_suffix[i] = element_action_info[i].suffix;
5206 action_id_suffix[NUM_ACTIONS] = NULL;
5208 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5209 direction_id_suffix[i] = element_direction_info[i].suffix;
5210 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5212 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5213 special_id_suffix[i] = special_suffix_info[i].suffix;
5214 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5216 for (i = 0; i < MAX_LEVELS; i++)
5217 level_id_suffix[i] = get_level_id_suffix(i);
5218 level_id_suffix[MAX_LEVELS] = NULL;
5220 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5221 image_id_prefix, action_id_suffix, direction_id_suffix,
5222 special_id_suffix, ignore_image_tokens);
5223 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5224 sound_id_prefix, action_id_suffix, dummy,
5225 special_id_suffix, ignore_sound_tokens);
5226 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5227 music_id_prefix, action_id_suffix, special_id_suffix,
5228 level_id_suffix, ignore_music_tokens);
5231 static void InitMixer()
5238 void InitGfxBuffers()
5240 static int win_xsize_last = -1;
5241 static int win_ysize_last = -1;
5243 /* create additional image buffers for double-buffering and cross-fading */
5245 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5247 /* used to temporarily store the backbuffer -- only re-create if changed */
5248 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5249 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5251 win_xsize_last = WIN_XSIZE;
5252 win_ysize_last = WIN_YSIZE;
5255 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5256 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5257 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5258 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5260 /* initialize screen properties */
5261 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5262 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5264 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5265 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5266 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5267 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5268 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5269 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5271 /* required if door size definitions have changed */
5272 InitGraphicCompatibilityInfo_Doors();
5274 InitGfxBuffers_EM();
5275 InitGfxBuffers_SP();
5280 struct GraphicInfo *graphic_info_last = graphic_info;
5281 char *filename_font_initial = NULL;
5282 char *filename_anim_initial = NULL;
5283 Bitmap *bitmap_font_initial = NULL;
5287 /* determine settings for initial font (for displaying startup messages) */
5288 for (i = 0; image_config[i].token != NULL; i++)
5290 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5292 char font_token[128];
5295 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5296 len_font_token = strlen(font_token);
5298 if (strEqual(image_config[i].token, font_token))
5299 filename_font_initial = image_config[i].value;
5300 else if (strlen(image_config[i].token) > len_font_token &&
5301 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5303 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5304 font_initial[j].src_x = atoi(image_config[i].value);
5305 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5306 font_initial[j].src_y = atoi(image_config[i].value);
5307 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5308 font_initial[j].width = atoi(image_config[i].value);
5309 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5310 font_initial[j].height = atoi(image_config[i].value);
5315 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5317 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5318 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5321 if (filename_font_initial == NULL) /* should not happen */
5322 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5325 InitGfxCustomArtworkInfo();
5326 InitGfxOtherSettings();
5328 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5330 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5331 font_initial[j].bitmap = bitmap_font_initial;
5333 InitFontGraphicInfo();
5335 font_height = getFontHeight(FC_RED);
5337 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5338 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5339 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5342 DrawInitText("Loading graphics", 120, FC_GREEN);
5344 /* initialize settings for busy animation with default values */
5345 int parameter[NUM_GFX_ARGS];
5346 for (i = 0; i < NUM_GFX_ARGS; i++)
5347 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5348 image_config_suffix[i].token,
5349 image_config_suffix[i].type);
5351 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5352 int len_anim_token = strlen(anim_token);
5354 /* read settings for busy animation from default custom artwork config */
5355 char *gfx_config_filename = getPath3(options.graphics_directory,
5357 GRAPHICSINFO_FILENAME);
5359 if (fileExists(gfx_config_filename))
5361 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5363 if (setup_file_hash)
5365 char *filename = getHashEntry(setup_file_hash, anim_token);
5369 filename_anim_initial = getStringCopy(filename);
5371 for (j = 0; image_config_suffix[j].token != NULL; j++)
5373 int type = image_config_suffix[j].type;
5374 char *suffix = image_config_suffix[j].token;
5375 char *token = getStringCat2(anim_token, suffix);
5376 char *value = getHashEntry(setup_file_hash, token);
5378 checked_free(token);
5381 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5385 freeSetupFileHash(setup_file_hash);
5389 if (filename_anim_initial == NULL)
5391 /* read settings for busy animation from static default artwork config */
5392 for (i = 0; image_config[i].token != NULL; i++)
5394 if (strEqual(image_config[i].token, anim_token))
5395 filename_anim_initial = getStringCopy(image_config[i].value);
5396 else if (strlen(image_config[i].token) > len_anim_token &&
5397 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5399 for (j = 0; image_config_suffix[j].token != NULL; j++)
5401 if (strEqual(&image_config[i].token[len_anim_token],
5402 image_config_suffix[j].token))
5404 get_graphic_parameter_value(image_config[i].value,
5405 image_config_suffix[j].token,
5406 image_config_suffix[j].type);
5412 if (filename_anim_initial == NULL) /* should not happen */
5413 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5415 anim_initial.bitmaps =
5416 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5418 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5419 LoadCustomImage(filename_anim_initial);
5421 checked_free(filename_anim_initial);
5423 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5425 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5427 graphic_info = graphic_info_last;
5429 init.busy.width = anim_initial.width;
5430 init.busy.height = anim_initial.height;
5432 InitMenuDesignSettings_Static();
5434 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5435 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5436 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5438 gfx.fade_border_source_status = global.border_status;
5439 gfx.fade_border_target_status = global.border_status;
5440 gfx.masked_border_bitmap_ptr = backbuffer;
5442 /* use copy of busy animation to prevent change while reloading artwork */
5446 void InitGfxBackground()
5448 fieldbuffer = bitmap_db_field;
5449 SetDrawtoField(DRAW_TO_BACKBUFFER);
5451 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5453 redraw_mask = REDRAW_ALL;
5456 static void InitLevelInfo()
5458 LoadLevelInfo(); /* global level info */
5459 LoadLevelSetup_LastSeries(); /* last played series info */
5460 LoadLevelSetup_SeriesInfo(); /* last played level info */
5462 if (global.autoplay_leveldir &&
5463 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5465 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5466 global.autoplay_leveldir);
5467 if (leveldir_current == NULL)
5468 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5472 static void InitLevelArtworkInfo()
5474 LoadLevelArtworkInfo();
5477 static void InitImages()
5479 print_timestamp_init("InitImages");
5482 printf("::: leveldir_current->identifier == '%s'\n",
5483 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5484 printf("::: leveldir_current->graphics_path == '%s'\n",
5485 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5486 printf("::: leveldir_current->graphics_set == '%s'\n",
5487 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5488 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5489 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5492 setLevelArtworkDir(artwork.gfx_first);
5495 printf("::: leveldir_current->identifier == '%s'\n",
5496 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5497 printf("::: leveldir_current->graphics_path == '%s'\n",
5498 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5499 printf("::: leveldir_current->graphics_set == '%s'\n",
5500 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5501 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5502 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5506 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5507 leveldir_current->identifier,
5508 artwork.gfx_current_identifier,
5509 artwork.gfx_current->identifier,
5510 leveldir_current->graphics_set,
5511 leveldir_current->graphics_path);
5514 UPDATE_BUSY_STATE();
5516 ReloadCustomImages();
5517 print_timestamp_time("ReloadCustomImages");
5519 UPDATE_BUSY_STATE();
5521 LoadCustomElementDescriptions();
5522 print_timestamp_time("LoadCustomElementDescriptions");
5524 UPDATE_BUSY_STATE();
5526 LoadMenuDesignSettings();
5527 print_timestamp_time("LoadMenuDesignSettings");
5529 UPDATE_BUSY_STATE();
5531 ReinitializeGraphics();
5532 print_timestamp_time("ReinitializeGraphics");
5534 LoadMenuDesignSettings_AfterGraphics();
5535 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5537 UPDATE_BUSY_STATE();
5539 print_timestamp_done("InitImages");
5542 static void InitSound(char *identifier)
5544 print_timestamp_init("InitSound");
5546 if (identifier == NULL)
5547 identifier = artwork.snd_current->identifier;
5549 /* set artwork path to send it to the sound server process */
5550 setLevelArtworkDir(artwork.snd_first);
5552 InitReloadCustomSounds(identifier);
5553 print_timestamp_time("InitReloadCustomSounds");
5555 ReinitializeSounds();
5556 print_timestamp_time("ReinitializeSounds");
5558 print_timestamp_done("InitSound");
5561 static void InitMusic(char *identifier)
5563 print_timestamp_init("InitMusic");
5565 if (identifier == NULL)
5566 identifier = artwork.mus_current->identifier;
5568 /* set artwork path to send it to the sound server process */
5569 setLevelArtworkDir(artwork.mus_first);
5571 InitReloadCustomMusic(identifier);
5572 print_timestamp_time("InitReloadCustomMusic");
5574 ReinitializeMusic();
5575 print_timestamp_time("ReinitializeMusic");
5577 print_timestamp_done("InitMusic");
5580 static void InitArtworkDone()
5582 if (program.headless)
5585 InitGlobalAnimations();
5588 void InitNetworkServer()
5590 #if defined(NETWORK_AVALIABLE)
5594 if (!options.network)
5597 #if defined(NETWORK_AVALIABLE)
5598 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5600 if (!ConnectToServer(options.server_host, options.server_port))
5601 Error(ERR_EXIT, "cannot connect to network game server");
5603 SendToServer_PlayerName(setup.player_name);
5604 SendToServer_ProtocolVersion();
5607 SendToServer_NrWanted(nr_wanted);
5611 static boolean CheckArtworkConfigForCustomElements(char *filename)
5613 SetupFileHash *setup_file_hash;
5614 boolean redefined_ce_found = FALSE;
5616 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5618 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5620 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5622 char *token = HASH_ITERATION_TOKEN(itr);
5624 if (strPrefix(token, "custom_"))
5626 redefined_ce_found = TRUE;
5631 END_HASH_ITERATION(setup_file_hash, itr)
5633 freeSetupFileHash(setup_file_hash);
5636 return redefined_ce_found;
5639 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5641 char *filename_base, *filename_local;
5642 boolean redefined_ce_found = FALSE;
5644 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5647 printf("::: leveldir_current->identifier == '%s'\n",
5648 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5649 printf("::: leveldir_current->graphics_path == '%s'\n",
5650 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5651 printf("::: leveldir_current->graphics_set == '%s'\n",
5652 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5653 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5654 leveldir_current == NULL ? "[NULL]" :
5655 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5658 /* first look for special artwork configured in level series config */
5659 filename_base = getCustomArtworkLevelConfigFilename(type);
5662 printf("::: filename_base == '%s'\n", filename_base);
5665 if (fileExists(filename_base))
5666 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5668 filename_local = getCustomArtworkConfigFilename(type);
5671 printf("::: filename_local == '%s'\n", filename_local);
5674 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5675 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5678 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5681 return redefined_ce_found;
5684 static void InitOverrideArtwork()
5686 boolean redefined_ce_found = FALSE;
5688 /* to check if this level set redefines any CEs, do not use overriding */
5689 gfx.override_level_graphics = FALSE;
5690 gfx.override_level_sounds = FALSE;
5691 gfx.override_level_music = FALSE;
5693 /* now check if this level set has definitions for custom elements */
5694 if (setup.override_level_graphics == AUTO ||
5695 setup.override_level_sounds == AUTO ||
5696 setup.override_level_music == AUTO)
5697 redefined_ce_found =
5698 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5699 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5700 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5703 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5706 if (redefined_ce_found)
5708 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5709 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5710 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5711 gfx.override_level_music = (setup.override_level_music == TRUE);
5715 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5716 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5717 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5718 gfx.override_level_music = (setup.override_level_music != FALSE);
5722 printf("::: => %d, %d, %d\n",
5723 gfx.override_level_graphics,
5724 gfx.override_level_sounds,
5725 gfx.override_level_music);
5729 static char *getNewArtworkIdentifier(int type)
5731 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5732 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5733 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5734 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5735 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5736 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5737 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5738 char *leveldir_identifier = leveldir_current->identifier;
5739 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5740 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5741 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5742 char *artwork_current_identifier;
5743 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5745 /* leveldir_current may be invalid (level group, parent link) */
5746 if (!validLevelSeries(leveldir_current))
5749 /* 1st step: determine artwork set to be activated in descending order:
5750 --------------------------------------------------------------------
5751 1. setup artwork (when configured to override everything else)
5752 2. artwork set configured in "levelinfo.conf" of current level set
5753 (artwork in level directory will have priority when loading later)
5754 3. artwork in level directory (stored in artwork sub-directory)
5755 4. setup artwork (currently configured in setup menu) */
5757 if (setup_override_artwork)
5758 artwork_current_identifier = setup_artwork_set;
5759 else if (leveldir_artwork_set != NULL)
5760 artwork_current_identifier = leveldir_artwork_set;
5761 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5762 artwork_current_identifier = leveldir_identifier;
5764 artwork_current_identifier = setup_artwork_set;
5767 /* 2nd step: check if it is really needed to reload artwork set
5768 ------------------------------------------------------------ */
5770 /* ---------- reload if level set and also artwork set has changed ------- */
5771 if (leveldir_current_identifier[type] != leveldir_identifier &&
5772 (last_has_level_artwork_set[type] || has_level_artwork_set))
5773 artwork_new_identifier = artwork_current_identifier;
5775 leveldir_current_identifier[type] = leveldir_identifier;
5776 last_has_level_artwork_set[type] = has_level_artwork_set;
5778 /* ---------- reload if "override artwork" setting has changed ----------- */
5779 if (last_override_level_artwork[type] != setup_override_artwork)
5780 artwork_new_identifier = artwork_current_identifier;
5782 last_override_level_artwork[type] = setup_override_artwork;
5784 /* ---------- reload if current artwork identifier has changed ----------- */
5785 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5786 artwork_current_identifier))
5787 artwork_new_identifier = artwork_current_identifier;
5789 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5791 /* ---------- do not reload directly after starting ---------------------- */
5792 if (!initialized[type])
5793 artwork_new_identifier = NULL;
5795 initialized[type] = TRUE;
5797 return artwork_new_identifier;
5800 void ReloadCustomArtwork(int force_reload)
5802 int last_game_status = game_status; /* save current game status */
5803 char *gfx_new_identifier;
5804 char *snd_new_identifier;
5805 char *mus_new_identifier;
5806 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5807 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5808 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5809 boolean reload_needed;
5811 InitOverrideArtwork();
5813 force_reload_gfx |= AdjustGraphicsForEMC();
5815 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5816 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5817 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5819 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5820 snd_new_identifier != NULL || force_reload_snd ||
5821 mus_new_identifier != NULL || force_reload_mus);
5826 print_timestamp_init("ReloadCustomArtwork");
5828 SetGameStatus(GAME_MODE_LOADING);
5830 FadeOut(REDRAW_ALL);
5832 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5833 print_timestamp_time("ClearRectangle");
5837 if (gfx_new_identifier != NULL || force_reload_gfx)
5840 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5841 artwork.gfx_current_identifier,
5843 artwork.gfx_current->identifier,
5844 leveldir_current->graphics_set);
5848 print_timestamp_time("InitImages");
5851 if (snd_new_identifier != NULL || force_reload_snd)
5853 InitSound(snd_new_identifier);
5854 print_timestamp_time("InitSound");
5857 if (mus_new_identifier != NULL || force_reload_mus)
5859 InitMusic(mus_new_identifier);
5860 print_timestamp_time("InitMusic");
5865 SetGameStatus(last_game_status); /* restore current game status */
5867 init_last = init; /* switch to new busy animation */
5869 FadeOut(REDRAW_ALL);
5871 RedrawGlobalBorder();
5873 /* force redraw of (open or closed) door graphics */
5874 SetDoorState(DOOR_OPEN_ALL);
5875 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5877 FadeSetEnterScreen();
5878 FadeSkipNextFadeOut();
5880 print_timestamp_done("ReloadCustomArtwork");
5882 LimitScreenUpdates(FALSE);
5885 void KeyboardAutoRepeatOffUnlessAutoplay()
5887 if (global.autoplay_leveldir == NULL)
5888 KeyboardAutoRepeatOff();
5891 void DisplayExitMessage(char *format, va_list ap)
5893 // check if draw buffer and fonts for exit message are already available
5894 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5897 int font_1 = FC_RED;
5898 int font_2 = FC_YELLOW;
5899 int font_3 = FC_BLUE;
5900 int font_width = getFontWidth(font_2);
5901 int font_height = getFontHeight(font_2);
5904 int sxsize = WIN_XSIZE - 2 * sx;
5905 int sysize = WIN_YSIZE - 2 * sy;
5906 int line_length = sxsize / font_width;
5907 int max_lines = sysize / font_height;
5908 int num_lines_printed;
5912 gfx.sxsize = sxsize;
5913 gfx.sysize = sysize;
5917 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5919 DrawTextSCentered(sy, font_1, "Fatal error:");
5920 sy += 3 * font_height;;
5923 DrawTextBufferVA(sx, sy, format, ap, font_2,
5924 line_length, line_length, max_lines,
5925 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5926 sy += (num_lines_printed + 3) * font_height;
5928 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5929 sy += 3 * font_height;
5932 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5933 line_length, line_length, max_lines,
5934 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5936 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5938 redraw_mask = REDRAW_ALL;
5940 /* force drawing exit message even if screen updates are currently limited */
5941 LimitScreenUpdates(FALSE);
5945 /* deactivate toons on error message screen */
5946 setup.toons = FALSE;
5948 WaitForEventToContinue();
5952 /* ========================================================================= */
5954 /* ========================================================================= */
5958 print_timestamp_init("OpenAll");
5960 SetGameStatus(GAME_MODE_LOADING);
5964 InitGlobal(); /* initialize some global variables */
5966 print_timestamp_time("[init global stuff]");
5970 print_timestamp_time("[init setup/config stuff (1)]");
5974 if (options.execute_command)
5975 Execute_Command(options.execute_command);
5977 if (options.serveronly)
5979 #if defined(PLATFORM_UNIX)
5980 NetworkServer(options.server_port, options.serveronly);
5982 Error(ERR_WARN, "networking only supported in Unix version");
5985 exit(0); /* never reached, server loops forever */
5989 print_timestamp_time("[init setup/config stuff (2)]");
5991 print_timestamp_time("[init setup/config stuff (3)]");
5992 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5993 print_timestamp_time("[init setup/config stuff (4)]");
5994 InitArtworkConfig(); /* needed before forking sound child process */
5995 print_timestamp_time("[init setup/config stuff (5)]");
5997 print_timestamp_time("[init setup/config stuff (6)]");
5999 InitRND(NEW_RANDOMIZE);
6000 InitSimpleRandom(NEW_RANDOMIZE);
6004 print_timestamp_time("[init setup/config stuff]");
6007 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6011 print_timestamp_time("[init video stuff]");
6013 InitElementPropertiesStatic();
6014 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6015 InitElementPropertiesGfxElement();
6017 print_timestamp_time("[init element properties stuff]");
6021 print_timestamp_time("InitGfx");
6024 print_timestamp_time("InitLevelInfo");
6026 InitLevelArtworkInfo();
6027 print_timestamp_time("InitLevelArtworkInfo");
6029 InitOverrideArtwork(); /* needs to know current level directory */
6030 print_timestamp_time("InitOverrideArtwork");
6032 InitImages(); /* needs to know current level directory */
6033 print_timestamp_time("InitImages");
6035 InitSound(NULL); /* needs to know current level directory */
6036 print_timestamp_time("InitSound");
6038 InitMusic(NULL); /* needs to know current level directory */
6039 print_timestamp_time("InitMusic");
6043 InitGfxBackground();
6048 if (global.autoplay_leveldir)
6053 else if (global.convert_leveldir)
6058 else if (global.create_images_dir)
6060 CreateLevelSketchImages();
6064 SetGameStatus(GAME_MODE_MAIN);
6066 FadeSetEnterScreen();
6067 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6068 FadeSkipNextFadeOut();
6070 print_timestamp_time("[post-artwork]");
6072 print_timestamp_done("OpenAll");
6076 InitNetworkServer();
6079 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6081 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6082 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6083 #if defined(PLATFORM_ANDROID)
6084 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6085 SDL_AndroidGetInternalStoragePath());
6086 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6087 SDL_AndroidGetExternalStoragePath());
6088 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6089 (SDL_AndroidGetExternalStorageState() &
6090 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6091 SDL_AndroidGetExternalStorageState() &
6092 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6097 void CloseAllAndExit(int exit_value)
6102 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6109 #if defined(TARGET_SDL)
6110 #if defined(TARGET_SDL2)
6112 // set a flag to tell the network server thread to quit and wait for it
6113 // using SDL_WaitThread()
6115 if (network_server) /* terminate network server */
6116 SDL_KillThread(server_thread);
6120 CloseVideoDisplay();
6121 ClosePlatformDependentStuff();
6123 if (exit_value != 0 && !options.execute_command)
6125 /* fall back to default level set (current set may have caused an error) */
6126 SaveLevelSetup_LastSeries_Deactivate();
6128 /* tell user where to find error log file which may contain more details */
6129 // (error notification now directly displayed on screen inside R'n'D
6130 // NotifyUserAboutErrorFile(); /* currently only works for Windows */