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];
1051 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1052 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1054 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1055 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1056 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1057 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1058 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1059 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1060 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1061 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1063 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1064 /* !!! make this better !!! */
1065 if (i == EL_EMPTY_SPACE)
1067 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1068 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1071 if (default_action_graphic == -1)
1072 default_action_graphic = default_graphic;
1074 if (default_action_crumbled == -1)
1075 default_action_crumbled = default_action_graphic;
1077 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1079 /* use action graphic as the default direction graphic, if undefined */
1080 int default_action_direction_graphic = element_info[i].graphic[act];
1081 int default_action_direction_crumbled = element_info[i].crumbled[act];
1083 /* no graphic for current action -- use default direction graphic */
1084 if (default_action_direction_graphic == -1)
1085 default_action_direction_graphic =
1086 (act_remove ? default_remove_graphic :
1088 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1089 default_action_graphic != default_graphic ?
1090 default_action_graphic :
1091 default_direction_graphic[dir]);
1093 if (element_info[i].direction_graphic[act][dir] == -1)
1094 element_info[i].direction_graphic[act][dir] =
1095 default_action_direction_graphic;
1097 if (default_action_direction_crumbled == -1)
1098 default_action_direction_crumbled =
1099 element_info[i].direction_graphic[act][dir];
1101 if (element_info[i].direction_crumbled[act][dir] == -1)
1102 element_info[i].direction_crumbled[act][dir] =
1103 default_action_direction_crumbled;
1106 /* no graphic for this specific action -- use default action graphic */
1107 if (element_info[i].graphic[act] == -1)
1108 element_info[i].graphic[act] =
1109 (act_remove ? default_remove_graphic :
1110 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1111 default_action_graphic);
1113 if (element_info[i].crumbled[act] == -1)
1114 element_info[i].crumbled[act] = element_info[i].graphic[act];
1118 UPDATE_BUSY_STATE();
1121 void InitElementSpecialGraphicInfo()
1123 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1124 int num_property_mappings = getImageListPropertyMappingSize();
1127 /* always start with reliable default values */
1128 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1129 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1130 element_info[i].special_graphic[j] =
1131 element_info[i].graphic[ACTION_DEFAULT];
1133 /* initialize special element/graphic mapping from static configuration */
1134 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1136 int element = element_to_special_graphic[i].element;
1137 int special = element_to_special_graphic[i].special;
1138 int graphic = element_to_special_graphic[i].graphic;
1139 int base_graphic = el2baseimg(element);
1140 boolean base_redefined =
1141 getImageListEntryFromImageID(base_graphic)->redefined;
1142 boolean special_redefined =
1143 getImageListEntryFromImageID(graphic)->redefined;
1145 /* if the base graphic ("emerald", for example) has been redefined,
1146 but not the special graphic ("emerald.EDITOR", for example), do not
1147 use an existing (in this case considered obsolete) special graphic
1148 anymore, but use the automatically created (down-scaled) graphic */
1149 if (base_redefined && !special_redefined)
1152 element_info[element].special_graphic[special] = graphic;
1155 /* initialize special element/graphic mapping from dynamic configuration */
1156 for (i = 0; i < num_property_mappings; i++)
1158 int element = property_mapping[i].base_index;
1159 int action = property_mapping[i].ext1_index;
1160 int direction = property_mapping[i].ext2_index;
1161 int special = property_mapping[i].ext3_index;
1162 int graphic = property_mapping[i].artwork_index;
1164 /* for action ".active", replace element with active element, if exists */
1165 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1167 element = ELEMENT_ACTIVE(element);
1171 if (element >= MAX_NUM_ELEMENTS)
1174 /* do not change special graphic if action or direction was specified */
1175 if (action != -1 || direction != -1)
1178 if (IS_SPECIAL_GFX_ARG(special))
1179 element_info[element].special_graphic[special] = graphic;
1182 /* now set all undefined/invalid graphics to default */
1183 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1184 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1185 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1186 element_info[i].special_graphic[j] =
1187 element_info[i].graphic[ACTION_DEFAULT];
1190 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1192 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1193 return get_parameter_value(value_raw, suffix, type);
1195 if (strEqual(value_raw, ARG_UNDEFINED))
1196 return ARG_UNDEFINED_VALUE;
1198 if (type == TYPE_ELEMENT)
1200 char *value = getHashEntry(element_token_hash, value_raw);
1204 Error(ERR_INFO_LINE, "-");
1205 Error(ERR_INFO, "warning: error found in config file:");
1206 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1207 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1208 Error(ERR_INFO, "custom graphic rejected for this element/action");
1209 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1210 Error(ERR_INFO_LINE, "-");
1213 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1215 else if (type == TYPE_GRAPHIC)
1217 char *value = getHashEntry(graphic_token_hash, value_raw);
1218 int fallback_graphic = IMG_CHAR_EXCLAM;
1222 Error(ERR_INFO_LINE, "-");
1223 Error(ERR_INFO, "warning: error found in config file:");
1224 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1225 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1226 Error(ERR_INFO, "custom graphic rejected for this element/action");
1227 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1228 Error(ERR_INFO_LINE, "-");
1231 return (value != NULL ? atoi(value) : fallback_graphic);
1237 static int get_scaled_graphic_width(int graphic)
1239 int original_width = getOriginalImageWidthFromImageID(graphic);
1240 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1242 return original_width * scale_up_factor;
1245 static int get_scaled_graphic_height(int graphic)
1247 int original_height = getOriginalImageHeightFromImageID(graphic);
1248 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1250 return original_height * scale_up_factor;
1253 static void set_graphic_parameters_ext(int graphic, int *parameter,
1254 Bitmap **src_bitmaps)
1256 struct GraphicInfo *g = &graphic_info[graphic];
1257 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1258 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1259 int anim_frames_per_line = 1;
1261 /* always start with reliable default values */
1262 g->src_image_width = 0;
1263 g->src_image_height = 0;
1266 g->width = TILEX; /* default for element graphics */
1267 g->height = TILEY; /* default for element graphics */
1268 g->offset_x = 0; /* one or both of these values ... */
1269 g->offset_y = 0; /* ... will be corrected later */
1270 g->offset2_x = 0; /* one or both of these values ... */
1271 g->offset2_y = 0; /* ... will be corrected later */
1272 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1273 g->crumbled_like = -1; /* do not use clone element */
1274 g->diggable_like = -1; /* do not use clone element */
1275 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1276 g->scale_up_factor = 1; /* default: no scaling up */
1277 g->tile_size = TILESIZE; /* default: standard tile size */
1278 g->clone_from = -1; /* do not use clone graphic */
1279 g->init_delay_fixed = 0;
1280 g->init_delay_random = 0;
1281 g->anim_delay_fixed = 0;
1282 g->anim_delay_random = 0;
1283 g->post_delay_fixed = 0;
1284 g->post_delay_random = 0;
1285 g->init_event = ANIM_EVENT_DEFAULT;
1286 g->anim_event = ANIM_EVENT_DEFAULT;
1287 g->draw_masked = FALSE;
1289 g->fade_mode = FADE_MODE_DEFAULT;
1293 g->align = ALIGN_CENTER; /* default for title screens */
1294 g->valign = VALIGN_MIDDLE; /* default for title screens */
1295 g->sort_priority = 0; /* default for title screens */
1297 g->style = STYLE_DEFAULT;
1299 g->bitmaps = src_bitmaps;
1300 g->bitmap = src_bitmap;
1302 /* optional zoom factor for scaling up the image to a larger size */
1303 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1304 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1305 if (g->scale_up_factor < 1)
1306 g->scale_up_factor = 1; /* no scaling */
1308 /* optional tile size for using non-standard image size */
1309 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1311 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1314 // CHECK: should tile sizes less than standard tile size be allowed?
1315 if (g->tile_size < TILESIZE)
1316 g->tile_size = TILESIZE; /* standard tile size */
1319 // when setting tile size, also set width and height accordingly
1320 g->width = g->tile_size;
1321 g->height = g->tile_size;
1324 if (g->use_image_size)
1326 /* set new default bitmap size (with scaling, but without small images) */
1327 g->width = get_scaled_graphic_width(graphic);
1328 g->height = get_scaled_graphic_height(graphic);
1331 /* optional width and height of each animation frame */
1332 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1333 g->width = parameter[GFX_ARG_WIDTH];
1334 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1335 g->height = parameter[GFX_ARG_HEIGHT];
1337 /* optional x and y tile position of animation frame sequence */
1338 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1339 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1340 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1341 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1343 /* optional x and y pixel position of animation frame sequence */
1344 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1345 g->src_x = parameter[GFX_ARG_X];
1346 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1347 g->src_y = parameter[GFX_ARG_Y];
1353 Error(ERR_INFO_LINE, "-");
1354 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1355 g->width, getTokenFromImageID(graphic), TILEX);
1356 Error(ERR_INFO_LINE, "-");
1358 g->width = TILEX; /* will be checked to be inside bitmap later */
1363 Error(ERR_INFO_LINE, "-");
1364 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1365 g->height, getTokenFromImageID(graphic), TILEY);
1366 Error(ERR_INFO_LINE, "-");
1368 g->height = TILEY; /* will be checked to be inside bitmap later */
1374 /* get final bitmap size (with scaling, but without small images) */
1375 int src_image_width = get_scaled_graphic_width(graphic);
1376 int src_image_height = get_scaled_graphic_height(graphic);
1378 if (src_image_width == 0 || src_image_height == 0)
1380 /* only happens when loaded outside artwork system (like "global.busy") */
1381 src_image_width = src_bitmap->width;
1382 src_image_height = src_bitmap->height;
1385 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1387 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1388 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1392 anim_frames_per_row = MAX(1, src_image_width / g->width);
1393 anim_frames_per_col = MAX(1, src_image_height / g->height);
1396 g->src_image_width = src_image_width;
1397 g->src_image_height = src_image_height;
1400 /* correct x or y offset dependent of vertical or horizontal frame order */
1401 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1403 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1404 parameter[GFX_ARG_OFFSET] : g->height);
1405 anim_frames_per_line = anim_frames_per_col;
1407 else /* frames are ordered horizontally */
1409 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1410 parameter[GFX_ARG_OFFSET] : g->width);
1411 anim_frames_per_line = anim_frames_per_row;
1414 /* optionally, the x and y offset of frames can be specified directly */
1415 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1416 g->offset_x = parameter[GFX_ARG_XOFFSET];
1417 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1418 g->offset_y = parameter[GFX_ARG_YOFFSET];
1420 /* optionally, moving animations may have separate start and end graphics */
1421 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1423 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1424 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1426 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1427 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1428 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1429 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1430 else /* frames are ordered horizontally */
1431 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1432 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1434 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1435 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1436 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1437 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1438 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1440 /* optionally, the second movement tile can be specified as start tile */
1441 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1442 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1444 /* automatically determine correct number of frames, if not defined */
1445 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1446 g->anim_frames = parameter[GFX_ARG_FRAMES];
1447 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1448 g->anim_frames = anim_frames_per_row;
1449 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1450 g->anim_frames = anim_frames_per_col;
1454 if (g->anim_frames == 0) /* frames must be at least 1 */
1457 g->anim_frames_per_line =
1458 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1459 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1461 g->anim_delay = parameter[GFX_ARG_DELAY];
1462 if (g->anim_delay == 0) /* delay must be at least 1 */
1465 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1467 /* automatically determine correct start frame, if not defined */
1468 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1469 g->anim_start_frame = 0;
1470 else if (g->anim_mode & ANIM_REVERSE)
1471 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1473 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1475 /* animation synchronized with global frame counter, not move position */
1476 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1478 /* optional element for cloning crumble graphics */
1479 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1480 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1482 /* optional element for cloning digging graphics */
1483 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1484 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1486 /* optional border size for "crumbling" diggable graphics */
1487 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1488 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1490 /* used for global animations and player "boring" and "sleeping" actions */
1491 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1492 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1493 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1494 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1495 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1496 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1497 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1498 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1499 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1500 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1501 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1502 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1504 /* used for global animations */
1505 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1506 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1507 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1508 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1510 /* used for toon animations and global animations */
1511 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1512 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1513 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1514 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1515 g->direction = parameter[GFX_ARG_DIRECTION];
1516 g->position = parameter[GFX_ARG_POSITION];
1517 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1518 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1520 /* this is only used for drawing font characters */
1521 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1522 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1524 /* use a different default value for global animations and toons */
1525 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1526 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1527 g->draw_masked = TRUE;
1529 /* this is used for drawing envelopes, global animations and toons */
1530 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1531 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1533 /* used for toon animations and global animations */
1534 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1535 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1537 /* optional graphic for cloning all graphics settings */
1538 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1539 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1541 /* optional settings for drawing title screens and title messages */
1542 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1543 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1544 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1545 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1546 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1547 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1548 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1549 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1550 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1551 g->align = parameter[GFX_ARG_ALIGN];
1552 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1553 g->valign = parameter[GFX_ARG_VALIGN];
1554 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1555 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1557 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1558 g->class = parameter[GFX_ARG_CLASS];
1559 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1560 g->style = parameter[GFX_ARG_STYLE];
1562 /* this is only used for drawing menu buttons and text */
1563 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1564 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1565 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1566 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1569 static void set_graphic_parameters(int graphic)
1571 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1572 char **parameter_raw = image->parameter;
1573 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1574 int parameter[NUM_GFX_ARGS];
1577 /* if fallback to default artwork is done, also use the default parameters */
1578 if (image->fallback_to_default)
1579 parameter_raw = image->default_parameter;
1581 /* get integer values from string parameters */
1582 for (i = 0; i < NUM_GFX_ARGS; i++)
1583 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1584 image_config_suffix[i].token,
1585 image_config_suffix[i].type);
1587 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1589 UPDATE_BUSY_STATE();
1592 static void set_cloned_graphic_parameters(int graphic)
1594 int fallback_graphic = IMG_CHAR_EXCLAM;
1595 int max_num_images = getImageListSize();
1596 int clone_graphic = graphic_info[graphic].clone_from;
1597 int num_references_followed = 1;
1599 while (graphic_info[clone_graphic].clone_from != -1 &&
1600 num_references_followed < max_num_images)
1602 clone_graphic = graphic_info[clone_graphic].clone_from;
1604 num_references_followed++;
1607 if (num_references_followed >= max_num_images)
1609 Error(ERR_INFO_LINE, "-");
1610 Error(ERR_INFO, "warning: error found in config file:");
1611 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1612 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1613 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1614 Error(ERR_INFO, "custom graphic rejected for this element/action");
1616 if (graphic == fallback_graphic)
1617 Error(ERR_EXIT, "no fallback graphic available");
1619 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1620 Error(ERR_INFO_LINE, "-");
1622 graphic_info[graphic] = graphic_info[fallback_graphic];
1626 graphic_info[graphic] = graphic_info[clone_graphic];
1627 graphic_info[graphic].clone_from = clone_graphic;
1631 static void InitGraphicInfo()
1633 int fallback_graphic = IMG_CHAR_EXCLAM;
1634 int num_images = getImageListSize();
1637 /* use image size as default values for width and height for these images */
1638 static int full_size_graphics[] =
1641 IMG_GLOBAL_BORDER_MAIN,
1642 IMG_GLOBAL_BORDER_SCORES,
1643 IMG_GLOBAL_BORDER_EDITOR,
1644 IMG_GLOBAL_BORDER_PLAYING,
1647 IMG_BACKGROUND_ENVELOPE_1,
1648 IMG_BACKGROUND_ENVELOPE_2,
1649 IMG_BACKGROUND_ENVELOPE_3,
1650 IMG_BACKGROUND_ENVELOPE_4,
1651 IMG_BACKGROUND_REQUEST,
1654 IMG_BACKGROUND_TITLE_INITIAL,
1655 IMG_BACKGROUND_TITLE,
1656 IMG_BACKGROUND_MAIN,
1657 IMG_BACKGROUND_LEVELS,
1658 IMG_BACKGROUND_LEVELNR,
1659 IMG_BACKGROUND_SCORES,
1660 IMG_BACKGROUND_EDITOR,
1661 IMG_BACKGROUND_INFO,
1662 IMG_BACKGROUND_INFO_ELEMENTS,
1663 IMG_BACKGROUND_INFO_MUSIC,
1664 IMG_BACKGROUND_INFO_CREDITS,
1665 IMG_BACKGROUND_INFO_PROGRAM,
1666 IMG_BACKGROUND_INFO_VERSION,
1667 IMG_BACKGROUND_INFO_LEVELSET,
1668 IMG_BACKGROUND_SETUP,
1669 IMG_BACKGROUND_PLAYING,
1670 IMG_BACKGROUND_DOOR,
1671 IMG_BACKGROUND_TAPE,
1672 IMG_BACKGROUND_PANEL,
1673 IMG_BACKGROUND_PALETTE,
1674 IMG_BACKGROUND_TOOLBOX,
1676 IMG_TITLESCREEN_INITIAL_1,
1677 IMG_TITLESCREEN_INITIAL_2,
1678 IMG_TITLESCREEN_INITIAL_3,
1679 IMG_TITLESCREEN_INITIAL_4,
1680 IMG_TITLESCREEN_INITIAL_5,
1687 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1688 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1689 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1690 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1691 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1692 IMG_BACKGROUND_TITLEMESSAGE_1,
1693 IMG_BACKGROUND_TITLEMESSAGE_2,
1694 IMG_BACKGROUND_TITLEMESSAGE_3,
1695 IMG_BACKGROUND_TITLEMESSAGE_4,
1696 IMG_BACKGROUND_TITLEMESSAGE_5,
1701 checked_free(graphic_info);
1703 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1705 /* initialize "use_image_size" flag with default value */
1706 for (i = 0; i < num_images; i++)
1707 graphic_info[i].use_image_size = FALSE;
1709 /* initialize "use_image_size" flag from static configuration above */
1710 for (i = 0; full_size_graphics[i] != -1; i++)
1711 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1713 /* first set all graphic paramaters ... */
1714 for (i = 0; i < num_images; i++)
1715 set_graphic_parameters(i);
1717 /* ... then copy these parameters for cloned graphics */
1718 for (i = 0; i < num_images; i++)
1719 if (graphic_info[i].clone_from != -1)
1720 set_cloned_graphic_parameters(i);
1722 for (i = 0; i < num_images; i++)
1724 Bitmap *src_bitmap = graphic_info[i].bitmap;
1728 int src_bitmap_width, src_bitmap_height;
1730 /* now check if no animation frames are outside of the loaded image */
1732 if (graphic_info[i].bitmap == NULL)
1733 continue; /* skip check for optional images that are undefined */
1735 /* get image size (this can differ from the standard element tile size!) */
1736 width = graphic_info[i].width;
1737 height = graphic_info[i].height;
1739 /* get final bitmap size (with scaling, but without small images) */
1740 src_bitmap_width = graphic_info[i].src_image_width;
1741 src_bitmap_height = graphic_info[i].src_image_height;
1743 /* check if first animation frame is inside specified bitmap */
1745 /* do not use getGraphicSourceXY() here to get position of first frame; */
1746 /* this avoids calculating wrong start position for out-of-bounds frame */
1747 src_x = graphic_info[i].src_x;
1748 src_y = graphic_info[i].src_y;
1750 if (program.headless)
1753 if (src_x < 0 || src_y < 0 ||
1754 src_x + width > src_bitmap_width ||
1755 src_y + height > src_bitmap_height)
1757 Error(ERR_INFO_LINE, "-");
1758 Error(ERR_INFO, "warning: error found in config file:");
1759 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1760 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1761 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1762 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1764 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1765 src_x, src_y, src_bitmap_width, src_bitmap_height);
1766 Error(ERR_INFO, "custom graphic rejected for this element/action");
1768 if (i == fallback_graphic)
1769 Error(ERR_EXIT, "no fallback graphic available");
1771 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1772 Error(ERR_INFO_LINE, "-");
1774 graphic_info[i] = graphic_info[fallback_graphic];
1776 /* if first frame out of bounds, do not check last frame anymore */
1780 /* check if last animation frame is inside specified bitmap */
1782 last_frame = graphic_info[i].anim_frames - 1;
1783 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1785 if (src_x < 0 || src_y < 0 ||
1786 src_x + width > src_bitmap_width ||
1787 src_y + height > src_bitmap_height)
1789 Error(ERR_INFO_LINE, "-");
1790 Error(ERR_INFO, "warning: error found in config file:");
1791 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1792 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1793 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1794 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1796 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1797 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1798 Error(ERR_INFO, "custom graphic rejected for this element/action");
1800 if (i == fallback_graphic)
1801 Error(ERR_EXIT, "no fallback graphic available");
1803 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1804 Error(ERR_INFO_LINE, "-");
1806 graphic_info[i] = graphic_info[fallback_graphic];
1811 static void InitGraphicCompatibilityInfo()
1813 struct FileInfo *fi_global_door =
1814 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1815 int num_images = getImageListSize();
1818 /* the following compatibility handling is needed for the following case:
1819 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1820 graphics mainly used for door and panel graphics, like editor, tape and
1821 in-game buttons with hard-coded bitmap positions and button sizes; as
1822 these graphics now have individual definitions, redefining "global.door"
1823 to change all these graphics at once like before does not work anymore
1824 (because all those individual definitions still have their default values);
1825 to solve this, remap all those individual definitions that are not
1826 redefined to the new bitmap of "global.door" if it was redefined */
1828 /* special compatibility handling if image "global.door" was redefined */
1829 if (fi_global_door->redefined)
1831 for (i = 0; i < num_images; i++)
1833 struct FileInfo *fi = getImageListEntryFromImageID(i);
1835 /* process only those images that still use the default settings */
1838 /* process all images which default to same image as "global.door" */
1839 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1841 // printf("::: special treatment needed for token '%s'\n", fi->token);
1843 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1844 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1850 InitGraphicCompatibilityInfo_Doors();
1853 static void InitElementSoundInfo()
1855 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1856 int num_property_mappings = getSoundListPropertyMappingSize();
1859 /* set values to -1 to identify later as "uninitialized" values */
1860 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1861 for (act = 0; act < NUM_ACTIONS; act++)
1862 element_info[i].sound[act] = -1;
1864 /* initialize element/sound mapping from static configuration */
1865 for (i = 0; element_to_sound[i].element > -1; i++)
1867 int element = element_to_sound[i].element;
1868 int action = element_to_sound[i].action;
1869 int sound = element_to_sound[i].sound;
1870 boolean is_class = element_to_sound[i].is_class;
1873 action = ACTION_DEFAULT;
1876 element_info[element].sound[action] = sound;
1878 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1879 if (strEqual(element_info[j].class_name,
1880 element_info[element].class_name))
1881 element_info[j].sound[action] = sound;
1884 /* initialize element class/sound mapping from dynamic configuration */
1885 for (i = 0; i < num_property_mappings; i++)
1887 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1888 int action = property_mapping[i].ext1_index;
1889 int sound = property_mapping[i].artwork_index;
1891 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1895 action = ACTION_DEFAULT;
1897 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1898 if (strEqual(element_info[j].class_name,
1899 element_info[element_class].class_name))
1900 element_info[j].sound[action] = sound;
1903 /* initialize element/sound mapping from dynamic configuration */
1904 for (i = 0; i < num_property_mappings; i++)
1906 int element = property_mapping[i].base_index;
1907 int action = property_mapping[i].ext1_index;
1908 int sound = property_mapping[i].artwork_index;
1910 if (element >= MAX_NUM_ELEMENTS)
1914 action = ACTION_DEFAULT;
1916 element_info[element].sound[action] = sound;
1919 /* now set all '-1' values to element specific default values */
1920 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1922 for (act = 0; act < NUM_ACTIONS; act++)
1924 /* generic default action sound (defined by "[default]" directive) */
1925 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1927 /* look for special default action sound (classic game specific) */
1928 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1929 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1930 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1931 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1932 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1933 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1934 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1935 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1937 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1938 /* !!! make this better !!! */
1939 if (i == EL_EMPTY_SPACE)
1940 default_action_sound = element_info[EL_DEFAULT].sound[act];
1942 /* no sound for this specific action -- use default action sound */
1943 if (element_info[i].sound[act] == -1)
1944 element_info[i].sound[act] = default_action_sound;
1948 /* copy sound settings to some elements that are only stored in level file
1949 in native R'n'D levels, but are used by game engine in native EM levels */
1950 for (i = 0; copy_properties[i][0] != -1; i++)
1951 for (j = 1; j <= 4; j++)
1952 for (act = 0; act < NUM_ACTIONS; act++)
1953 element_info[copy_properties[i][j]].sound[act] =
1954 element_info[copy_properties[i][0]].sound[act];
1957 static void InitGameModeSoundInfo()
1961 /* set values to -1 to identify later as "uninitialized" values */
1962 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1965 /* initialize gamemode/sound mapping from static configuration */
1966 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1968 int gamemode = gamemode_to_sound[i].gamemode;
1969 int sound = gamemode_to_sound[i].sound;
1972 gamemode = GAME_MODE_DEFAULT;
1974 menu.sound[gamemode] = sound;
1977 /* now set all '-1' values to levelset specific default values */
1978 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1979 if (menu.sound[i] == -1)
1980 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1983 static void set_sound_parameters(int sound, char **parameter_raw)
1985 int parameter[NUM_SND_ARGS];
1988 /* get integer values from string parameters */
1989 for (i = 0; i < NUM_SND_ARGS; i++)
1991 get_parameter_value(parameter_raw[i],
1992 sound_config_suffix[i].token,
1993 sound_config_suffix[i].type);
1995 /* explicit loop mode setting in configuration overrides default value */
1996 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1997 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1999 /* sound volume to change the original volume when loading the sound file */
2000 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2002 /* sound priority to give certain sounds a higher or lower priority */
2003 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2006 static void InitSoundInfo()
2008 int *sound_effect_properties;
2009 int num_sounds = getSoundListSize();
2012 checked_free(sound_info);
2014 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2015 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2017 /* initialize sound effect for all elements to "no sound" */
2018 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2019 for (j = 0; j < NUM_ACTIONS; j++)
2020 element_info[i].sound[j] = SND_UNDEFINED;
2022 for (i = 0; i < num_sounds; i++)
2024 struct FileInfo *sound = getSoundListEntry(i);
2025 int len_effect_text = strlen(sound->token);
2027 sound_effect_properties[i] = ACTION_OTHER;
2028 sound_info[i].loop = FALSE; /* default: play sound only once */
2030 /* determine all loop sounds and identify certain sound classes */
2032 for (j = 0; element_action_info[j].suffix; j++)
2034 int len_action_text = strlen(element_action_info[j].suffix);
2036 if (len_action_text < len_effect_text &&
2037 strEqual(&sound->token[len_effect_text - len_action_text],
2038 element_action_info[j].suffix))
2040 sound_effect_properties[i] = element_action_info[j].value;
2041 sound_info[i].loop = element_action_info[j].is_loop_sound;
2047 /* associate elements and some selected sound actions */
2049 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2051 if (element_info[j].class_name)
2053 int len_class_text = strlen(element_info[j].class_name);
2055 if (len_class_text + 1 < len_effect_text &&
2056 strncmp(sound->token,
2057 element_info[j].class_name, len_class_text) == 0 &&
2058 sound->token[len_class_text] == '.')
2060 int sound_action_value = sound_effect_properties[i];
2062 element_info[j].sound[sound_action_value] = i;
2067 set_sound_parameters(i, sound->parameter);
2070 free(sound_effect_properties);
2073 static void InitGameModeMusicInfo()
2075 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2076 int num_property_mappings = getMusicListPropertyMappingSize();
2077 int default_levelset_music = -1;
2080 /* set values to -1 to identify later as "uninitialized" values */
2081 for (i = 0; i < MAX_LEVELS; i++)
2082 levelset.music[i] = -1;
2083 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2086 /* initialize gamemode/music mapping from static configuration */
2087 for (i = 0; gamemode_to_music[i].music > -1; i++)
2089 int gamemode = gamemode_to_music[i].gamemode;
2090 int music = gamemode_to_music[i].music;
2093 gamemode = GAME_MODE_DEFAULT;
2095 menu.music[gamemode] = music;
2098 /* initialize gamemode/music mapping from dynamic configuration */
2099 for (i = 0; i < num_property_mappings; i++)
2101 int prefix = property_mapping[i].base_index;
2102 int gamemode = property_mapping[i].ext2_index;
2103 int level = property_mapping[i].ext3_index;
2104 int music = property_mapping[i].artwork_index;
2106 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2110 gamemode = GAME_MODE_DEFAULT;
2112 /* level specific music only allowed for in-game music */
2113 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2114 gamemode = GAME_MODE_PLAYING;
2119 default_levelset_music = music;
2122 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2123 levelset.music[level] = music;
2124 if (gamemode != GAME_MODE_PLAYING)
2125 menu.music[gamemode] = music;
2128 /* now set all '-1' values to menu specific default values */
2129 /* (undefined values of "levelset.music[]" might stay at "-1" to
2130 allow dynamic selection of music files from music directory!) */
2131 for (i = 0; i < MAX_LEVELS; i++)
2132 if (levelset.music[i] == -1)
2133 levelset.music[i] = default_levelset_music;
2134 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2135 if (menu.music[i] == -1)
2136 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2139 static void set_music_parameters(int music, char **parameter_raw)
2141 int parameter[NUM_MUS_ARGS];
2144 /* get integer values from string parameters */
2145 for (i = 0; i < NUM_MUS_ARGS; i++)
2147 get_parameter_value(parameter_raw[i],
2148 music_config_suffix[i].token,
2149 music_config_suffix[i].type);
2151 /* explicit loop mode setting in configuration overrides default value */
2152 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2153 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2156 static void InitMusicInfo()
2158 int num_music = getMusicListSize();
2161 checked_free(music_info);
2163 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2165 for (i = 0; i < num_music; i++)
2167 struct FileInfo *music = getMusicListEntry(i);
2168 int len_music_text = strlen(music->token);
2170 music_info[i].loop = TRUE; /* default: play music in loop mode */
2172 /* determine all loop music */
2174 for (j = 0; music_prefix_info[j].prefix; j++)
2176 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2178 if (len_prefix_text < len_music_text &&
2179 strncmp(music->token,
2180 music_prefix_info[j].prefix, len_prefix_text) == 0)
2182 music_info[i].loop = music_prefix_info[j].is_loop_music;
2188 set_music_parameters(i, music->parameter);
2192 static void ReinitializeGraphics()
2194 print_timestamp_init("ReinitializeGraphics");
2196 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2198 InitGraphicInfo(); /* graphic properties mapping */
2199 print_timestamp_time("InitGraphicInfo");
2200 InitElementGraphicInfo(); /* element game graphic mapping */
2201 print_timestamp_time("InitElementGraphicInfo");
2202 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2203 print_timestamp_time("InitElementSpecialGraphicInfo");
2205 InitElementSmallImages(); /* scale elements to all needed sizes */
2206 print_timestamp_time("InitElementSmallImages");
2207 InitScaledImages(); /* scale all other images, if needed */
2208 print_timestamp_time("InitScaledImages");
2209 InitBitmapPointers(); /* set standard size bitmap pointers */
2210 print_timestamp_time("InitBitmapPointers");
2211 InitFontGraphicInfo(); /* initialize text drawing functions */
2212 print_timestamp_time("InitFontGraphicInfo");
2213 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2214 print_timestamp_time("InitGlobalAnimGraphicInfo");
2216 InitImageTextures(); /* create textures for certain images */
2217 print_timestamp_time("InitImageTextures");
2219 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2220 print_timestamp_time("InitGraphicInfo_EM");
2222 InitGraphicCompatibilityInfo();
2223 print_timestamp_time("InitGraphicCompatibilityInfo");
2225 SetMainBackgroundImage(IMG_BACKGROUND);
2226 print_timestamp_time("SetMainBackgroundImage");
2227 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2228 print_timestamp_time("SetDoorBackgroundImage");
2231 print_timestamp_time("InitGadgets");
2233 print_timestamp_time("InitDoors");
2235 print_timestamp_done("ReinitializeGraphics");
2238 static void ReinitializeSounds()
2240 InitSoundInfo(); /* sound properties mapping */
2241 InitElementSoundInfo(); /* element game sound mapping */
2242 InitGameModeSoundInfo(); /* game mode sound mapping */
2243 InitGlobalAnimSoundInfo(); /* global animation sound settings */
2245 InitPlayLevelSound(); /* internal game sound settings */
2248 static void ReinitializeMusic()
2250 InitMusicInfo(); /* music properties mapping */
2251 InitGameModeMusicInfo(); /* game mode music mapping */
2252 InitGlobalAnimMusicInfo(); /* global animation music settings */
2255 static int get_special_property_bit(int element, int property_bit_nr)
2257 struct PropertyBitInfo
2263 static struct PropertyBitInfo pb_can_move_into_acid[] =
2265 /* the player may be able fall into acid when gravity is activated */
2270 { EL_SP_MURPHY, 0 },
2271 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2273 /* all elements that can move may be able to also move into acid */
2276 { EL_BUG_RIGHT, 1 },
2279 { EL_SPACESHIP, 2 },
2280 { EL_SPACESHIP_LEFT, 2 },
2281 { EL_SPACESHIP_RIGHT, 2 },
2282 { EL_SPACESHIP_UP, 2 },
2283 { EL_SPACESHIP_DOWN, 2 },
2284 { EL_BD_BUTTERFLY, 3 },
2285 { EL_BD_BUTTERFLY_LEFT, 3 },
2286 { EL_BD_BUTTERFLY_RIGHT, 3 },
2287 { EL_BD_BUTTERFLY_UP, 3 },
2288 { EL_BD_BUTTERFLY_DOWN, 3 },
2289 { EL_BD_FIREFLY, 4 },
2290 { EL_BD_FIREFLY_LEFT, 4 },
2291 { EL_BD_FIREFLY_RIGHT, 4 },
2292 { EL_BD_FIREFLY_UP, 4 },
2293 { EL_BD_FIREFLY_DOWN, 4 },
2295 { EL_YAMYAM_LEFT, 5 },
2296 { EL_YAMYAM_RIGHT, 5 },
2297 { EL_YAMYAM_UP, 5 },
2298 { EL_YAMYAM_DOWN, 5 },
2299 { EL_DARK_YAMYAM, 6 },
2302 { EL_PACMAN_LEFT, 8 },
2303 { EL_PACMAN_RIGHT, 8 },
2304 { EL_PACMAN_UP, 8 },
2305 { EL_PACMAN_DOWN, 8 },
2307 { EL_MOLE_LEFT, 9 },
2308 { EL_MOLE_RIGHT, 9 },
2310 { EL_MOLE_DOWN, 9 },
2314 { EL_SATELLITE, 13 },
2315 { EL_SP_SNIKSNAK, 14 },
2316 { EL_SP_ELECTRON, 15 },
2319 { EL_EMC_ANDROID, 18 },
2324 static struct PropertyBitInfo pb_dont_collide_with[] =
2326 { EL_SP_SNIKSNAK, 0 },
2327 { EL_SP_ELECTRON, 1 },
2335 struct PropertyBitInfo *pb_info;
2338 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2339 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2344 struct PropertyBitInfo *pb_info = NULL;
2347 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2348 if (pb_definition[i].bit_nr == property_bit_nr)
2349 pb_info = pb_definition[i].pb_info;
2351 if (pb_info == NULL)
2354 for (i = 0; pb_info[i].element != -1; i++)
2355 if (pb_info[i].element == element)
2356 return pb_info[i].bit_nr;
2361 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2362 boolean property_value)
2364 int bit_nr = get_special_property_bit(element, property_bit_nr);
2369 *bitfield |= (1 << bit_nr);
2371 *bitfield &= ~(1 << bit_nr);
2375 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2377 int bit_nr = get_special_property_bit(element, property_bit_nr);
2380 return ((*bitfield & (1 << bit_nr)) != 0);
2385 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2387 static int group_nr;
2388 static struct ElementGroupInfo *group;
2389 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2392 if (actual_group == NULL) /* not yet initialized */
2395 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2397 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2398 group_element - EL_GROUP_START + 1);
2400 /* replace element which caused too deep recursion by question mark */
2401 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2406 if (recursion_depth == 0) /* initialization */
2408 group = actual_group;
2409 group_nr = GROUP_NR(group_element);
2411 group->num_elements_resolved = 0;
2412 group->choice_pos = 0;
2414 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2415 element_info[i].in_group[group_nr] = FALSE;
2418 for (i = 0; i < actual_group->num_elements; i++)
2420 int element = actual_group->element[i];
2422 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2425 if (IS_GROUP_ELEMENT(element))
2426 ResolveGroupElementExt(element, recursion_depth + 1);
2429 group->element_resolved[group->num_elements_resolved++] = element;
2430 element_info[element].in_group[group_nr] = TRUE;
2435 void ResolveGroupElement(int group_element)
2437 ResolveGroupElementExt(group_element, 0);
2440 void InitElementPropertiesStatic()
2442 static boolean clipboard_elements_initialized = FALSE;
2444 static int ep_diggable[] =
2449 EL_SP_BUGGY_BASE_ACTIVATING,
2452 EL_INVISIBLE_SAND_ACTIVE,
2455 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2456 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2461 EL_SP_BUGGY_BASE_ACTIVE,
2468 static int ep_collectible_only[] =
2490 EL_DYNABOMB_INCREASE_NUMBER,
2491 EL_DYNABOMB_INCREASE_SIZE,
2492 EL_DYNABOMB_INCREASE_POWER,
2510 /* !!! handle separately !!! */
2511 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2517 static int ep_dont_run_into[] =
2519 /* same elements as in 'ep_dont_touch' */
2525 /* same elements as in 'ep_dont_collide_with' */
2537 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2542 EL_SP_BUGGY_BASE_ACTIVE,
2549 static int ep_dont_collide_with[] =
2551 /* same elements as in 'ep_dont_touch' */
2568 static int ep_dont_touch[] =
2578 static int ep_indestructible[] =
2582 EL_ACID_POOL_TOPLEFT,
2583 EL_ACID_POOL_TOPRIGHT,
2584 EL_ACID_POOL_BOTTOMLEFT,
2585 EL_ACID_POOL_BOTTOM,
2586 EL_ACID_POOL_BOTTOMRIGHT,
2587 EL_SP_HARDWARE_GRAY,
2588 EL_SP_HARDWARE_GREEN,
2589 EL_SP_HARDWARE_BLUE,
2591 EL_SP_HARDWARE_YELLOW,
2592 EL_SP_HARDWARE_BASE_1,
2593 EL_SP_HARDWARE_BASE_2,
2594 EL_SP_HARDWARE_BASE_3,
2595 EL_SP_HARDWARE_BASE_4,
2596 EL_SP_HARDWARE_BASE_5,
2597 EL_SP_HARDWARE_BASE_6,
2598 EL_INVISIBLE_STEELWALL,
2599 EL_INVISIBLE_STEELWALL_ACTIVE,
2600 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2601 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2602 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2603 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2604 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2605 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2606 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2607 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2608 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2609 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2610 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2611 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2613 EL_LIGHT_SWITCH_ACTIVE,
2614 EL_SIGN_EXCLAMATION,
2615 EL_SIGN_RADIOACTIVITY,
2622 EL_SIGN_ENTRY_FORBIDDEN,
2623 EL_SIGN_EMERGENCY_EXIT,
2631 EL_STEEL_EXIT_CLOSED,
2633 EL_STEEL_EXIT_OPENING,
2634 EL_STEEL_EXIT_CLOSING,
2635 EL_EM_STEEL_EXIT_CLOSED,
2636 EL_EM_STEEL_EXIT_OPEN,
2637 EL_EM_STEEL_EXIT_OPENING,
2638 EL_EM_STEEL_EXIT_CLOSING,
2639 EL_DC_STEELWALL_1_LEFT,
2640 EL_DC_STEELWALL_1_RIGHT,
2641 EL_DC_STEELWALL_1_TOP,
2642 EL_DC_STEELWALL_1_BOTTOM,
2643 EL_DC_STEELWALL_1_HORIZONTAL,
2644 EL_DC_STEELWALL_1_VERTICAL,
2645 EL_DC_STEELWALL_1_TOPLEFT,
2646 EL_DC_STEELWALL_1_TOPRIGHT,
2647 EL_DC_STEELWALL_1_BOTTOMLEFT,
2648 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2649 EL_DC_STEELWALL_1_TOPLEFT_2,
2650 EL_DC_STEELWALL_1_TOPRIGHT_2,
2651 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2652 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2653 EL_DC_STEELWALL_2_LEFT,
2654 EL_DC_STEELWALL_2_RIGHT,
2655 EL_DC_STEELWALL_2_TOP,
2656 EL_DC_STEELWALL_2_BOTTOM,
2657 EL_DC_STEELWALL_2_HORIZONTAL,
2658 EL_DC_STEELWALL_2_VERTICAL,
2659 EL_DC_STEELWALL_2_MIDDLE,
2660 EL_DC_STEELWALL_2_SINGLE,
2661 EL_STEELWALL_SLIPPERY,
2675 EL_GATE_1_GRAY_ACTIVE,
2676 EL_GATE_2_GRAY_ACTIVE,
2677 EL_GATE_3_GRAY_ACTIVE,
2678 EL_GATE_4_GRAY_ACTIVE,
2687 EL_EM_GATE_1_GRAY_ACTIVE,
2688 EL_EM_GATE_2_GRAY_ACTIVE,
2689 EL_EM_GATE_3_GRAY_ACTIVE,
2690 EL_EM_GATE_4_GRAY_ACTIVE,
2699 EL_EMC_GATE_5_GRAY_ACTIVE,
2700 EL_EMC_GATE_6_GRAY_ACTIVE,
2701 EL_EMC_GATE_7_GRAY_ACTIVE,
2702 EL_EMC_GATE_8_GRAY_ACTIVE,
2704 EL_DC_GATE_WHITE_GRAY,
2705 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2706 EL_DC_GATE_FAKE_GRAY,
2708 EL_SWITCHGATE_OPENING,
2709 EL_SWITCHGATE_CLOSED,
2710 EL_SWITCHGATE_CLOSING,
2711 EL_DC_SWITCHGATE_SWITCH_UP,
2712 EL_DC_SWITCHGATE_SWITCH_DOWN,
2714 EL_TIMEGATE_OPENING,
2716 EL_TIMEGATE_CLOSING,
2717 EL_DC_TIMEGATE_SWITCH,
2718 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2722 EL_TUBE_VERTICAL_LEFT,
2723 EL_TUBE_VERTICAL_RIGHT,
2724 EL_TUBE_HORIZONTAL_UP,
2725 EL_TUBE_HORIZONTAL_DOWN,
2730 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2731 EL_EXPANDABLE_STEELWALL_VERTICAL,
2732 EL_EXPANDABLE_STEELWALL_ANY,
2737 static int ep_slippery[] =
2751 EL_ROBOT_WHEEL_ACTIVE,
2757 EL_ACID_POOL_TOPLEFT,
2758 EL_ACID_POOL_TOPRIGHT,
2768 EL_STEELWALL_SLIPPERY,
2771 EL_EMC_WALL_SLIPPERY_1,
2772 EL_EMC_WALL_SLIPPERY_2,
2773 EL_EMC_WALL_SLIPPERY_3,
2774 EL_EMC_WALL_SLIPPERY_4,
2776 EL_EMC_MAGIC_BALL_ACTIVE,
2781 static int ep_can_change[] =
2786 static int ep_can_move[] =
2788 /* same elements as in 'pb_can_move_into_acid' */
2811 static int ep_can_fall[] =
2825 EL_QUICKSAND_FAST_FULL,
2827 EL_BD_MAGIC_WALL_FULL,
2828 EL_DC_MAGIC_WALL_FULL,
2842 static int ep_can_smash_player[] =
2868 static int ep_can_smash_enemies[] =
2877 static int ep_can_smash_everything[] =
2886 static int ep_explodes_by_fire[] =
2888 /* same elements as in 'ep_explodes_impact' */
2893 /* same elements as in 'ep_explodes_smashed' */
2903 EL_EM_DYNAMITE_ACTIVE,
2904 EL_DYNABOMB_PLAYER_1_ACTIVE,
2905 EL_DYNABOMB_PLAYER_2_ACTIVE,
2906 EL_DYNABOMB_PLAYER_3_ACTIVE,
2907 EL_DYNABOMB_PLAYER_4_ACTIVE,
2908 EL_DYNABOMB_INCREASE_NUMBER,
2909 EL_DYNABOMB_INCREASE_SIZE,
2910 EL_DYNABOMB_INCREASE_POWER,
2911 EL_SP_DISK_RED_ACTIVE,
2925 static int ep_explodes_smashed[] =
2927 /* same elements as in 'ep_explodes_impact' */
2941 static int ep_explodes_impact[] =
2950 static int ep_walkable_over[] =
2954 EL_SOKOBAN_FIELD_EMPTY,
2961 EL_EM_STEEL_EXIT_OPEN,
2962 EL_EM_STEEL_EXIT_OPENING,
2971 EL_GATE_1_GRAY_ACTIVE,
2972 EL_GATE_2_GRAY_ACTIVE,
2973 EL_GATE_3_GRAY_ACTIVE,
2974 EL_GATE_4_GRAY_ACTIVE,
2982 static int ep_walkable_inside[] =
2987 EL_TUBE_VERTICAL_LEFT,
2988 EL_TUBE_VERTICAL_RIGHT,
2989 EL_TUBE_HORIZONTAL_UP,
2990 EL_TUBE_HORIZONTAL_DOWN,
2999 static int ep_walkable_under[] =
3004 static int ep_passable_over[] =
3014 EL_EM_GATE_1_GRAY_ACTIVE,
3015 EL_EM_GATE_2_GRAY_ACTIVE,
3016 EL_EM_GATE_3_GRAY_ACTIVE,
3017 EL_EM_GATE_4_GRAY_ACTIVE,
3026 EL_EMC_GATE_5_GRAY_ACTIVE,
3027 EL_EMC_GATE_6_GRAY_ACTIVE,
3028 EL_EMC_GATE_7_GRAY_ACTIVE,
3029 EL_EMC_GATE_8_GRAY_ACTIVE,
3031 EL_DC_GATE_WHITE_GRAY,
3032 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3039 static int ep_passable_inside[] =
3045 EL_SP_PORT_HORIZONTAL,
3046 EL_SP_PORT_VERTICAL,
3048 EL_SP_GRAVITY_PORT_LEFT,
3049 EL_SP_GRAVITY_PORT_RIGHT,
3050 EL_SP_GRAVITY_PORT_UP,
3051 EL_SP_GRAVITY_PORT_DOWN,
3052 EL_SP_GRAVITY_ON_PORT_LEFT,
3053 EL_SP_GRAVITY_ON_PORT_RIGHT,
3054 EL_SP_GRAVITY_ON_PORT_UP,
3055 EL_SP_GRAVITY_ON_PORT_DOWN,
3056 EL_SP_GRAVITY_OFF_PORT_LEFT,
3057 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3058 EL_SP_GRAVITY_OFF_PORT_UP,
3059 EL_SP_GRAVITY_OFF_PORT_DOWN,
3064 static int ep_passable_under[] =
3069 static int ep_droppable[] =
3074 static int ep_explodes_1x1_old[] =
3079 static int ep_pushable[] =
3091 EL_SOKOBAN_FIELD_FULL,
3100 static int ep_explodes_cross_old[] =
3105 static int ep_protected[] =
3107 /* same elements as in 'ep_walkable_inside' */
3111 EL_TUBE_VERTICAL_LEFT,
3112 EL_TUBE_VERTICAL_RIGHT,
3113 EL_TUBE_HORIZONTAL_UP,
3114 EL_TUBE_HORIZONTAL_DOWN,
3120 /* same elements as in 'ep_passable_over' */
3129 EL_EM_GATE_1_GRAY_ACTIVE,
3130 EL_EM_GATE_2_GRAY_ACTIVE,
3131 EL_EM_GATE_3_GRAY_ACTIVE,
3132 EL_EM_GATE_4_GRAY_ACTIVE,
3141 EL_EMC_GATE_5_GRAY_ACTIVE,
3142 EL_EMC_GATE_6_GRAY_ACTIVE,
3143 EL_EMC_GATE_7_GRAY_ACTIVE,
3144 EL_EMC_GATE_8_GRAY_ACTIVE,
3146 EL_DC_GATE_WHITE_GRAY,
3147 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3151 /* same elements as in 'ep_passable_inside' */
3156 EL_SP_PORT_HORIZONTAL,
3157 EL_SP_PORT_VERTICAL,
3159 EL_SP_GRAVITY_PORT_LEFT,
3160 EL_SP_GRAVITY_PORT_RIGHT,
3161 EL_SP_GRAVITY_PORT_UP,
3162 EL_SP_GRAVITY_PORT_DOWN,
3163 EL_SP_GRAVITY_ON_PORT_LEFT,
3164 EL_SP_GRAVITY_ON_PORT_RIGHT,
3165 EL_SP_GRAVITY_ON_PORT_UP,
3166 EL_SP_GRAVITY_ON_PORT_DOWN,
3167 EL_SP_GRAVITY_OFF_PORT_LEFT,
3168 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3169 EL_SP_GRAVITY_OFF_PORT_UP,
3170 EL_SP_GRAVITY_OFF_PORT_DOWN,
3175 static int ep_throwable[] =
3180 static int ep_can_explode[] =
3182 /* same elements as in 'ep_explodes_impact' */
3187 /* same elements as in 'ep_explodes_smashed' */
3193 /* elements that can explode by explosion or by dragonfire */
3197 EL_EM_DYNAMITE_ACTIVE,
3198 EL_DYNABOMB_PLAYER_1_ACTIVE,
3199 EL_DYNABOMB_PLAYER_2_ACTIVE,
3200 EL_DYNABOMB_PLAYER_3_ACTIVE,
3201 EL_DYNABOMB_PLAYER_4_ACTIVE,
3202 EL_DYNABOMB_INCREASE_NUMBER,
3203 EL_DYNABOMB_INCREASE_SIZE,
3204 EL_DYNABOMB_INCREASE_POWER,
3205 EL_SP_DISK_RED_ACTIVE,
3213 /* elements that can explode only by explosion */
3219 static int ep_gravity_reachable[] =
3225 EL_INVISIBLE_SAND_ACTIVE,
3230 EL_SP_PORT_HORIZONTAL,
3231 EL_SP_PORT_VERTICAL,
3233 EL_SP_GRAVITY_PORT_LEFT,
3234 EL_SP_GRAVITY_PORT_RIGHT,
3235 EL_SP_GRAVITY_PORT_UP,
3236 EL_SP_GRAVITY_PORT_DOWN,
3237 EL_SP_GRAVITY_ON_PORT_LEFT,
3238 EL_SP_GRAVITY_ON_PORT_RIGHT,
3239 EL_SP_GRAVITY_ON_PORT_UP,
3240 EL_SP_GRAVITY_ON_PORT_DOWN,
3241 EL_SP_GRAVITY_OFF_PORT_LEFT,
3242 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3243 EL_SP_GRAVITY_OFF_PORT_UP,
3244 EL_SP_GRAVITY_OFF_PORT_DOWN,
3250 static int ep_player[] =
3257 EL_SOKOBAN_FIELD_PLAYER,
3263 static int ep_can_pass_magic_wall[] =
3277 static int ep_can_pass_dc_magic_wall[] =
3293 static int ep_switchable[] =
3297 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3298 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3299 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3300 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3301 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3302 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3303 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3304 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3305 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3306 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3307 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3308 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3309 EL_SWITCHGATE_SWITCH_UP,
3310 EL_SWITCHGATE_SWITCH_DOWN,
3311 EL_DC_SWITCHGATE_SWITCH_UP,
3312 EL_DC_SWITCHGATE_SWITCH_DOWN,
3314 EL_LIGHT_SWITCH_ACTIVE,
3316 EL_DC_TIMEGATE_SWITCH,
3317 EL_BALLOON_SWITCH_LEFT,
3318 EL_BALLOON_SWITCH_RIGHT,
3319 EL_BALLOON_SWITCH_UP,
3320 EL_BALLOON_SWITCH_DOWN,
3321 EL_BALLOON_SWITCH_ANY,
3322 EL_BALLOON_SWITCH_NONE,
3325 EL_EMC_MAGIC_BALL_SWITCH,
3326 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3331 static int ep_bd_element[] =
3365 static int ep_sp_element[] =
3367 /* should always be valid */
3370 /* standard classic Supaplex elements */
3377 EL_SP_HARDWARE_GRAY,
3385 EL_SP_GRAVITY_PORT_RIGHT,
3386 EL_SP_GRAVITY_PORT_DOWN,
3387 EL_SP_GRAVITY_PORT_LEFT,
3388 EL_SP_GRAVITY_PORT_UP,
3393 EL_SP_PORT_VERTICAL,
3394 EL_SP_PORT_HORIZONTAL,
3400 EL_SP_HARDWARE_BASE_1,
3401 EL_SP_HARDWARE_GREEN,
3402 EL_SP_HARDWARE_BLUE,
3404 EL_SP_HARDWARE_YELLOW,
3405 EL_SP_HARDWARE_BASE_2,
3406 EL_SP_HARDWARE_BASE_3,
3407 EL_SP_HARDWARE_BASE_4,
3408 EL_SP_HARDWARE_BASE_5,
3409 EL_SP_HARDWARE_BASE_6,
3413 /* additional elements that appeared in newer Supaplex levels */
3416 /* additional gravity port elements (not switching, but setting gravity) */
3417 EL_SP_GRAVITY_ON_PORT_LEFT,
3418 EL_SP_GRAVITY_ON_PORT_RIGHT,
3419 EL_SP_GRAVITY_ON_PORT_UP,
3420 EL_SP_GRAVITY_ON_PORT_DOWN,
3421 EL_SP_GRAVITY_OFF_PORT_LEFT,
3422 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3423 EL_SP_GRAVITY_OFF_PORT_UP,
3424 EL_SP_GRAVITY_OFF_PORT_DOWN,
3426 /* more than one Murphy in a level results in an inactive clone */
3429 /* runtime Supaplex elements */
3430 EL_SP_DISK_RED_ACTIVE,
3431 EL_SP_TERMINAL_ACTIVE,
3432 EL_SP_BUGGY_BASE_ACTIVATING,
3433 EL_SP_BUGGY_BASE_ACTIVE,
3440 static int ep_sb_element[] =
3445 EL_SOKOBAN_FIELD_EMPTY,
3446 EL_SOKOBAN_FIELD_FULL,
3447 EL_SOKOBAN_FIELD_PLAYER,
3452 EL_INVISIBLE_STEELWALL,
3457 static int ep_gem[] =
3469 static int ep_food_dark_yamyam[] =
3497 static int ep_food_penguin[] =
3511 static int ep_food_pig[] =
3523 static int ep_historic_wall[] =
3534 EL_GATE_1_GRAY_ACTIVE,
3535 EL_GATE_2_GRAY_ACTIVE,
3536 EL_GATE_3_GRAY_ACTIVE,
3537 EL_GATE_4_GRAY_ACTIVE,
3546 EL_EM_GATE_1_GRAY_ACTIVE,
3547 EL_EM_GATE_2_GRAY_ACTIVE,
3548 EL_EM_GATE_3_GRAY_ACTIVE,
3549 EL_EM_GATE_4_GRAY_ACTIVE,
3556 EL_EXPANDABLE_WALL_HORIZONTAL,
3557 EL_EXPANDABLE_WALL_VERTICAL,
3558 EL_EXPANDABLE_WALL_ANY,
3559 EL_EXPANDABLE_WALL_GROWING,
3560 EL_BD_EXPANDABLE_WALL,
3567 EL_SP_HARDWARE_GRAY,
3568 EL_SP_HARDWARE_GREEN,
3569 EL_SP_HARDWARE_BLUE,
3571 EL_SP_HARDWARE_YELLOW,
3572 EL_SP_HARDWARE_BASE_1,
3573 EL_SP_HARDWARE_BASE_2,
3574 EL_SP_HARDWARE_BASE_3,
3575 EL_SP_HARDWARE_BASE_4,
3576 EL_SP_HARDWARE_BASE_5,
3577 EL_SP_HARDWARE_BASE_6,
3579 EL_SP_TERMINAL_ACTIVE,
3582 EL_INVISIBLE_STEELWALL,
3583 EL_INVISIBLE_STEELWALL_ACTIVE,
3585 EL_INVISIBLE_WALL_ACTIVE,
3586 EL_STEELWALL_SLIPPERY,
3603 static int ep_historic_solid[] =
3607 EL_EXPANDABLE_WALL_HORIZONTAL,
3608 EL_EXPANDABLE_WALL_VERTICAL,
3609 EL_EXPANDABLE_WALL_ANY,
3610 EL_BD_EXPANDABLE_WALL,
3623 EL_QUICKSAND_FILLING,
3624 EL_QUICKSAND_EMPTYING,
3626 EL_MAGIC_WALL_ACTIVE,
3627 EL_MAGIC_WALL_EMPTYING,
3628 EL_MAGIC_WALL_FILLING,
3632 EL_BD_MAGIC_WALL_ACTIVE,
3633 EL_BD_MAGIC_WALL_EMPTYING,
3634 EL_BD_MAGIC_WALL_FULL,
3635 EL_BD_MAGIC_WALL_FILLING,
3636 EL_BD_MAGIC_WALL_DEAD,
3645 EL_SP_TERMINAL_ACTIVE,
3649 EL_INVISIBLE_WALL_ACTIVE,
3650 EL_SWITCHGATE_SWITCH_UP,
3651 EL_SWITCHGATE_SWITCH_DOWN,
3652 EL_DC_SWITCHGATE_SWITCH_UP,
3653 EL_DC_SWITCHGATE_SWITCH_DOWN,
3655 EL_TIMEGATE_SWITCH_ACTIVE,
3656 EL_DC_TIMEGATE_SWITCH,
3657 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3669 /* the following elements are a direct copy of "indestructible" elements,
3670 except "EL_ACID", which is "indestructible", but not "solid"! */
3675 EL_ACID_POOL_TOPLEFT,
3676 EL_ACID_POOL_TOPRIGHT,
3677 EL_ACID_POOL_BOTTOMLEFT,
3678 EL_ACID_POOL_BOTTOM,
3679 EL_ACID_POOL_BOTTOMRIGHT,
3680 EL_SP_HARDWARE_GRAY,
3681 EL_SP_HARDWARE_GREEN,
3682 EL_SP_HARDWARE_BLUE,
3684 EL_SP_HARDWARE_YELLOW,
3685 EL_SP_HARDWARE_BASE_1,
3686 EL_SP_HARDWARE_BASE_2,
3687 EL_SP_HARDWARE_BASE_3,
3688 EL_SP_HARDWARE_BASE_4,
3689 EL_SP_HARDWARE_BASE_5,
3690 EL_SP_HARDWARE_BASE_6,
3691 EL_INVISIBLE_STEELWALL,
3692 EL_INVISIBLE_STEELWALL_ACTIVE,
3693 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3694 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3695 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3696 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3697 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3698 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3699 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3700 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3701 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3702 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3703 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3704 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3706 EL_LIGHT_SWITCH_ACTIVE,
3707 EL_SIGN_EXCLAMATION,
3708 EL_SIGN_RADIOACTIVITY,
3715 EL_SIGN_ENTRY_FORBIDDEN,
3716 EL_SIGN_EMERGENCY_EXIT,
3724 EL_STEEL_EXIT_CLOSED,
3726 EL_DC_STEELWALL_1_LEFT,
3727 EL_DC_STEELWALL_1_RIGHT,
3728 EL_DC_STEELWALL_1_TOP,
3729 EL_DC_STEELWALL_1_BOTTOM,
3730 EL_DC_STEELWALL_1_HORIZONTAL,
3731 EL_DC_STEELWALL_1_VERTICAL,
3732 EL_DC_STEELWALL_1_TOPLEFT,
3733 EL_DC_STEELWALL_1_TOPRIGHT,
3734 EL_DC_STEELWALL_1_BOTTOMLEFT,
3735 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3736 EL_DC_STEELWALL_1_TOPLEFT_2,
3737 EL_DC_STEELWALL_1_TOPRIGHT_2,
3738 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3739 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3740 EL_DC_STEELWALL_2_LEFT,
3741 EL_DC_STEELWALL_2_RIGHT,
3742 EL_DC_STEELWALL_2_TOP,
3743 EL_DC_STEELWALL_2_BOTTOM,
3744 EL_DC_STEELWALL_2_HORIZONTAL,
3745 EL_DC_STEELWALL_2_VERTICAL,
3746 EL_DC_STEELWALL_2_MIDDLE,
3747 EL_DC_STEELWALL_2_SINGLE,
3748 EL_STEELWALL_SLIPPERY,
3762 EL_GATE_1_GRAY_ACTIVE,
3763 EL_GATE_2_GRAY_ACTIVE,
3764 EL_GATE_3_GRAY_ACTIVE,
3765 EL_GATE_4_GRAY_ACTIVE,
3774 EL_EM_GATE_1_GRAY_ACTIVE,
3775 EL_EM_GATE_2_GRAY_ACTIVE,
3776 EL_EM_GATE_3_GRAY_ACTIVE,
3777 EL_EM_GATE_4_GRAY_ACTIVE,
3779 EL_SWITCHGATE_OPENING,
3780 EL_SWITCHGATE_CLOSED,
3781 EL_SWITCHGATE_CLOSING,
3783 EL_TIMEGATE_OPENING,
3785 EL_TIMEGATE_CLOSING,
3789 EL_TUBE_VERTICAL_LEFT,
3790 EL_TUBE_VERTICAL_RIGHT,
3791 EL_TUBE_HORIZONTAL_UP,
3792 EL_TUBE_HORIZONTAL_DOWN,
3801 static int ep_classic_enemy[] =
3818 static int ep_belt[] =
3820 EL_CONVEYOR_BELT_1_LEFT,
3821 EL_CONVEYOR_BELT_1_MIDDLE,
3822 EL_CONVEYOR_BELT_1_RIGHT,
3823 EL_CONVEYOR_BELT_2_LEFT,
3824 EL_CONVEYOR_BELT_2_MIDDLE,
3825 EL_CONVEYOR_BELT_2_RIGHT,
3826 EL_CONVEYOR_BELT_3_LEFT,
3827 EL_CONVEYOR_BELT_3_MIDDLE,
3828 EL_CONVEYOR_BELT_3_RIGHT,
3829 EL_CONVEYOR_BELT_4_LEFT,
3830 EL_CONVEYOR_BELT_4_MIDDLE,
3831 EL_CONVEYOR_BELT_4_RIGHT,
3836 static int ep_belt_active[] =
3838 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3839 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3840 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3841 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3842 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3843 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3844 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3845 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3846 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3847 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3848 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3849 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3854 static int ep_belt_switch[] =
3856 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3857 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3858 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3859 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3860 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3861 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3862 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3863 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3864 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3865 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3866 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3867 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3872 static int ep_tube[] =
3879 EL_TUBE_HORIZONTAL_UP,
3880 EL_TUBE_HORIZONTAL_DOWN,
3882 EL_TUBE_VERTICAL_LEFT,
3883 EL_TUBE_VERTICAL_RIGHT,
3889 static int ep_acid_pool[] =
3891 EL_ACID_POOL_TOPLEFT,
3892 EL_ACID_POOL_TOPRIGHT,
3893 EL_ACID_POOL_BOTTOMLEFT,
3894 EL_ACID_POOL_BOTTOM,
3895 EL_ACID_POOL_BOTTOMRIGHT,
3900 static int ep_keygate[] =
3910 EL_GATE_1_GRAY_ACTIVE,
3911 EL_GATE_2_GRAY_ACTIVE,
3912 EL_GATE_3_GRAY_ACTIVE,
3913 EL_GATE_4_GRAY_ACTIVE,
3922 EL_EM_GATE_1_GRAY_ACTIVE,
3923 EL_EM_GATE_2_GRAY_ACTIVE,
3924 EL_EM_GATE_3_GRAY_ACTIVE,
3925 EL_EM_GATE_4_GRAY_ACTIVE,
3934 EL_EMC_GATE_5_GRAY_ACTIVE,
3935 EL_EMC_GATE_6_GRAY_ACTIVE,
3936 EL_EMC_GATE_7_GRAY_ACTIVE,
3937 EL_EMC_GATE_8_GRAY_ACTIVE,
3939 EL_DC_GATE_WHITE_GRAY,
3940 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3945 static int ep_amoeboid[] =
3957 static int ep_amoebalive[] =
3968 static int ep_has_editor_content[] =
3974 EL_SOKOBAN_FIELD_PLAYER,
3991 static int ep_can_turn_each_move[] =
3993 /* !!! do something with this one !!! */
3997 static int ep_can_grow[] =
4011 static int ep_active_bomb[] =
4014 EL_EM_DYNAMITE_ACTIVE,
4015 EL_DYNABOMB_PLAYER_1_ACTIVE,
4016 EL_DYNABOMB_PLAYER_2_ACTIVE,
4017 EL_DYNABOMB_PLAYER_3_ACTIVE,
4018 EL_DYNABOMB_PLAYER_4_ACTIVE,
4019 EL_SP_DISK_RED_ACTIVE,
4024 static int ep_inactive[] =
4034 EL_QUICKSAND_FAST_EMPTY,
4057 EL_GATE_1_GRAY_ACTIVE,
4058 EL_GATE_2_GRAY_ACTIVE,
4059 EL_GATE_3_GRAY_ACTIVE,
4060 EL_GATE_4_GRAY_ACTIVE,
4069 EL_EM_GATE_1_GRAY_ACTIVE,
4070 EL_EM_GATE_2_GRAY_ACTIVE,
4071 EL_EM_GATE_3_GRAY_ACTIVE,
4072 EL_EM_GATE_4_GRAY_ACTIVE,
4081 EL_EMC_GATE_5_GRAY_ACTIVE,
4082 EL_EMC_GATE_6_GRAY_ACTIVE,
4083 EL_EMC_GATE_7_GRAY_ACTIVE,
4084 EL_EMC_GATE_8_GRAY_ACTIVE,
4086 EL_DC_GATE_WHITE_GRAY,
4087 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4088 EL_DC_GATE_FAKE_GRAY,
4091 EL_INVISIBLE_STEELWALL,
4099 EL_WALL_EMERALD_YELLOW,
4100 EL_DYNABOMB_INCREASE_NUMBER,
4101 EL_DYNABOMB_INCREASE_SIZE,
4102 EL_DYNABOMB_INCREASE_POWER,
4106 EL_SOKOBAN_FIELD_EMPTY,
4107 EL_SOKOBAN_FIELD_FULL,
4108 EL_WALL_EMERALD_RED,
4109 EL_WALL_EMERALD_PURPLE,
4110 EL_ACID_POOL_TOPLEFT,
4111 EL_ACID_POOL_TOPRIGHT,
4112 EL_ACID_POOL_BOTTOMLEFT,
4113 EL_ACID_POOL_BOTTOM,
4114 EL_ACID_POOL_BOTTOMRIGHT,
4118 EL_BD_MAGIC_WALL_DEAD,
4120 EL_DC_MAGIC_WALL_DEAD,
4121 EL_AMOEBA_TO_DIAMOND,
4129 EL_SP_GRAVITY_PORT_RIGHT,
4130 EL_SP_GRAVITY_PORT_DOWN,
4131 EL_SP_GRAVITY_PORT_LEFT,
4132 EL_SP_GRAVITY_PORT_UP,
4133 EL_SP_PORT_HORIZONTAL,
4134 EL_SP_PORT_VERTICAL,
4145 EL_SP_HARDWARE_GRAY,
4146 EL_SP_HARDWARE_GREEN,
4147 EL_SP_HARDWARE_BLUE,
4149 EL_SP_HARDWARE_YELLOW,
4150 EL_SP_HARDWARE_BASE_1,
4151 EL_SP_HARDWARE_BASE_2,
4152 EL_SP_HARDWARE_BASE_3,
4153 EL_SP_HARDWARE_BASE_4,
4154 EL_SP_HARDWARE_BASE_5,
4155 EL_SP_HARDWARE_BASE_6,
4156 EL_SP_GRAVITY_ON_PORT_LEFT,
4157 EL_SP_GRAVITY_ON_PORT_RIGHT,
4158 EL_SP_GRAVITY_ON_PORT_UP,
4159 EL_SP_GRAVITY_ON_PORT_DOWN,
4160 EL_SP_GRAVITY_OFF_PORT_LEFT,
4161 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4162 EL_SP_GRAVITY_OFF_PORT_UP,
4163 EL_SP_GRAVITY_OFF_PORT_DOWN,
4164 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4165 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4166 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4167 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4168 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4169 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4170 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4171 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4172 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4173 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4174 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4175 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4176 EL_SIGN_EXCLAMATION,
4177 EL_SIGN_RADIOACTIVITY,
4184 EL_SIGN_ENTRY_FORBIDDEN,
4185 EL_SIGN_EMERGENCY_EXIT,
4193 EL_DC_STEELWALL_1_LEFT,
4194 EL_DC_STEELWALL_1_RIGHT,
4195 EL_DC_STEELWALL_1_TOP,
4196 EL_DC_STEELWALL_1_BOTTOM,
4197 EL_DC_STEELWALL_1_HORIZONTAL,
4198 EL_DC_STEELWALL_1_VERTICAL,
4199 EL_DC_STEELWALL_1_TOPLEFT,
4200 EL_DC_STEELWALL_1_TOPRIGHT,
4201 EL_DC_STEELWALL_1_BOTTOMLEFT,
4202 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4203 EL_DC_STEELWALL_1_TOPLEFT_2,
4204 EL_DC_STEELWALL_1_TOPRIGHT_2,
4205 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4206 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4207 EL_DC_STEELWALL_2_LEFT,
4208 EL_DC_STEELWALL_2_RIGHT,
4209 EL_DC_STEELWALL_2_TOP,
4210 EL_DC_STEELWALL_2_BOTTOM,
4211 EL_DC_STEELWALL_2_HORIZONTAL,
4212 EL_DC_STEELWALL_2_VERTICAL,
4213 EL_DC_STEELWALL_2_MIDDLE,
4214 EL_DC_STEELWALL_2_SINGLE,
4215 EL_STEELWALL_SLIPPERY,
4220 EL_EMC_WALL_SLIPPERY_1,
4221 EL_EMC_WALL_SLIPPERY_2,
4222 EL_EMC_WALL_SLIPPERY_3,
4223 EL_EMC_WALL_SLIPPERY_4,
4244 static int ep_em_slippery_wall[] =
4249 static int ep_gfx_crumbled[] =
4260 static int ep_editor_cascade_active[] =
4262 EL_INTERNAL_CASCADE_BD_ACTIVE,
4263 EL_INTERNAL_CASCADE_EM_ACTIVE,
4264 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4265 EL_INTERNAL_CASCADE_RND_ACTIVE,
4266 EL_INTERNAL_CASCADE_SB_ACTIVE,
4267 EL_INTERNAL_CASCADE_SP_ACTIVE,
4268 EL_INTERNAL_CASCADE_DC_ACTIVE,
4269 EL_INTERNAL_CASCADE_DX_ACTIVE,
4270 EL_INTERNAL_CASCADE_MM_ACTIVE,
4271 EL_INTERNAL_CASCADE_DF_ACTIVE,
4272 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4273 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4274 EL_INTERNAL_CASCADE_CE_ACTIVE,
4275 EL_INTERNAL_CASCADE_GE_ACTIVE,
4276 EL_INTERNAL_CASCADE_REF_ACTIVE,
4277 EL_INTERNAL_CASCADE_USER_ACTIVE,
4278 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4283 static int ep_editor_cascade_inactive[] =
4285 EL_INTERNAL_CASCADE_BD,
4286 EL_INTERNAL_CASCADE_EM,
4287 EL_INTERNAL_CASCADE_EMC,
4288 EL_INTERNAL_CASCADE_RND,
4289 EL_INTERNAL_CASCADE_SB,
4290 EL_INTERNAL_CASCADE_SP,
4291 EL_INTERNAL_CASCADE_DC,
4292 EL_INTERNAL_CASCADE_DX,
4293 EL_INTERNAL_CASCADE_MM,
4294 EL_INTERNAL_CASCADE_DF,
4295 EL_INTERNAL_CASCADE_CHARS,
4296 EL_INTERNAL_CASCADE_STEEL_CHARS,
4297 EL_INTERNAL_CASCADE_CE,
4298 EL_INTERNAL_CASCADE_GE,
4299 EL_INTERNAL_CASCADE_REF,
4300 EL_INTERNAL_CASCADE_USER,
4301 EL_INTERNAL_CASCADE_DYNAMIC,
4306 static int ep_obsolete[] =
4310 EL_EM_KEY_1_FILE_OBSOLETE,
4311 EL_EM_KEY_2_FILE_OBSOLETE,
4312 EL_EM_KEY_3_FILE_OBSOLETE,
4313 EL_EM_KEY_4_FILE_OBSOLETE,
4314 EL_ENVELOPE_OBSOLETE,
4323 } element_properties[] =
4325 { ep_diggable, EP_DIGGABLE },
4326 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4327 { ep_dont_run_into, EP_DONT_RUN_INTO },
4328 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4329 { ep_dont_touch, EP_DONT_TOUCH },
4330 { ep_indestructible, EP_INDESTRUCTIBLE },
4331 { ep_slippery, EP_SLIPPERY },
4332 { ep_can_change, EP_CAN_CHANGE },
4333 { ep_can_move, EP_CAN_MOVE },
4334 { ep_can_fall, EP_CAN_FALL },
4335 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4336 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4337 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4338 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4339 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4340 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4341 { ep_walkable_over, EP_WALKABLE_OVER },
4342 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4343 { ep_walkable_under, EP_WALKABLE_UNDER },
4344 { ep_passable_over, EP_PASSABLE_OVER },
4345 { ep_passable_inside, EP_PASSABLE_INSIDE },
4346 { ep_passable_under, EP_PASSABLE_UNDER },
4347 { ep_droppable, EP_DROPPABLE },
4348 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4349 { ep_pushable, EP_PUSHABLE },
4350 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4351 { ep_protected, EP_PROTECTED },
4352 { ep_throwable, EP_THROWABLE },
4353 { ep_can_explode, EP_CAN_EXPLODE },
4354 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4356 { ep_player, EP_PLAYER },
4357 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4358 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4359 { ep_switchable, EP_SWITCHABLE },
4360 { ep_bd_element, EP_BD_ELEMENT },
4361 { ep_sp_element, EP_SP_ELEMENT },
4362 { ep_sb_element, EP_SB_ELEMENT },
4364 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4365 { ep_food_penguin, EP_FOOD_PENGUIN },
4366 { ep_food_pig, EP_FOOD_PIG },
4367 { ep_historic_wall, EP_HISTORIC_WALL },
4368 { ep_historic_solid, EP_HISTORIC_SOLID },
4369 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4370 { ep_belt, EP_BELT },
4371 { ep_belt_active, EP_BELT_ACTIVE },
4372 { ep_belt_switch, EP_BELT_SWITCH },
4373 { ep_tube, EP_TUBE },
4374 { ep_acid_pool, EP_ACID_POOL },
4375 { ep_keygate, EP_KEYGATE },
4376 { ep_amoeboid, EP_AMOEBOID },
4377 { ep_amoebalive, EP_AMOEBALIVE },
4378 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4379 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4380 { ep_can_grow, EP_CAN_GROW },
4381 { ep_active_bomb, EP_ACTIVE_BOMB },
4382 { ep_inactive, EP_INACTIVE },
4384 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4386 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4388 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4389 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4391 { ep_obsolete, EP_OBSOLETE },
4398 /* always start with reliable default values (element has no properties) */
4399 /* (but never initialize clipboard elements after the very first time) */
4400 /* (to be able to use clipboard elements between several levels) */
4401 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4402 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4403 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4404 SET_PROPERTY(i, j, FALSE);
4406 /* set all base element properties from above array definitions */
4407 for (i = 0; element_properties[i].elements != NULL; i++)
4408 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4409 SET_PROPERTY((element_properties[i].elements)[j],
4410 element_properties[i].property, TRUE);
4412 /* copy properties to some elements that are only stored in level file */
4413 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4414 for (j = 0; copy_properties[j][0] != -1; j++)
4415 if (HAS_PROPERTY(copy_properties[j][0], i))
4416 for (k = 1; k <= 4; k++)
4417 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4419 /* set static element properties that are not listed in array definitions */
4420 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4421 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4423 clipboard_elements_initialized = TRUE;
4426 void InitElementPropertiesEngine(int engine_version)
4428 static int no_wall_properties[] =
4431 EP_COLLECTIBLE_ONLY,
4433 EP_DONT_COLLIDE_WITH,
4436 EP_CAN_SMASH_PLAYER,
4437 EP_CAN_SMASH_ENEMIES,
4438 EP_CAN_SMASH_EVERYTHING,
4443 EP_FOOD_DARK_YAMYAM,
4459 /* important: after initialization in InitElementPropertiesStatic(), the
4460 elements are not again initialized to a default value; therefore all
4461 changes have to make sure that they leave the element with a defined
4462 property (which means that conditional property changes must be set to
4463 a reliable default value before) */
4465 /* resolve group elements */
4466 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4467 ResolveGroupElement(EL_GROUP_START + i);
4469 /* set all special, combined or engine dependent element properties */
4470 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4472 /* do not change (already initialized) clipboard elements here */
4473 if (IS_CLIPBOARD_ELEMENT(i))
4476 /* ---------- INACTIVE ------------------------------------------------- */
4477 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4478 i <= EL_CHAR_END) ||
4479 (i >= EL_STEEL_CHAR_START &&
4480 i <= EL_STEEL_CHAR_END)));
4482 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4483 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4484 IS_WALKABLE_INSIDE(i) ||
4485 IS_WALKABLE_UNDER(i)));
4487 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4488 IS_PASSABLE_INSIDE(i) ||
4489 IS_PASSABLE_UNDER(i)));
4491 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4492 IS_PASSABLE_OVER(i)));
4494 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4495 IS_PASSABLE_INSIDE(i)));
4497 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4498 IS_PASSABLE_UNDER(i)));
4500 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4503 /* ---------- COLLECTIBLE ---------------------------------------------- */
4504 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4508 /* ---------- SNAPPABLE ------------------------------------------------ */
4509 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4510 IS_COLLECTIBLE(i) ||
4514 /* ---------- WALL ----------------------------------------------------- */
4515 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4517 for (j = 0; no_wall_properties[j] != -1; j++)
4518 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4519 i >= EL_FIRST_RUNTIME_UNREAL)
4520 SET_PROPERTY(i, EP_WALL, FALSE);
4522 if (IS_HISTORIC_WALL(i))
4523 SET_PROPERTY(i, EP_WALL, TRUE);
4525 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4526 if (engine_version < VERSION_IDENT(2,2,0,0))
4527 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4529 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4531 !IS_COLLECTIBLE(i)));
4533 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4534 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4535 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4537 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4538 IS_INDESTRUCTIBLE(i)));
4540 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4542 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4543 else if (engine_version < VERSION_IDENT(2,2,0,0))
4544 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4546 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4550 if (IS_CUSTOM_ELEMENT(i))
4552 /* these are additional properties which are initially false when set */
4554 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4556 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4557 if (DONT_COLLIDE_WITH(i))
4558 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4560 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4561 if (CAN_SMASH_EVERYTHING(i))
4562 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4563 if (CAN_SMASH_ENEMIES(i))
4564 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4567 /* ---------- CAN_SMASH ------------------------------------------------ */
4568 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4569 CAN_SMASH_ENEMIES(i) ||
4570 CAN_SMASH_EVERYTHING(i)));
4572 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4573 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4574 EXPLODES_BY_FIRE(i)));
4576 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4577 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4578 EXPLODES_SMASHED(i)));
4580 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4581 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4582 EXPLODES_IMPACT(i)));
4584 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4585 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4587 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4588 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4589 i == EL_BLACK_ORB));
4591 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4592 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4594 IS_CUSTOM_ELEMENT(i)));
4596 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4597 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4598 i == EL_SP_ELECTRON));
4600 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4601 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4602 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4603 getMoveIntoAcidProperty(&level, i));
4605 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4606 if (MAYBE_DONT_COLLIDE_WITH(i))
4607 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4608 getDontCollideWithProperty(&level, i));
4610 /* ---------- SP_PORT -------------------------------------------------- */
4611 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4612 IS_PASSABLE_INSIDE(i)));
4614 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4615 for (j = 0; j < level.num_android_clone_elements; j++)
4616 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4618 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4620 /* ---------- CAN_CHANGE ----------------------------------------------- */
4621 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4622 for (j = 0; j < element_info[i].num_change_pages; j++)
4623 if (element_info[i].change_page[j].can_change)
4624 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4626 /* ---------- HAS_ACTION ----------------------------------------------- */
4627 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4628 for (j = 0; j < element_info[i].num_change_pages; j++)
4629 if (element_info[i].change_page[j].has_action)
4630 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4632 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4633 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4636 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4637 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4638 element_info[i].crumbled[ACTION_DEFAULT] !=
4639 element_info[i].graphic[ACTION_DEFAULT]);
4641 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4642 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4643 IS_EDITOR_CASCADE_INACTIVE(i)));
4646 /* dynamically adjust element properties according to game engine version */
4648 static int ep_em_slippery_wall[] =
4653 EL_EXPANDABLE_WALL_HORIZONTAL,
4654 EL_EXPANDABLE_WALL_VERTICAL,
4655 EL_EXPANDABLE_WALL_ANY,
4656 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4657 EL_EXPANDABLE_STEELWALL_VERTICAL,
4658 EL_EXPANDABLE_STEELWALL_ANY,
4659 EL_EXPANDABLE_STEELWALL_GROWING,
4663 static int ep_em_explodes_by_fire[] =
4666 EL_EM_DYNAMITE_ACTIVE,
4671 /* special EM style gems behaviour */
4672 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4673 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4674 level.em_slippery_gems);
4676 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4677 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4678 (level.em_slippery_gems &&
4679 engine_version > VERSION_IDENT(2,0,1,0)));
4681 /* special EM style explosion behaviour regarding chain reactions */
4682 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4683 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4684 level.em_explodes_by_fire);
4687 /* this is needed because some graphics depend on element properties */
4688 if (game_status == GAME_MODE_PLAYING)
4689 InitElementGraphicInfo();
4692 void InitElementPropertiesGfxElement()
4696 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4698 struct ElementInfo *ei = &element_info[i];
4700 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4704 static void InitGlobal()
4709 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4711 /* check if element_name_info entry defined for each element in "main.h" */
4712 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4713 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4715 element_info[i].token_name = element_name_info[i].token_name;
4716 element_info[i].class_name = element_name_info[i].class_name;
4717 element_info[i].editor_description= element_name_info[i].editor_description;
4720 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4722 /* check if global_anim_name_info defined for each entry in "main.h" */
4723 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4724 global_anim_name_info[i].token_name == NULL)
4725 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4727 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4730 /* create hash from image config list */
4731 image_config_hash = newSetupFileHash();
4732 for (i = 0; image_config[i].token != NULL; i++)
4733 setHashEntry(image_config_hash,
4734 image_config[i].token,
4735 image_config[i].value);
4737 /* create hash from element token list */
4738 element_token_hash = newSetupFileHash();
4739 for (i = 0; element_name_info[i].token_name != NULL; i++)
4740 setHashEntry(element_token_hash,
4741 element_name_info[i].token_name,
4744 /* create hash from graphic token list */
4745 graphic_token_hash = newSetupFileHash();
4746 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4747 if (strSuffix(image_config[i].value, ".png") ||
4748 strSuffix(image_config[i].value, ".pcx") ||
4749 strSuffix(image_config[i].value, ".wav") ||
4750 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4751 setHashEntry(graphic_token_hash,
4752 image_config[i].token,
4753 int2str(graphic++, 0));
4755 /* create hash from font token list */
4756 font_token_hash = newSetupFileHash();
4757 for (i = 0; font_info[i].token_name != NULL; i++)
4758 setHashEntry(font_token_hash,
4759 font_info[i].token_name,
4762 /* set default filenames for all cloned graphics in static configuration */
4763 for (i = 0; image_config[i].token != NULL; i++)
4765 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4767 char *token = image_config[i].token;
4768 char *token_clone_from = getStringCat2(token, ".clone_from");
4769 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4771 if (token_cloned != NULL)
4773 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4775 if (value_cloned != NULL)
4777 /* set default filename in static configuration */
4778 image_config[i].value = value_cloned;
4780 /* set default filename in image config hash */
4781 setHashEntry(image_config_hash, token, value_cloned);
4785 free(token_clone_from);
4789 /* always start with reliable default values (all elements) */
4790 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4791 ActiveElement[i] = i;
4793 /* now add all entries that have an active state (active elements) */
4794 for (i = 0; element_with_active_state[i].element != -1; i++)
4796 int element = element_with_active_state[i].element;
4797 int element_active = element_with_active_state[i].element_active;
4799 ActiveElement[element] = element_active;
4802 /* always start with reliable default values (all buttons) */
4803 for (i = 0; i < NUM_IMAGE_FILES; i++)
4804 ActiveButton[i] = i;
4806 /* now add all entries that have an active state (active buttons) */
4807 for (i = 0; button_with_active_state[i].button != -1; i++)
4809 int button = button_with_active_state[i].button;
4810 int button_active = button_with_active_state[i].button_active;
4812 ActiveButton[button] = button_active;
4815 /* always start with reliable default values (all fonts) */
4816 for (i = 0; i < NUM_FONTS; i++)
4819 /* now add all entries that have an active state (active fonts) */
4820 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4822 int font = font_with_active_state[i].font_nr;
4823 int font_active = font_with_active_state[i].font_nr_active;
4825 ActiveFont[font] = font_active;
4828 global.autoplay_leveldir = NULL;
4829 global.convert_leveldir = NULL;
4830 global.create_images_dir = NULL;
4832 global.frames_per_second = 0;
4833 global.show_frames_per_second = FALSE;
4835 global.border_status = GAME_MODE_LOADING;
4836 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4838 global.use_envelope_request = FALSE;
4841 void Execute_Command(char *command)
4845 if (strEqual(command, "print graphicsinfo.conf"))
4847 Print("# You can configure additional/alternative image files here.\n");
4848 Print("# (The entries below are default and therefore commented out.)\n");
4850 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4852 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4855 for (i = 0; image_config[i].token != NULL; i++)
4856 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4857 image_config[i].value));
4861 else if (strEqual(command, "print soundsinfo.conf"))
4863 Print("# You can configure additional/alternative sound files here.\n");
4864 Print("# (The entries below are default and therefore commented out.)\n");
4866 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4868 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4871 for (i = 0; sound_config[i].token != NULL; i++)
4872 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4873 sound_config[i].value));
4877 else if (strEqual(command, "print musicinfo.conf"))
4879 Print("# You can configure additional/alternative music files here.\n");
4880 Print("# (The entries below are default and therefore commented out.)\n");
4882 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4884 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4887 for (i = 0; music_config[i].token != NULL; i++)
4888 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4889 music_config[i].value));
4893 else if (strEqual(command, "print editorsetup.conf"))
4895 Print("# You can configure your personal editor element list here.\n");
4896 Print("# (The entries below are default and therefore commented out.)\n");
4899 /* this is needed to be able to check element list for cascade elements */
4900 InitElementPropertiesStatic();
4901 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4903 PrintEditorElementList();
4907 else if (strEqual(command, "print helpanim.conf"))
4909 Print("# You can configure different element help animations here.\n");
4910 Print("# (The entries below are default and therefore commented out.)\n");
4913 for (i = 0; helpanim_config[i].token != NULL; i++)
4915 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4916 helpanim_config[i].value));
4918 if (strEqual(helpanim_config[i].token, "end"))
4924 else if (strEqual(command, "print helptext.conf"))
4926 Print("# You can configure different element help text here.\n");
4927 Print("# (The entries below are default and therefore commented out.)\n");
4930 for (i = 0; helptext_config[i].token != NULL; i++)
4931 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4932 helptext_config[i].value));
4936 else if (strPrefix(command, "dump level "))
4938 char *filename = &command[11];
4940 if (!fileExists(filename))
4941 Error(ERR_EXIT, "cannot open file '%s'", filename);
4943 LoadLevelFromFilename(&level, filename);
4948 else if (strPrefix(command, "dump tape "))
4950 char *filename = &command[10];
4952 if (!fileExists(filename))
4953 Error(ERR_EXIT, "cannot open file '%s'", filename);
4955 LoadTapeFromFilename(filename);
4960 else if (strPrefix(command, "autotest ") ||
4961 strPrefix(command, "autoplay ") ||
4962 strPrefix(command, "autoffwd ") ||
4963 strPrefix(command, "autowarp "))
4965 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4967 global.autoplay_mode =
4968 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
4969 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
4970 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
4971 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
4972 AUTOPLAY_MODE_NONE);
4974 while (*str_ptr != '\0') /* continue parsing string */
4976 /* cut leading whitespace from string, replace it by string terminator */
4977 while (*str_ptr == ' ' || *str_ptr == '\t')
4980 if (*str_ptr == '\0') /* end of string reached */
4983 if (global.autoplay_leveldir == NULL) /* read level set string */
4985 global.autoplay_leveldir = str_ptr;
4986 global.autoplay_all = TRUE; /* default: play all tapes */
4988 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4989 global.autoplay_level[i] = FALSE;
4991 else /* read level number string */
4993 int level_nr = atoi(str_ptr); /* get level_nr value */
4995 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4996 global.autoplay_level[level_nr] = TRUE;
4998 global.autoplay_all = FALSE;
5001 /* advance string pointer to the next whitespace (or end of string) */
5002 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5006 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5007 program.headless = TRUE;
5009 else if (strPrefix(command, "convert "))
5011 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5012 char *str_ptr = strchr(str_copy, ' ');
5014 global.convert_leveldir = str_copy;
5015 global.convert_level_nr = -1;
5017 if (str_ptr != NULL) /* level number follows */
5019 *str_ptr++ = '\0'; /* terminate leveldir string */
5020 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5023 program.headless = TRUE;
5025 else if (strPrefix(command, "create images "))
5027 global.create_images_dir = getStringCopy(&command[14]);
5029 if (access(global.create_images_dir, W_OK) != 0)
5030 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5031 global.create_images_dir);
5033 else if (strPrefix(command, "create CE image "))
5035 CreateCustomElementImages(&command[16]);
5041 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5045 static void InitSetup()
5047 LoadSetup(); /* global setup info */
5048 LoadSetup_AutoSetup(); /* global auto setup info */
5050 /* set some options from setup file */
5052 if (setup.options.verbose)
5053 options.verbose = TRUE;
5055 if (setup.debug.show_frames_per_second)
5056 global.show_frames_per_second = TRUE;
5059 static void InitGameInfo()
5061 game.restart_level = FALSE;
5064 static void InitPlayerInfo()
5068 /* choose default local player */
5069 local_player = &stored_player[0];
5071 for (i = 0; i < MAX_PLAYERS; i++)
5072 stored_player[i].connected = FALSE;
5074 local_player->connected = TRUE;
5077 static void InitArtworkInfo()
5082 static char *get_string_in_brackets(char *string)
5084 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5086 sprintf(string_in_brackets, "[%s]", string);
5088 return string_in_brackets;
5091 static char *get_level_id_suffix(int id_nr)
5093 char *id_suffix = checked_malloc(1 + 3 + 1);
5095 if (id_nr < 0 || id_nr > 999)
5098 sprintf(id_suffix, ".%03d", id_nr);
5103 static void InitArtworkConfig()
5105 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5107 NUM_GLOBAL_ANIM_TOKENS + 1];
5108 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5109 NUM_GLOBAL_ANIM_TOKENS + 1];
5110 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5111 NUM_GLOBAL_ANIM_TOKENS + 1];
5112 static char *action_id_suffix[NUM_ACTIONS + 1];
5113 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5114 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5115 static char *level_id_suffix[MAX_LEVELS + 1];
5116 static char *dummy[1] = { NULL };
5117 static char *ignore_generic_tokens[] =
5123 static char **ignore_image_tokens;
5124 static char **ignore_sound_tokens;
5125 static char **ignore_music_tokens;
5126 int num_ignore_generic_tokens;
5127 int num_ignore_image_tokens;
5128 int num_ignore_sound_tokens;
5129 int num_ignore_music_tokens;
5132 /* dynamically determine list of generic tokens to be ignored */
5133 num_ignore_generic_tokens = 0;
5134 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5135 num_ignore_generic_tokens++;
5137 /* dynamically determine list of image tokens to be ignored */
5138 num_ignore_image_tokens = num_ignore_generic_tokens;
5139 for (i = 0; image_config_vars[i].token != NULL; i++)
5140 num_ignore_image_tokens++;
5141 ignore_image_tokens =
5142 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5143 for (i = 0; i < num_ignore_generic_tokens; i++)
5144 ignore_image_tokens[i] = ignore_generic_tokens[i];
5145 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5146 ignore_image_tokens[num_ignore_generic_tokens + i] =
5147 image_config_vars[i].token;
5148 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5150 /* dynamically determine list of sound tokens to be ignored */
5151 num_ignore_sound_tokens = num_ignore_generic_tokens;
5152 ignore_sound_tokens =
5153 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5154 for (i = 0; i < num_ignore_generic_tokens; i++)
5155 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5156 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5158 /* dynamically determine list of music tokens to be ignored */
5159 num_ignore_music_tokens = num_ignore_generic_tokens;
5160 ignore_music_tokens =
5161 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5162 for (i = 0; i < num_ignore_generic_tokens; i++)
5163 ignore_music_tokens[i] = ignore_generic_tokens[i];
5164 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5166 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5167 image_id_prefix[i] = element_info[i].token_name;
5168 for (i = 0; i < NUM_FONTS; i++)
5169 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5170 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5171 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5172 global_anim_info[i].token_name;
5173 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5175 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5176 sound_id_prefix[i] = element_info[i].token_name;
5177 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5178 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5179 get_string_in_brackets(element_info[i].class_name);
5180 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5181 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5182 global_anim_info[i].token_name;
5183 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5185 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5186 music_id_prefix[i] = music_prefix_info[i].prefix;
5187 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5188 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5189 global_anim_info[i].token_name;
5190 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5192 for (i = 0; i < NUM_ACTIONS; i++)
5193 action_id_suffix[i] = element_action_info[i].suffix;
5194 action_id_suffix[NUM_ACTIONS] = NULL;
5196 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5197 direction_id_suffix[i] = element_direction_info[i].suffix;
5198 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5200 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5201 special_id_suffix[i] = special_suffix_info[i].suffix;
5202 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5204 for (i = 0; i < MAX_LEVELS; i++)
5205 level_id_suffix[i] = get_level_id_suffix(i);
5206 level_id_suffix[MAX_LEVELS] = NULL;
5208 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5209 image_id_prefix, action_id_suffix, direction_id_suffix,
5210 special_id_suffix, ignore_image_tokens);
5211 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5212 sound_id_prefix, action_id_suffix, dummy,
5213 special_id_suffix, ignore_sound_tokens);
5214 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5215 music_id_prefix, action_id_suffix, special_id_suffix,
5216 level_id_suffix, ignore_music_tokens);
5219 static void InitMixer()
5226 void InitGfxBuffers()
5228 static int win_xsize_last = -1;
5229 static int win_ysize_last = -1;
5231 /* create additional image buffers for double-buffering and cross-fading */
5233 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5235 /* used to temporarily store the backbuffer -- only re-create if changed */
5236 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5237 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5239 win_xsize_last = WIN_XSIZE;
5240 win_ysize_last = WIN_YSIZE;
5243 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5244 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5245 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5246 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5248 /* initialize screen properties */
5249 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5250 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5252 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5253 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5254 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5255 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5256 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5257 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5259 /* required if door size definitions have changed */
5260 InitGraphicCompatibilityInfo_Doors();
5262 InitGfxBuffers_EM();
5263 InitGfxBuffers_SP();
5268 struct GraphicInfo *graphic_info_last = graphic_info;
5269 char *filename_font_initial = NULL;
5270 char *filename_anim_initial = NULL;
5271 Bitmap *bitmap_font_initial = NULL;
5275 /* determine settings for initial font (for displaying startup messages) */
5276 for (i = 0; image_config[i].token != NULL; i++)
5278 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5280 char font_token[128];
5283 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5284 len_font_token = strlen(font_token);
5286 if (strEqual(image_config[i].token, font_token))
5287 filename_font_initial = image_config[i].value;
5288 else if (strlen(image_config[i].token) > len_font_token &&
5289 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5291 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5292 font_initial[j].src_x = atoi(image_config[i].value);
5293 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5294 font_initial[j].src_y = atoi(image_config[i].value);
5295 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5296 font_initial[j].width = atoi(image_config[i].value);
5297 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5298 font_initial[j].height = atoi(image_config[i].value);
5303 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5305 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5306 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5309 if (filename_font_initial == NULL) /* should not happen */
5310 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5313 InitGfxCustomArtworkInfo();
5314 InitGfxOtherSettings();
5316 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5318 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5319 font_initial[j].bitmap = bitmap_font_initial;
5321 InitFontGraphicInfo();
5323 font_height = getFontHeight(FC_RED);
5325 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5326 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5327 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5330 DrawInitText("Loading graphics", 120, FC_GREEN);
5332 /* initialize settings for busy animation with default values */
5333 int parameter[NUM_GFX_ARGS];
5334 for (i = 0; i < NUM_GFX_ARGS; i++)
5335 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5336 image_config_suffix[i].token,
5337 image_config_suffix[i].type);
5339 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5340 int len_anim_token = strlen(anim_token);
5342 /* read settings for busy animation from default custom artwork config */
5343 char *gfx_config_filename = getPath3(options.graphics_directory,
5345 GRAPHICSINFO_FILENAME);
5347 if (fileExists(gfx_config_filename))
5349 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5351 if (setup_file_hash)
5353 char *filename = getHashEntry(setup_file_hash, anim_token);
5357 filename_anim_initial = getStringCopy(filename);
5359 for (j = 0; image_config_suffix[j].token != NULL; j++)
5361 int type = image_config_suffix[j].type;
5362 char *suffix = image_config_suffix[j].token;
5363 char *token = getStringCat2(anim_token, suffix);
5364 char *value = getHashEntry(setup_file_hash, token);
5366 checked_free(token);
5369 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5373 freeSetupFileHash(setup_file_hash);
5377 if (filename_anim_initial == NULL)
5379 /* read settings for busy animation from static default artwork config */
5380 for (i = 0; image_config[i].token != NULL; i++)
5382 if (strEqual(image_config[i].token, anim_token))
5383 filename_anim_initial = getStringCopy(image_config[i].value);
5384 else if (strlen(image_config[i].token) > len_anim_token &&
5385 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5387 for (j = 0; image_config_suffix[j].token != NULL; j++)
5389 if (strEqual(&image_config[i].token[len_anim_token],
5390 image_config_suffix[j].token))
5392 get_graphic_parameter_value(image_config[i].value,
5393 image_config_suffix[j].token,
5394 image_config_suffix[j].type);
5400 if (filename_anim_initial == NULL) /* should not happen */
5401 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5403 anim_initial.bitmaps =
5404 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5406 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5407 LoadCustomImage(filename_anim_initial);
5409 checked_free(filename_anim_initial);
5411 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5413 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5415 graphic_info = graphic_info_last;
5417 init.busy.width = anim_initial.width;
5418 init.busy.height = anim_initial.height;
5420 InitMenuDesignSettings_Static();
5422 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5423 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5424 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5426 gfx.fade_border_source_status = global.border_status;
5427 gfx.fade_border_target_status = global.border_status;
5428 gfx.masked_border_bitmap_ptr = backbuffer;
5430 /* use copy of busy animation to prevent change while reloading artwork */
5434 void InitGfxBackground()
5436 fieldbuffer = bitmap_db_field;
5437 SetDrawtoField(DRAW_TO_BACKBUFFER);
5439 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5441 redraw_mask = REDRAW_ALL;
5444 static void InitLevelInfo()
5446 LoadLevelInfo(); /* global level info */
5447 LoadLevelSetup_LastSeries(); /* last played series info */
5448 LoadLevelSetup_SeriesInfo(); /* last played level info */
5450 if (global.autoplay_leveldir &&
5451 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5453 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5454 global.autoplay_leveldir);
5455 if (leveldir_current == NULL)
5456 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5460 static void InitLevelArtworkInfo()
5462 LoadLevelArtworkInfo();
5465 static void InitImages()
5467 print_timestamp_init("InitImages");
5470 printf("::: leveldir_current->identifier == '%s'\n",
5471 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5472 printf("::: leveldir_current->graphics_path == '%s'\n",
5473 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5474 printf("::: leveldir_current->graphics_set == '%s'\n",
5475 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5476 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5477 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5480 setLevelArtworkDir(artwork.gfx_first);
5483 printf("::: leveldir_current->identifier == '%s'\n",
5484 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5485 printf("::: leveldir_current->graphics_path == '%s'\n",
5486 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5487 printf("::: leveldir_current->graphics_set == '%s'\n",
5488 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5489 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5490 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5494 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5495 leveldir_current->identifier,
5496 artwork.gfx_current_identifier,
5497 artwork.gfx_current->identifier,
5498 leveldir_current->graphics_set,
5499 leveldir_current->graphics_path);
5502 UPDATE_BUSY_STATE();
5504 ReloadCustomImages();
5505 print_timestamp_time("ReloadCustomImages");
5507 UPDATE_BUSY_STATE();
5509 LoadCustomElementDescriptions();
5510 print_timestamp_time("LoadCustomElementDescriptions");
5512 UPDATE_BUSY_STATE();
5514 LoadMenuDesignSettings();
5515 print_timestamp_time("LoadMenuDesignSettings");
5517 UPDATE_BUSY_STATE();
5519 ReinitializeGraphics();
5520 print_timestamp_time("ReinitializeGraphics");
5522 LoadMenuDesignSettings_AfterGraphics();
5523 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5525 UPDATE_BUSY_STATE();
5527 print_timestamp_done("InitImages");
5530 static void InitSound(char *identifier)
5532 print_timestamp_init("InitSound");
5534 if (identifier == NULL)
5535 identifier = artwork.snd_current->identifier;
5537 /* set artwork path to send it to the sound server process */
5538 setLevelArtworkDir(artwork.snd_first);
5540 InitReloadCustomSounds(identifier);
5541 print_timestamp_time("InitReloadCustomSounds");
5543 ReinitializeSounds();
5544 print_timestamp_time("ReinitializeSounds");
5546 print_timestamp_done("InitSound");
5549 static void InitMusic(char *identifier)
5551 print_timestamp_init("InitMusic");
5553 if (identifier == NULL)
5554 identifier = artwork.mus_current->identifier;
5556 /* set artwork path to send it to the sound server process */
5557 setLevelArtworkDir(artwork.mus_first);
5559 InitReloadCustomMusic(identifier);
5560 print_timestamp_time("InitReloadCustomMusic");
5562 ReinitializeMusic();
5563 print_timestamp_time("ReinitializeMusic");
5565 print_timestamp_done("InitMusic");
5568 static void InitArtworkDone()
5570 if (program.headless)
5573 InitGlobalAnimations();
5576 void InitNetworkServer()
5578 #if defined(NETWORK_AVALIABLE)
5582 if (!options.network)
5585 #if defined(NETWORK_AVALIABLE)
5586 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5588 if (!ConnectToServer(options.server_host, options.server_port))
5589 Error(ERR_EXIT, "cannot connect to network game server");
5591 SendToServer_PlayerName(setup.player_name);
5592 SendToServer_ProtocolVersion();
5595 SendToServer_NrWanted(nr_wanted);
5599 static boolean CheckArtworkConfigForCustomElements(char *filename)
5601 SetupFileHash *setup_file_hash;
5602 boolean redefined_ce_found = FALSE;
5604 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5606 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5608 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5610 char *token = HASH_ITERATION_TOKEN(itr);
5612 if (strPrefix(token, "custom_"))
5614 redefined_ce_found = TRUE;
5619 END_HASH_ITERATION(setup_file_hash, itr)
5621 freeSetupFileHash(setup_file_hash);
5624 return redefined_ce_found;
5627 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5629 char *filename_base, *filename_local;
5630 boolean redefined_ce_found = FALSE;
5632 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5635 printf("::: leveldir_current->identifier == '%s'\n",
5636 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5637 printf("::: leveldir_current->graphics_path == '%s'\n",
5638 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5639 printf("::: leveldir_current->graphics_set == '%s'\n",
5640 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5641 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5642 leveldir_current == NULL ? "[NULL]" :
5643 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5646 /* first look for special artwork configured in level series config */
5647 filename_base = getCustomArtworkLevelConfigFilename(type);
5650 printf("::: filename_base == '%s'\n", filename_base);
5653 if (fileExists(filename_base))
5654 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5656 filename_local = getCustomArtworkConfigFilename(type);
5659 printf("::: filename_local == '%s'\n", filename_local);
5662 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5663 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5666 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5669 return redefined_ce_found;
5672 static void InitOverrideArtwork()
5674 boolean redefined_ce_found = FALSE;
5676 /* to check if this level set redefines any CEs, do not use overriding */
5677 gfx.override_level_graphics = FALSE;
5678 gfx.override_level_sounds = FALSE;
5679 gfx.override_level_music = FALSE;
5681 /* now check if this level set has definitions for custom elements */
5682 if (setup.override_level_graphics == AUTO ||
5683 setup.override_level_sounds == AUTO ||
5684 setup.override_level_music == AUTO)
5685 redefined_ce_found =
5686 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5687 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5688 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5691 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5694 if (redefined_ce_found)
5696 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5697 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5698 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5699 gfx.override_level_music = (setup.override_level_music == TRUE);
5703 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5704 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5705 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5706 gfx.override_level_music = (setup.override_level_music != FALSE);
5710 printf("::: => %d, %d, %d\n",
5711 gfx.override_level_graphics,
5712 gfx.override_level_sounds,
5713 gfx.override_level_music);
5717 static char *getNewArtworkIdentifier(int type)
5719 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5720 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5721 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5722 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5723 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5724 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5725 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5726 char *leveldir_identifier = leveldir_current->identifier;
5727 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5728 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5729 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5730 char *artwork_current_identifier;
5731 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5733 /* leveldir_current may be invalid (level group, parent link) */
5734 if (!validLevelSeries(leveldir_current))
5737 /* 1st step: determine artwork set to be activated in descending order:
5738 --------------------------------------------------------------------
5739 1. setup artwork (when configured to override everything else)
5740 2. artwork set configured in "levelinfo.conf" of current level set
5741 (artwork in level directory will have priority when loading later)
5742 3. artwork in level directory (stored in artwork sub-directory)
5743 4. setup artwork (currently configured in setup menu) */
5745 if (setup_override_artwork)
5746 artwork_current_identifier = setup_artwork_set;
5747 else if (leveldir_artwork_set != NULL)
5748 artwork_current_identifier = leveldir_artwork_set;
5749 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5750 artwork_current_identifier = leveldir_identifier;
5752 artwork_current_identifier = setup_artwork_set;
5755 /* 2nd step: check if it is really needed to reload artwork set
5756 ------------------------------------------------------------ */
5758 /* ---------- reload if level set and also artwork set has changed ------- */
5759 if (leveldir_current_identifier[type] != leveldir_identifier &&
5760 (last_has_level_artwork_set[type] || has_level_artwork_set))
5761 artwork_new_identifier = artwork_current_identifier;
5763 leveldir_current_identifier[type] = leveldir_identifier;
5764 last_has_level_artwork_set[type] = has_level_artwork_set;
5766 /* ---------- reload if "override artwork" setting has changed ----------- */
5767 if (last_override_level_artwork[type] != setup_override_artwork)
5768 artwork_new_identifier = artwork_current_identifier;
5770 last_override_level_artwork[type] = setup_override_artwork;
5772 /* ---------- reload if current artwork identifier has changed ----------- */
5773 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5774 artwork_current_identifier))
5775 artwork_new_identifier = artwork_current_identifier;
5777 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5779 /* ---------- do not reload directly after starting ---------------------- */
5780 if (!initialized[type])
5781 artwork_new_identifier = NULL;
5783 initialized[type] = TRUE;
5785 return artwork_new_identifier;
5788 void ReloadCustomArtwork(int force_reload)
5790 int last_game_status = game_status; /* save current game status */
5791 char *gfx_new_identifier;
5792 char *snd_new_identifier;
5793 char *mus_new_identifier;
5794 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5795 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5796 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5797 boolean reload_needed;
5799 InitOverrideArtwork();
5801 force_reload_gfx |= AdjustGraphicsForEMC();
5803 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5804 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5805 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5807 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5808 snd_new_identifier != NULL || force_reload_snd ||
5809 mus_new_identifier != NULL || force_reload_mus);
5814 print_timestamp_init("ReloadCustomArtwork");
5816 SetGameStatus(GAME_MODE_LOADING);
5818 FadeOut(REDRAW_ALL);
5820 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5821 print_timestamp_time("ClearRectangle");
5825 if (gfx_new_identifier != NULL || force_reload_gfx)
5828 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5829 artwork.gfx_current_identifier,
5831 artwork.gfx_current->identifier,
5832 leveldir_current->graphics_set);
5836 print_timestamp_time("InitImages");
5839 if (snd_new_identifier != NULL || force_reload_snd)
5841 InitSound(snd_new_identifier);
5842 print_timestamp_time("InitSound");
5845 if (mus_new_identifier != NULL || force_reload_mus)
5847 InitMusic(mus_new_identifier);
5848 print_timestamp_time("InitMusic");
5853 SetGameStatus(last_game_status); /* restore current game status */
5855 init_last = init; /* switch to new busy animation */
5857 FadeOut(REDRAW_ALL);
5859 RedrawGlobalBorder();
5861 /* force redraw of (open or closed) door graphics */
5862 SetDoorState(DOOR_OPEN_ALL);
5863 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5865 FadeSetEnterScreen();
5866 FadeSkipNextFadeOut();
5868 print_timestamp_done("ReloadCustomArtwork");
5870 LimitScreenUpdates(FALSE);
5873 void KeyboardAutoRepeatOffUnlessAutoplay()
5875 if (global.autoplay_leveldir == NULL)
5876 KeyboardAutoRepeatOff();
5879 void DisplayExitMessage(char *format, va_list ap)
5881 // also check for initialized video (headless flag may be temporarily unset)
5882 if (program.headless || !video.initialized)
5885 // check if draw buffer and fonts for exit message are already available
5886 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5889 int font_1 = FC_RED;
5890 int font_2 = FC_YELLOW;
5891 int font_3 = FC_BLUE;
5892 int font_width = getFontWidth(font_2);
5893 int font_height = getFontHeight(font_2);
5896 int sxsize = WIN_XSIZE - 2 * sx;
5897 int sysize = WIN_YSIZE - 2 * sy;
5898 int line_length = sxsize / font_width;
5899 int max_lines = sysize / font_height;
5900 int num_lines_printed;
5904 gfx.sxsize = sxsize;
5905 gfx.sysize = sysize;
5909 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5911 DrawTextSCentered(sy, font_1, "Fatal error:");
5912 sy += 3 * font_height;;
5915 DrawTextBufferVA(sx, sy, format, ap, font_2,
5916 line_length, line_length, max_lines,
5917 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5918 sy += (num_lines_printed + 3) * font_height;
5920 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5921 sy += 3 * font_height;
5924 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5925 line_length, line_length, max_lines,
5926 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5928 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5930 redraw_mask = REDRAW_ALL;
5932 /* force drawing exit message even if screen updates are currently limited */
5933 LimitScreenUpdates(FALSE);
5937 /* deactivate toons on error message screen */
5938 setup.toons = FALSE;
5940 WaitForEventToContinue();
5944 /* ========================================================================= */
5946 /* ========================================================================= */
5950 print_timestamp_init("OpenAll");
5952 SetGameStatus(GAME_MODE_LOADING);
5956 InitGlobal(); /* initialize some global variables */
5958 print_timestamp_time("[init global stuff]");
5962 print_timestamp_time("[init setup/config stuff (1)]");
5966 if (options.execute_command)
5967 Execute_Command(options.execute_command);
5969 if (options.serveronly)
5971 #if defined(PLATFORM_UNIX)
5972 NetworkServer(options.server_port, options.serveronly);
5974 Error(ERR_WARN, "networking only supported in Unix version");
5977 exit(0); /* never reached, server loops forever */
5981 print_timestamp_time("[init setup/config stuff (2)]");
5983 print_timestamp_time("[init setup/config stuff (3)]");
5984 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5985 print_timestamp_time("[init setup/config stuff (4)]");
5986 InitArtworkConfig(); /* needed before forking sound child process */
5987 print_timestamp_time("[init setup/config stuff (5)]");
5989 print_timestamp_time("[init setup/config stuff (6)]");
5991 InitRND(NEW_RANDOMIZE);
5992 InitSimpleRandom(NEW_RANDOMIZE);
5996 print_timestamp_time("[init setup/config stuff]");
5998 InitVideoDefaults();
6000 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6004 print_timestamp_time("[init video stuff]");
6006 InitElementPropertiesStatic();
6007 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6008 InitElementPropertiesGfxElement();
6010 print_timestamp_time("[init element properties stuff]");
6014 print_timestamp_time("InitGfx");
6017 print_timestamp_time("InitLevelInfo");
6019 InitLevelArtworkInfo();
6020 print_timestamp_time("InitLevelArtworkInfo");
6022 InitOverrideArtwork(); /* needs to know current level directory */
6023 print_timestamp_time("InitOverrideArtwork");
6025 InitImages(); /* needs to know current level directory */
6026 print_timestamp_time("InitImages");
6028 InitSound(NULL); /* needs to know current level directory */
6029 print_timestamp_time("InitSound");
6031 InitMusic(NULL); /* needs to know current level directory */
6032 print_timestamp_time("InitMusic");
6036 InitGfxBackground();
6042 if (global.autoplay_leveldir)
6047 else if (global.convert_leveldir)
6052 else if (global.create_images_dir)
6054 CreateLevelSketchImages();
6058 SetGameStatus(GAME_MODE_MAIN);
6060 FadeSetEnterScreen();
6061 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6062 FadeSkipNextFadeOut();
6064 print_timestamp_time("[post-artwork]");
6066 print_timestamp_done("OpenAll");
6070 InitNetworkServer();
6073 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6075 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6076 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6077 #if defined(PLATFORM_ANDROID)
6078 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6079 SDL_AndroidGetInternalStoragePath());
6080 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6081 SDL_AndroidGetExternalStoragePath());
6082 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6083 (SDL_AndroidGetExternalStorageState() &
6084 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6085 SDL_AndroidGetExternalStorageState() &
6086 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6091 void CloseAllAndExit(int exit_value)
6096 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6103 #if defined(TARGET_SDL)
6104 #if defined(TARGET_SDL2)
6106 // set a flag to tell the network server thread to quit and wait for it
6107 // using SDL_WaitThread()
6109 if (network_server) /* terminate network server */
6110 SDL_KillThread(server_thread);
6114 CloseVideoDisplay();
6115 ClosePlatformDependentStuff();
6117 if (exit_value != 0 && !options.execute_command)
6119 /* fall back to default level set (current set may have caused an error) */
6120 SaveLevelSetup_LastSeries_Deactivate();
6122 /* tell user where to find error log file which may contain more details */
6123 // (error notification now directly displayed on screen inside R'n'D
6124 // NotifyUserAboutErrorFile(); /* currently only works for Windows */