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].offset_x =
555 (graphic_info[graphic].offset_x != 0 ?
556 graphic_info[graphic].offset_x :
557 graphic_info[graphic].width);
558 font_bitmap_info[font_bitmap_id].offset_y =
559 (graphic_info[graphic].offset_y != 0 ?
560 graphic_info[graphic].offset_y :
561 graphic_info[graphic].height);
563 font_bitmap_info[font_bitmap_id].draw_xoffset =
564 graphic_info[graphic].draw_xoffset;
565 font_bitmap_info[font_bitmap_id].draw_yoffset =
566 graphic_info[graphic].draw_yoffset;
568 font_bitmap_info[font_bitmap_id].num_chars =
569 graphic_info[graphic].anim_frames;
570 font_bitmap_info[font_bitmap_id].num_chars_per_line =
571 graphic_info[graphic].anim_frames_per_line;
575 InitFontInfo(font_bitmap_info, num_font_bitmaps,
576 getFontBitmapID, getFontFromToken);
579 void InitGlobalAnimGraphicInfo()
581 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
582 int num_property_mappings = getImageListPropertyMappingSize();
585 if (graphic_info == NULL) /* still at startup phase */
588 /* always start with reliable default values (no global animations) */
589 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
590 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
591 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
592 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
594 /* initialize global animation definitions from static configuration */
595 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
597 int j = GLOBAL_ANIM_ID_PART_BASE;
598 int k = GFX_SPECIAL_ARG_DEFAULT;
600 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
603 /* initialize global animation definitions from dynamic configuration */
604 for (i = 0; i < num_property_mappings; i++)
606 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
607 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
608 int special = property_mapping[i].ext3_index;
609 int graphic = property_mapping[i].artwork_index;
611 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
614 /* set animation part to base part, if not specified */
615 if (!IS_GLOBAL_ANIM_PART(part_nr))
616 part_nr = GLOBAL_ANIM_ID_PART_BASE;
618 /* set animation screen to default, if not specified */
619 if (!IS_SPECIAL_GFX_ARG(special))
620 special = GFX_SPECIAL_ARG_DEFAULT;
622 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
624 /* fix default value for ".draw_masked" (for backward compatibility) */
625 struct GraphicInfo *g = &graphic_info[graphic];
626 struct FileInfo *image = getImageListEntryFromImageID(graphic);
627 char **parameter_raw = image->parameter;
628 int p = GFX_ARG_DRAW_MASKED;
629 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
630 image_config_suffix[p].token,
631 image_config_suffix[p].type);
633 /* if ".draw_masked" parameter is undefined, use default value "TRUE" */
634 if (draw_masked == ARG_UNDEFINED_VALUE)
635 g->draw_masked = TRUE;
639 printf("::: InitGlobalAnimGraphicInfo\n");
641 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
642 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
643 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
644 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
645 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
646 printf("::: - anim %d, part %d, mode %d => %d\n",
647 i, j, k, global_anim_info[i].graphic[j][k]);
651 void InitGlobalAnimSoundInfo()
653 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
654 int num_property_mappings = getSoundListPropertyMappingSize();
657 /* always start with reliable default values (no global animation sounds) */
658 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
659 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
660 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
661 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
663 /* initialize global animation sound definitions from dynamic configuration */
664 for (i = 0; i < num_property_mappings; i++)
666 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
667 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
668 int special = property_mapping[i].ext3_index;
669 int sound = property_mapping[i].artwork_index;
671 // sound uses control definition; map it to position of graphic (artwork)
672 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
674 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
677 /* set animation part to base part, if not specified */
678 if (!IS_GLOBAL_ANIM_PART(part_nr))
679 part_nr = GLOBAL_ANIM_ID_PART_BASE;
681 /* set animation screen to default, if not specified */
682 if (!IS_SPECIAL_GFX_ARG(special))
683 special = GFX_SPECIAL_ARG_DEFAULT;
685 global_anim_info[anim_nr].sound[part_nr][special] = sound;
689 printf("::: InitGlobalAnimSoundInfo\n");
691 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
692 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
693 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
694 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
695 printf("::: - anim %d, part %d, mode %d => %d\n",
696 i, j, k, global_anim_info[i].sound[j][k]);
700 void InitGlobalAnimMusicInfo()
702 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
703 int num_property_mappings = getMusicListPropertyMappingSize();
706 /* always start with reliable default values (no global animation music) */
707 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
708 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
709 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
710 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
712 /* initialize global animation music definitions from dynamic configuration */
713 for (i = 0; i < num_property_mappings; i++)
715 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
716 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
717 int special = property_mapping[i].ext2_index;
718 int music = property_mapping[i].artwork_index;
720 // music uses control definition; map it to position of graphic (artwork)
721 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
723 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
726 /* set animation part to base part, if not specified */
727 if (!IS_GLOBAL_ANIM_PART(part_nr))
728 part_nr = GLOBAL_ANIM_ID_PART_BASE;
730 /* set animation screen to default, if not specified */
731 if (!IS_SPECIAL_GFX_ARG(special))
732 special = GFX_SPECIAL_ARG_DEFAULT;
734 global_anim_info[anim_nr].music[part_nr][special] = music;
738 printf("::: InitGlobalAnimMusicInfo\n");
740 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
741 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
742 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
743 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
744 printf("::: - anim %d, part %d, mode %d => %d\n",
745 i, j, k, global_anim_info[i].music[j][k]);
749 void InitElementGraphicInfo()
751 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
752 int num_property_mappings = getImageListPropertyMappingSize();
755 if (graphic_info == NULL) /* still at startup phase */
758 /* set values to -1 to identify later as "uninitialized" values */
759 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
761 for (act = 0; act < NUM_ACTIONS; act++)
763 element_info[i].graphic[act] = -1;
764 element_info[i].crumbled[act] = -1;
766 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
768 element_info[i].direction_graphic[act][dir] = -1;
769 element_info[i].direction_crumbled[act][dir] = -1;
776 /* initialize normal element/graphic mapping from static configuration */
777 for (i = 0; element_to_graphic[i].element > -1; i++)
779 int element = element_to_graphic[i].element;
780 int action = element_to_graphic[i].action;
781 int direction = element_to_graphic[i].direction;
782 boolean crumbled = element_to_graphic[i].crumbled;
783 int graphic = element_to_graphic[i].graphic;
784 int base_graphic = el2baseimg(element);
786 if (graphic_info[graphic].bitmap == NULL)
789 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
792 boolean base_redefined =
793 getImageListEntryFromImageID(base_graphic)->redefined;
794 boolean act_dir_redefined =
795 getImageListEntryFromImageID(graphic)->redefined;
797 /* if the base graphic ("emerald", for example) has been redefined,
798 but not the action graphic ("emerald.falling", for example), do not
799 use an existing (in this case considered obsolete) action graphic
800 anymore, but use the automatically determined default graphic */
801 if (base_redefined && !act_dir_redefined)
806 action = ACTION_DEFAULT;
811 element_info[element].direction_crumbled[action][direction] = graphic;
813 element_info[element].crumbled[action] = graphic;
818 element_info[element].direction_graphic[action][direction] = graphic;
820 element_info[element].graphic[action] = graphic;
824 /* initialize normal element/graphic mapping from dynamic configuration */
825 for (i = 0; i < num_property_mappings; i++)
827 int element = property_mapping[i].base_index;
828 int action = property_mapping[i].ext1_index;
829 int direction = property_mapping[i].ext2_index;
830 int special = property_mapping[i].ext3_index;
831 int graphic = property_mapping[i].artwork_index;
832 boolean crumbled = FALSE;
834 if (special == GFX_SPECIAL_ARG_CRUMBLED)
840 if (graphic_info[graphic].bitmap == NULL)
843 if (element >= MAX_NUM_ELEMENTS || special != -1)
847 action = ACTION_DEFAULT;
852 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
853 element_info[element].direction_crumbled[action][dir] = -1;
856 element_info[element].direction_crumbled[action][direction] = graphic;
858 element_info[element].crumbled[action] = graphic;
863 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
864 element_info[element].direction_graphic[action][dir] = -1;
867 element_info[element].direction_graphic[action][direction] = graphic;
869 element_info[element].graphic[action] = graphic;
873 /* now copy all graphics that are defined to be cloned from other graphics */
874 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
876 int graphic = element_info[i].graphic[ACTION_DEFAULT];
877 int crumbled_like, diggable_like;
882 crumbled_like = graphic_info[graphic].crumbled_like;
883 diggable_like = graphic_info[graphic].diggable_like;
885 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
887 for (act = 0; act < NUM_ACTIONS; act++)
888 element_info[i].crumbled[act] =
889 element_info[crumbled_like].crumbled[act];
890 for (act = 0; act < NUM_ACTIONS; act++)
891 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
892 element_info[i].direction_crumbled[act][dir] =
893 element_info[crumbled_like].direction_crumbled[act][dir];
896 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
898 element_info[i].graphic[ACTION_DIGGING] =
899 element_info[diggable_like].graphic[ACTION_DIGGING];
900 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
901 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
902 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
906 /* set hardcoded definitions for some runtime elements without graphic */
907 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
909 /* set hardcoded definitions for some internal elements without graphic */
910 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
912 if (IS_EDITOR_CASCADE_INACTIVE(i))
913 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
914 else if (IS_EDITOR_CASCADE_ACTIVE(i))
915 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
918 /* now set all undefined/invalid graphics to -1 to set to default after it */
919 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
921 for (act = 0; act < NUM_ACTIONS; act++)
925 graphic = element_info[i].graphic[act];
926 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
927 element_info[i].graphic[act] = -1;
929 graphic = element_info[i].crumbled[act];
930 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
931 element_info[i].crumbled[act] = -1;
933 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
935 graphic = element_info[i].direction_graphic[act][dir];
936 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
937 element_info[i].direction_graphic[act][dir] = -1;
939 graphic = element_info[i].direction_crumbled[act][dir];
940 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
941 element_info[i].direction_crumbled[act][dir] = -1;
948 /* adjust graphics with 2nd tile for movement according to direction
949 (do this before correcting '-1' values to minimize calculations) */
950 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
952 for (act = 0; act < NUM_ACTIONS; act++)
954 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
956 int graphic = element_info[i].direction_graphic[act][dir];
957 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
959 if (act == ACTION_FALLING) /* special case */
960 graphic = element_info[i].graphic[act];
963 graphic_info[graphic].double_movement &&
964 graphic_info[graphic].swap_double_tiles != 0)
966 struct GraphicInfo *g = &graphic_info[graphic];
967 int src_x_front = g->src_x;
968 int src_y_front = g->src_y;
969 int src_x_back = g->src_x + g->offset2_x;
970 int src_y_back = g->src_y + g->offset2_y;
971 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
973 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
974 src_y_front < src_y_back);
975 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
976 boolean swap_movement_tiles_autodetected =
977 (!frames_are_ordered_diagonally &&
978 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
979 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
980 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
981 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
983 /* swap frontside and backside graphic tile coordinates, if needed */
984 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
986 /* get current (wrong) backside tile coordinates */
987 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
989 /* set frontside tile coordinates to backside tile coordinates */
990 g->src_x = src_x_back;
991 g->src_y = src_y_back;
993 /* invert tile offset to point to new backside tile coordinates */
997 /* do not swap front and backside tiles again after correction */
998 g->swap_double_tiles = 0;
1005 UPDATE_BUSY_STATE();
1007 /* now set all '-1' values to element specific default values */
1008 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1010 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1011 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1012 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1013 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1015 if (default_graphic == -1)
1016 default_graphic = IMG_UNKNOWN;
1018 if (default_crumbled == -1)
1019 default_crumbled = default_graphic;
1021 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1023 default_direction_graphic[dir] =
1024 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1025 default_direction_crumbled[dir] =
1026 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1028 if (default_direction_graphic[dir] == -1)
1029 default_direction_graphic[dir] = default_graphic;
1031 if (default_direction_crumbled[dir] == -1)
1032 default_direction_crumbled[dir] = default_direction_graphic[dir];
1035 for (act = 0; act < NUM_ACTIONS; act++)
1037 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1038 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1039 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1040 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1041 act == ACTION_TURNING_FROM_RIGHT ||
1042 act == ACTION_TURNING_FROM_UP ||
1043 act == ACTION_TURNING_FROM_DOWN);
1045 /* generic default action graphic (defined by "[default]" directive) */
1046 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1047 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1048 int default_remove_graphic = IMG_EMPTY;
1050 if (act_remove && default_action_graphic != -1)
1051 default_remove_graphic = default_action_graphic;
1053 /* look for special default action graphic (classic game specific) */
1054 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1055 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1056 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1057 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1058 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1059 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1060 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1061 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1063 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1064 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1065 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1066 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1067 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1068 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1069 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1070 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1072 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1073 /* !!! make this better !!! */
1074 if (i == EL_EMPTY_SPACE)
1076 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1077 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1080 if (default_action_graphic == -1)
1081 default_action_graphic = default_graphic;
1083 if (default_action_crumbled == -1)
1084 default_action_crumbled = default_action_graphic;
1086 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1088 /* use action graphic as the default direction graphic, if undefined */
1089 int default_action_direction_graphic = element_info[i].graphic[act];
1090 int default_action_direction_crumbled = element_info[i].crumbled[act];
1092 /* no graphic for current action -- use default direction graphic */
1093 if (default_action_direction_graphic == -1)
1094 default_action_direction_graphic =
1095 (act_remove ? default_remove_graphic :
1097 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1098 default_action_graphic != default_graphic ?
1099 default_action_graphic :
1100 default_direction_graphic[dir]);
1102 if (element_info[i].direction_graphic[act][dir] == -1)
1103 element_info[i].direction_graphic[act][dir] =
1104 default_action_direction_graphic;
1106 if (default_action_direction_crumbled == -1)
1107 default_action_direction_crumbled =
1108 element_info[i].direction_graphic[act][dir];
1110 if (element_info[i].direction_crumbled[act][dir] == -1)
1111 element_info[i].direction_crumbled[act][dir] =
1112 default_action_direction_crumbled;
1115 /* no graphic for this specific action -- use default action graphic */
1116 if (element_info[i].graphic[act] == -1)
1117 element_info[i].graphic[act] =
1118 (act_remove ? default_remove_graphic :
1119 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1120 default_action_graphic);
1122 if (element_info[i].crumbled[act] == -1)
1123 element_info[i].crumbled[act] = element_info[i].graphic[act];
1127 UPDATE_BUSY_STATE();
1130 void InitElementSpecialGraphicInfo()
1132 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1133 int num_property_mappings = getImageListPropertyMappingSize();
1136 /* always start with reliable default values */
1137 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1138 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1139 element_info[i].special_graphic[j] =
1140 element_info[i].graphic[ACTION_DEFAULT];
1142 /* initialize special element/graphic mapping from static configuration */
1143 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1145 int element = element_to_special_graphic[i].element;
1146 int special = element_to_special_graphic[i].special;
1147 int graphic = element_to_special_graphic[i].graphic;
1148 int base_graphic = el2baseimg(element);
1149 boolean base_redefined =
1150 getImageListEntryFromImageID(base_graphic)->redefined;
1151 boolean special_redefined =
1152 getImageListEntryFromImageID(graphic)->redefined;
1154 /* if the base graphic ("emerald", for example) has been redefined,
1155 but not the special graphic ("emerald.EDITOR", for example), do not
1156 use an existing (in this case considered obsolete) special graphic
1157 anymore, but use the automatically created (down-scaled) graphic */
1158 if (base_redefined && !special_redefined)
1161 element_info[element].special_graphic[special] = graphic;
1164 /* initialize special element/graphic mapping from dynamic configuration */
1165 for (i = 0; i < num_property_mappings; i++)
1167 int element = property_mapping[i].base_index;
1168 int action = property_mapping[i].ext1_index;
1169 int direction = property_mapping[i].ext2_index;
1170 int special = property_mapping[i].ext3_index;
1171 int graphic = property_mapping[i].artwork_index;
1173 /* for action ".active", replace element with active element, if exists */
1174 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1176 element = ELEMENT_ACTIVE(element);
1180 if (element >= MAX_NUM_ELEMENTS)
1183 /* do not change special graphic if action or direction was specified */
1184 if (action != -1 || direction != -1)
1187 if (IS_SPECIAL_GFX_ARG(special))
1188 element_info[element].special_graphic[special] = graphic;
1191 /* now set all undefined/invalid graphics to default */
1192 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1193 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1194 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1195 element_info[i].special_graphic[j] =
1196 element_info[i].graphic[ACTION_DEFAULT];
1199 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1201 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1202 return get_parameter_value(value_raw, suffix, type);
1204 if (strEqual(value_raw, ARG_UNDEFINED))
1205 return ARG_UNDEFINED_VALUE;
1207 if (type == TYPE_ELEMENT)
1209 char *value = getHashEntry(element_token_hash, value_raw);
1213 Error(ERR_INFO_LINE, "-");
1214 Error(ERR_INFO, "warning: error found in config file:");
1215 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1216 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1217 Error(ERR_INFO, "custom graphic rejected for this element/action");
1218 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1219 Error(ERR_INFO_LINE, "-");
1222 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1224 else if (type == TYPE_GRAPHIC)
1226 char *value = getHashEntry(graphic_token_hash, value_raw);
1227 int fallback_graphic = IMG_CHAR_EXCLAM;
1231 Error(ERR_INFO_LINE, "-");
1232 Error(ERR_INFO, "warning: error found in config file:");
1233 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1234 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1235 Error(ERR_INFO, "custom graphic rejected for this element/action");
1236 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1237 Error(ERR_INFO_LINE, "-");
1240 return (value != NULL ? atoi(value) : fallback_graphic);
1246 static int get_scaled_graphic_width(int graphic)
1248 int original_width = getOriginalImageWidthFromImageID(graphic);
1249 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1251 return original_width * scale_up_factor;
1254 static int get_scaled_graphic_height(int graphic)
1256 int original_height = getOriginalImageHeightFromImageID(graphic);
1257 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1259 return original_height * scale_up_factor;
1262 static void set_graphic_parameters_ext(int graphic, int *parameter,
1263 Bitmap **src_bitmaps)
1265 struct GraphicInfo *g = &graphic_info[graphic];
1266 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1267 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1268 int anim_frames_per_line = 1;
1270 /* always start with reliable default values */
1271 g->src_image_width = 0;
1272 g->src_image_height = 0;
1275 g->width = TILEX; /* default for element graphics */
1276 g->height = TILEY; /* default for element graphics */
1277 g->offset_x = 0; /* one or both of these values ... */
1278 g->offset_y = 0; /* ... will be corrected later */
1279 g->offset2_x = 0; /* one or both of these values ... */
1280 g->offset2_y = 0; /* ... will be corrected later */
1281 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1282 g->crumbled_like = -1; /* do not use clone element */
1283 g->diggable_like = -1; /* do not use clone element */
1284 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1285 g->scale_up_factor = 1; /* default: no scaling up */
1286 g->tile_size = TILESIZE; /* default: standard tile size */
1287 g->clone_from = -1; /* do not use clone graphic */
1288 g->init_delay_fixed = 0;
1289 g->init_delay_random = 0;
1290 g->anim_delay_fixed = 0;
1291 g->anim_delay_random = 0;
1292 g->post_delay_fixed = 0;
1293 g->post_delay_random = 0;
1294 g->init_event = ANIM_EVENT_DEFAULT;
1295 g->anim_event = ANIM_EVENT_DEFAULT;
1296 g->draw_masked = FALSE;
1298 g->fade_mode = FADE_MODE_DEFAULT;
1302 g->align = ALIGN_CENTER; /* default for title screens */
1303 g->valign = VALIGN_MIDDLE; /* default for title screens */
1304 g->sort_priority = 0; /* default for title screens */
1306 g->style = STYLE_DEFAULT;
1308 g->bitmaps = src_bitmaps;
1309 g->bitmap = src_bitmap;
1311 /* optional zoom factor for scaling up the image to a larger size */
1312 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1313 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1314 if (g->scale_up_factor < 1)
1315 g->scale_up_factor = 1; /* no scaling */
1317 /* optional tile size for using non-standard image size */
1318 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1320 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1323 // CHECK: should tile sizes less than standard tile size be allowed?
1324 if (g->tile_size < TILESIZE)
1325 g->tile_size = TILESIZE; /* standard tile size */
1328 // when setting tile size, also set width and height accordingly
1329 g->width = g->tile_size;
1330 g->height = g->tile_size;
1333 if (g->use_image_size)
1335 /* set new default bitmap size (with scaling, but without small images) */
1336 g->width = get_scaled_graphic_width(graphic);
1337 g->height = get_scaled_graphic_height(graphic);
1340 /* optional width and height of each animation frame */
1341 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1342 g->width = parameter[GFX_ARG_WIDTH];
1343 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1344 g->height = parameter[GFX_ARG_HEIGHT];
1346 /* optional x and y tile position of animation frame sequence */
1347 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1348 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1349 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1350 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1352 /* optional x and y pixel position of animation frame sequence */
1353 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1354 g->src_x = parameter[GFX_ARG_X];
1355 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1356 g->src_y = parameter[GFX_ARG_Y];
1362 Error(ERR_INFO_LINE, "-");
1363 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1364 g->width, getTokenFromImageID(graphic), TILEX);
1365 Error(ERR_INFO_LINE, "-");
1367 g->width = TILEX; /* will be checked to be inside bitmap later */
1372 Error(ERR_INFO_LINE, "-");
1373 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1374 g->height, getTokenFromImageID(graphic), TILEY);
1375 Error(ERR_INFO_LINE, "-");
1377 g->height = TILEY; /* will be checked to be inside bitmap later */
1383 /* get final bitmap size (with scaling, but without small images) */
1384 int src_image_width = get_scaled_graphic_width(graphic);
1385 int src_image_height = get_scaled_graphic_height(graphic);
1387 if (src_image_width == 0 || src_image_height == 0)
1389 /* only happens when loaded outside artwork system (like "global.busy") */
1390 src_image_width = src_bitmap->width;
1391 src_image_height = src_bitmap->height;
1394 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1396 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1397 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1401 anim_frames_per_row = MAX(1, src_image_width / g->width);
1402 anim_frames_per_col = MAX(1, src_image_height / g->height);
1405 g->src_image_width = src_image_width;
1406 g->src_image_height = src_image_height;
1409 /* correct x or y offset dependent of vertical or horizontal frame order */
1410 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1412 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1413 parameter[GFX_ARG_OFFSET] : g->height);
1414 anim_frames_per_line = anim_frames_per_col;
1416 else /* frames are ordered horizontally */
1418 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1419 parameter[GFX_ARG_OFFSET] : g->width);
1420 anim_frames_per_line = anim_frames_per_row;
1423 /* optionally, the x and y offset of frames can be specified directly */
1424 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1425 g->offset_x = parameter[GFX_ARG_XOFFSET];
1426 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1427 g->offset_y = parameter[GFX_ARG_YOFFSET];
1429 /* optionally, moving animations may have separate start and end graphics */
1430 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1432 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1433 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1435 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1436 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1437 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1438 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1439 else /* frames are ordered horizontally */
1440 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1441 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1443 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1444 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1445 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1446 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1447 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1449 /* optionally, the second movement tile can be specified as start tile */
1450 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1451 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1453 /* automatically determine correct number of frames, if not defined */
1454 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1455 g->anim_frames = parameter[GFX_ARG_FRAMES];
1456 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1457 g->anim_frames = anim_frames_per_row;
1458 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1459 g->anim_frames = anim_frames_per_col;
1463 if (g->anim_frames == 0) /* frames must be at least 1 */
1466 g->anim_frames_per_line =
1467 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1468 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1470 g->anim_delay = parameter[GFX_ARG_DELAY];
1471 if (g->anim_delay == 0) /* delay must be at least 1 */
1474 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1476 /* automatically determine correct start frame, if not defined */
1477 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1478 g->anim_start_frame = 0;
1479 else if (g->anim_mode & ANIM_REVERSE)
1480 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1482 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1484 /* animation synchronized with global frame counter, not move position */
1485 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1487 /* optional element for cloning crumble graphics */
1488 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1489 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1491 /* optional element for cloning digging graphics */
1492 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1493 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1495 /* optional border size for "crumbling" diggable graphics */
1496 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1497 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1499 /* used for global animations and player "boring" and "sleeping" actions */
1500 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1501 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1502 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1503 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1504 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1505 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1506 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1507 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1508 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1509 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1510 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1511 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1513 /* used for global animations */
1514 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1515 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1516 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1517 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1519 /* used for toon animations and global animations */
1520 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1521 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1522 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1523 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1524 g->direction = parameter[GFX_ARG_DIRECTION];
1525 g->position = parameter[GFX_ARG_POSITION];
1526 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1527 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1529 /* this is only used for drawing font characters */
1530 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1531 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1533 /* use a different default value for global animations and toons */
1534 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1535 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1536 g->draw_masked = TRUE;
1538 /* this is used for drawing envelopes, global animations and toons */
1539 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1540 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1542 /* used for toon animations and global animations */
1543 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1544 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1546 /* optional graphic for cloning all graphics settings */
1547 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1548 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1550 /* optional settings for drawing title screens and title messages */
1551 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1552 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1553 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1554 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1555 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1556 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1557 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1558 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1559 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1560 g->align = parameter[GFX_ARG_ALIGN];
1561 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1562 g->valign = parameter[GFX_ARG_VALIGN];
1563 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1564 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1566 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1567 g->class = parameter[GFX_ARG_CLASS];
1568 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1569 g->style = parameter[GFX_ARG_STYLE];
1571 /* this is only used for drawing menu buttons and text */
1572 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1573 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1574 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1575 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1578 static void set_graphic_parameters(int graphic)
1580 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1581 char **parameter_raw = image->parameter;
1582 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1583 int parameter[NUM_GFX_ARGS];
1586 /* if fallback to default artwork is done, also use the default parameters */
1587 if (image->fallback_to_default)
1588 parameter_raw = image->default_parameter;
1590 /* get integer values from string parameters */
1591 for (i = 0; i < NUM_GFX_ARGS; i++)
1592 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1593 image_config_suffix[i].token,
1594 image_config_suffix[i].type);
1596 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1598 UPDATE_BUSY_STATE();
1601 static void set_cloned_graphic_parameters(int graphic)
1603 int fallback_graphic = IMG_CHAR_EXCLAM;
1604 int max_num_images = getImageListSize();
1605 int clone_graphic = graphic_info[graphic].clone_from;
1606 int num_references_followed = 1;
1608 while (graphic_info[clone_graphic].clone_from != -1 &&
1609 num_references_followed < max_num_images)
1611 clone_graphic = graphic_info[clone_graphic].clone_from;
1613 num_references_followed++;
1616 if (num_references_followed >= max_num_images)
1618 Error(ERR_INFO_LINE, "-");
1619 Error(ERR_INFO, "warning: error found in config file:");
1620 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1621 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1622 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1623 Error(ERR_INFO, "custom graphic rejected for this element/action");
1625 if (graphic == fallback_graphic)
1626 Error(ERR_EXIT, "no fallback graphic available");
1628 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1629 Error(ERR_INFO_LINE, "-");
1631 graphic_info[graphic] = graphic_info[fallback_graphic];
1635 graphic_info[graphic] = graphic_info[clone_graphic];
1636 graphic_info[graphic].clone_from = clone_graphic;
1640 static void InitGraphicInfo()
1642 int fallback_graphic = IMG_CHAR_EXCLAM;
1643 int num_images = getImageListSize();
1646 /* use image size as default values for width and height for these images */
1647 static int full_size_graphics[] =
1650 IMG_GLOBAL_BORDER_MAIN,
1651 IMG_GLOBAL_BORDER_SCORES,
1652 IMG_GLOBAL_BORDER_EDITOR,
1653 IMG_GLOBAL_BORDER_PLAYING,
1656 IMG_BACKGROUND_ENVELOPE_1,
1657 IMG_BACKGROUND_ENVELOPE_2,
1658 IMG_BACKGROUND_ENVELOPE_3,
1659 IMG_BACKGROUND_ENVELOPE_4,
1660 IMG_BACKGROUND_REQUEST,
1663 IMG_BACKGROUND_TITLE_INITIAL,
1664 IMG_BACKGROUND_TITLE,
1665 IMG_BACKGROUND_MAIN,
1666 IMG_BACKGROUND_LEVELS,
1667 IMG_BACKGROUND_LEVELNR,
1668 IMG_BACKGROUND_SCORES,
1669 IMG_BACKGROUND_EDITOR,
1670 IMG_BACKGROUND_INFO,
1671 IMG_BACKGROUND_INFO_ELEMENTS,
1672 IMG_BACKGROUND_INFO_MUSIC,
1673 IMG_BACKGROUND_INFO_CREDITS,
1674 IMG_BACKGROUND_INFO_PROGRAM,
1675 IMG_BACKGROUND_INFO_VERSION,
1676 IMG_BACKGROUND_INFO_LEVELSET,
1677 IMG_BACKGROUND_SETUP,
1678 IMG_BACKGROUND_PLAYING,
1679 IMG_BACKGROUND_DOOR,
1680 IMG_BACKGROUND_TAPE,
1681 IMG_BACKGROUND_PANEL,
1682 IMG_BACKGROUND_PALETTE,
1683 IMG_BACKGROUND_TOOLBOX,
1685 IMG_TITLESCREEN_INITIAL_1,
1686 IMG_TITLESCREEN_INITIAL_2,
1687 IMG_TITLESCREEN_INITIAL_3,
1688 IMG_TITLESCREEN_INITIAL_4,
1689 IMG_TITLESCREEN_INITIAL_5,
1696 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1697 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1698 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1699 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1700 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1701 IMG_BACKGROUND_TITLEMESSAGE_1,
1702 IMG_BACKGROUND_TITLEMESSAGE_2,
1703 IMG_BACKGROUND_TITLEMESSAGE_3,
1704 IMG_BACKGROUND_TITLEMESSAGE_4,
1705 IMG_BACKGROUND_TITLEMESSAGE_5,
1710 checked_free(graphic_info);
1712 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1714 /* initialize "use_image_size" flag with default value */
1715 for (i = 0; i < num_images; i++)
1716 graphic_info[i].use_image_size = FALSE;
1718 /* initialize "use_image_size" flag from static configuration above */
1719 for (i = 0; full_size_graphics[i] != -1; i++)
1720 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1722 /* first set all graphic paramaters ... */
1723 for (i = 0; i < num_images; i++)
1724 set_graphic_parameters(i);
1726 /* ... then copy these parameters for cloned graphics */
1727 for (i = 0; i < num_images; i++)
1728 if (graphic_info[i].clone_from != -1)
1729 set_cloned_graphic_parameters(i);
1731 for (i = 0; i < num_images; i++)
1733 Bitmap *src_bitmap = graphic_info[i].bitmap;
1737 int src_bitmap_width, src_bitmap_height;
1739 /* now check if no animation frames are outside of the loaded image */
1741 if (graphic_info[i].bitmap == NULL)
1742 continue; /* skip check for optional images that are undefined */
1744 /* get image size (this can differ from the standard element tile size!) */
1745 width = graphic_info[i].width;
1746 height = graphic_info[i].height;
1748 /* get final bitmap size (with scaling, but without small images) */
1749 src_bitmap_width = graphic_info[i].src_image_width;
1750 src_bitmap_height = graphic_info[i].src_image_height;
1752 /* check if first animation frame is inside specified bitmap */
1754 /* do not use getGraphicSourceXY() here to get position of first frame; */
1755 /* this avoids calculating wrong start position for out-of-bounds frame */
1756 src_x = graphic_info[i].src_x;
1757 src_y = graphic_info[i].src_y;
1759 if (program.headless)
1762 if (src_x < 0 || src_y < 0 ||
1763 src_x + width > src_bitmap_width ||
1764 src_y + height > src_bitmap_height)
1766 Error(ERR_INFO_LINE, "-");
1767 Error(ERR_INFO, "warning: error found in config file:");
1768 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1769 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1770 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1771 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1773 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1774 src_x, src_y, src_bitmap_width, src_bitmap_height);
1775 Error(ERR_INFO, "custom graphic rejected for this element/action");
1777 if (i == fallback_graphic)
1778 Error(ERR_EXIT, "no fallback graphic available");
1780 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1781 Error(ERR_INFO_LINE, "-");
1783 graphic_info[i] = graphic_info[fallback_graphic];
1785 /* if first frame out of bounds, do not check last frame anymore */
1789 /* check if last animation frame is inside specified bitmap */
1791 last_frame = graphic_info[i].anim_frames - 1;
1792 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1794 if (src_x < 0 || src_y < 0 ||
1795 src_x + width > src_bitmap_width ||
1796 src_y + height > src_bitmap_height)
1798 Error(ERR_INFO_LINE, "-");
1799 Error(ERR_INFO, "warning: error found in config file:");
1800 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1801 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1802 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1803 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1805 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1806 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1807 Error(ERR_INFO, "custom graphic rejected for this element/action");
1809 if (i == fallback_graphic)
1810 Error(ERR_EXIT, "no fallback graphic available");
1812 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1813 Error(ERR_INFO_LINE, "-");
1815 graphic_info[i] = graphic_info[fallback_graphic];
1820 static void InitGraphicCompatibilityInfo()
1822 struct FileInfo *fi_global_door =
1823 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1824 int num_images = getImageListSize();
1827 /* the following compatibility handling is needed for the following case:
1828 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1829 graphics mainly used for door and panel graphics, like editor, tape and
1830 in-game buttons with hard-coded bitmap positions and button sizes; as
1831 these graphics now have individual definitions, redefining "global.door"
1832 to change all these graphics at once like before does not work anymore
1833 (because all those individual definitions still have their default values);
1834 to solve this, remap all those individual definitions that are not
1835 redefined to the new bitmap of "global.door" if it was redefined */
1837 /* special compatibility handling if image "global.door" was redefined */
1838 if (fi_global_door->redefined)
1840 for (i = 0; i < num_images; i++)
1842 struct FileInfo *fi = getImageListEntryFromImageID(i);
1844 /* process only those images that still use the default settings */
1847 /* process all images which default to same image as "global.door" */
1848 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1850 // printf("::: special treatment needed for token '%s'\n", fi->token);
1852 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1853 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1859 InitGraphicCompatibilityInfo_Doors();
1862 static void InitElementSoundInfo()
1864 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1865 int num_property_mappings = getSoundListPropertyMappingSize();
1868 /* set values to -1 to identify later as "uninitialized" values */
1869 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1870 for (act = 0; act < NUM_ACTIONS; act++)
1871 element_info[i].sound[act] = -1;
1873 /* initialize element/sound mapping from static configuration */
1874 for (i = 0; element_to_sound[i].element > -1; i++)
1876 int element = element_to_sound[i].element;
1877 int action = element_to_sound[i].action;
1878 int sound = element_to_sound[i].sound;
1879 boolean is_class = element_to_sound[i].is_class;
1882 action = ACTION_DEFAULT;
1885 element_info[element].sound[action] = sound;
1887 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1888 if (strEqual(element_info[j].class_name,
1889 element_info[element].class_name))
1890 element_info[j].sound[action] = sound;
1893 /* initialize element class/sound mapping from dynamic configuration */
1894 for (i = 0; i < num_property_mappings; i++)
1896 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1897 int action = property_mapping[i].ext1_index;
1898 int sound = property_mapping[i].artwork_index;
1900 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1904 action = ACTION_DEFAULT;
1906 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1907 if (strEqual(element_info[j].class_name,
1908 element_info[element_class].class_name))
1909 element_info[j].sound[action] = sound;
1912 /* initialize element/sound mapping from dynamic configuration */
1913 for (i = 0; i < num_property_mappings; i++)
1915 int element = property_mapping[i].base_index;
1916 int action = property_mapping[i].ext1_index;
1917 int sound = property_mapping[i].artwork_index;
1919 if (element >= MAX_NUM_ELEMENTS)
1923 action = ACTION_DEFAULT;
1925 element_info[element].sound[action] = sound;
1928 /* now set all '-1' values to element specific default values */
1929 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1931 for (act = 0; act < NUM_ACTIONS; act++)
1933 /* generic default action sound (defined by "[default]" directive) */
1934 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1936 /* look for special default action sound (classic game specific) */
1937 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1938 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1939 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1940 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1941 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1942 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1943 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1944 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1946 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1947 /* !!! make this better !!! */
1948 if (i == EL_EMPTY_SPACE)
1949 default_action_sound = element_info[EL_DEFAULT].sound[act];
1951 /* no sound for this specific action -- use default action sound */
1952 if (element_info[i].sound[act] == -1)
1953 element_info[i].sound[act] = default_action_sound;
1957 /* copy sound settings to some elements that are only stored in level file
1958 in native R'n'D levels, but are used by game engine in native EM levels */
1959 for (i = 0; copy_properties[i][0] != -1; i++)
1960 for (j = 1; j <= 4; j++)
1961 for (act = 0; act < NUM_ACTIONS; act++)
1962 element_info[copy_properties[i][j]].sound[act] =
1963 element_info[copy_properties[i][0]].sound[act];
1966 static void InitGameModeSoundInfo()
1970 /* set values to -1 to identify later as "uninitialized" values */
1971 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1974 /* initialize gamemode/sound mapping from static configuration */
1975 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1977 int gamemode = gamemode_to_sound[i].gamemode;
1978 int sound = gamemode_to_sound[i].sound;
1981 gamemode = GAME_MODE_DEFAULT;
1983 menu.sound[gamemode] = sound;
1986 /* now set all '-1' values to levelset specific default values */
1987 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1988 if (menu.sound[i] == -1)
1989 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1992 static void set_sound_parameters(int sound, char **parameter_raw)
1994 int parameter[NUM_SND_ARGS];
1997 /* get integer values from string parameters */
1998 for (i = 0; i < NUM_SND_ARGS; i++)
2000 get_parameter_value(parameter_raw[i],
2001 sound_config_suffix[i].token,
2002 sound_config_suffix[i].type);
2004 /* explicit loop mode setting in configuration overrides default value */
2005 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2006 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2008 /* sound volume to change the original volume when loading the sound file */
2009 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2011 /* sound priority to give certain sounds a higher or lower priority */
2012 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2015 static void InitSoundInfo()
2017 int *sound_effect_properties;
2018 int num_sounds = getSoundListSize();
2021 checked_free(sound_info);
2023 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2024 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2026 /* initialize sound effect for all elements to "no sound" */
2027 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2028 for (j = 0; j < NUM_ACTIONS; j++)
2029 element_info[i].sound[j] = SND_UNDEFINED;
2031 for (i = 0; i < num_sounds; i++)
2033 struct FileInfo *sound = getSoundListEntry(i);
2034 int len_effect_text = strlen(sound->token);
2036 sound_effect_properties[i] = ACTION_OTHER;
2037 sound_info[i].loop = FALSE; /* default: play sound only once */
2039 /* determine all loop sounds and identify certain sound classes */
2041 for (j = 0; element_action_info[j].suffix; j++)
2043 int len_action_text = strlen(element_action_info[j].suffix);
2045 if (len_action_text < len_effect_text &&
2046 strEqual(&sound->token[len_effect_text - len_action_text],
2047 element_action_info[j].suffix))
2049 sound_effect_properties[i] = element_action_info[j].value;
2050 sound_info[i].loop = element_action_info[j].is_loop_sound;
2056 /* associate elements and some selected sound actions */
2058 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2060 if (element_info[j].class_name)
2062 int len_class_text = strlen(element_info[j].class_name);
2064 if (len_class_text + 1 < len_effect_text &&
2065 strncmp(sound->token,
2066 element_info[j].class_name, len_class_text) == 0 &&
2067 sound->token[len_class_text] == '.')
2069 int sound_action_value = sound_effect_properties[i];
2071 element_info[j].sound[sound_action_value] = i;
2076 set_sound_parameters(i, sound->parameter);
2079 free(sound_effect_properties);
2082 static void InitGameModeMusicInfo()
2084 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2085 int num_property_mappings = getMusicListPropertyMappingSize();
2086 int default_levelset_music = -1;
2089 /* set values to -1 to identify later as "uninitialized" values */
2090 for (i = 0; i < MAX_LEVELS; i++)
2091 levelset.music[i] = -1;
2092 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2095 /* initialize gamemode/music mapping from static configuration */
2096 for (i = 0; gamemode_to_music[i].music > -1; i++)
2098 int gamemode = gamemode_to_music[i].gamemode;
2099 int music = gamemode_to_music[i].music;
2102 gamemode = GAME_MODE_DEFAULT;
2104 menu.music[gamemode] = music;
2107 /* initialize gamemode/music mapping from dynamic configuration */
2108 for (i = 0; i < num_property_mappings; i++)
2110 int prefix = property_mapping[i].base_index;
2111 int gamemode = property_mapping[i].ext2_index;
2112 int level = property_mapping[i].ext3_index;
2113 int music = property_mapping[i].artwork_index;
2115 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2119 gamemode = GAME_MODE_DEFAULT;
2121 /* level specific music only allowed for in-game music */
2122 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2123 gamemode = GAME_MODE_PLAYING;
2128 default_levelset_music = music;
2131 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2132 levelset.music[level] = music;
2133 if (gamemode != GAME_MODE_PLAYING)
2134 menu.music[gamemode] = music;
2137 /* now set all '-1' values to menu specific default values */
2138 /* (undefined values of "levelset.music[]" might stay at "-1" to
2139 allow dynamic selection of music files from music directory!) */
2140 for (i = 0; i < MAX_LEVELS; i++)
2141 if (levelset.music[i] == -1)
2142 levelset.music[i] = default_levelset_music;
2143 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2144 if (menu.music[i] == -1)
2145 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2148 static void set_music_parameters(int music, char **parameter_raw)
2150 int parameter[NUM_MUS_ARGS];
2153 /* get integer values from string parameters */
2154 for (i = 0; i < NUM_MUS_ARGS; i++)
2156 get_parameter_value(parameter_raw[i],
2157 music_config_suffix[i].token,
2158 music_config_suffix[i].type);
2160 /* explicit loop mode setting in configuration overrides default value */
2161 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2162 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2165 static void InitMusicInfo()
2167 int num_music = getMusicListSize();
2170 checked_free(music_info);
2172 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2174 for (i = 0; i < num_music; i++)
2176 struct FileInfo *music = getMusicListEntry(i);
2177 int len_music_text = strlen(music->token);
2179 music_info[i].loop = TRUE; /* default: play music in loop mode */
2181 /* determine all loop music */
2183 for (j = 0; music_prefix_info[j].prefix; j++)
2185 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2187 if (len_prefix_text < len_music_text &&
2188 strncmp(music->token,
2189 music_prefix_info[j].prefix, len_prefix_text) == 0)
2191 music_info[i].loop = music_prefix_info[j].is_loop_music;
2197 set_music_parameters(i, music->parameter);
2201 static void ReinitializeGraphics()
2203 print_timestamp_init("ReinitializeGraphics");
2205 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2207 InitGraphicInfo(); /* graphic properties mapping */
2208 print_timestamp_time("InitGraphicInfo");
2209 InitElementGraphicInfo(); /* element game graphic mapping */
2210 print_timestamp_time("InitElementGraphicInfo");
2211 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2212 print_timestamp_time("InitElementSpecialGraphicInfo");
2214 InitElementSmallImages(); /* scale elements to all needed sizes */
2215 print_timestamp_time("InitElementSmallImages");
2216 InitScaledImages(); /* scale all other images, if needed */
2217 print_timestamp_time("InitScaledImages");
2218 InitBitmapPointers(); /* set standard size bitmap pointers */
2219 print_timestamp_time("InitBitmapPointers");
2220 InitFontGraphicInfo(); /* initialize text drawing functions */
2221 print_timestamp_time("InitFontGraphicInfo");
2222 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2223 print_timestamp_time("InitGlobalAnimGraphicInfo");
2225 InitImageTextures(); /* create textures for certain images */
2226 print_timestamp_time("InitImageTextures");
2228 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2229 print_timestamp_time("InitGraphicInfo_EM");
2231 InitGraphicCompatibilityInfo();
2232 print_timestamp_time("InitGraphicCompatibilityInfo");
2234 SetMainBackgroundImage(IMG_BACKGROUND);
2235 print_timestamp_time("SetMainBackgroundImage");
2236 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2237 print_timestamp_time("SetDoorBackgroundImage");
2240 print_timestamp_time("InitGadgets");
2242 print_timestamp_time("InitDoors");
2244 print_timestamp_done("ReinitializeGraphics");
2247 static void ReinitializeSounds()
2249 InitSoundInfo(); /* sound properties mapping */
2250 InitElementSoundInfo(); /* element game sound mapping */
2251 InitGameModeSoundInfo(); /* game mode sound mapping */
2252 InitGlobalAnimSoundInfo(); /* global animation sound settings */
2254 InitPlayLevelSound(); /* internal game sound settings */
2257 static void ReinitializeMusic()
2259 InitMusicInfo(); /* music properties mapping */
2260 InitGameModeMusicInfo(); /* game mode music mapping */
2261 InitGlobalAnimMusicInfo(); /* global animation music settings */
2264 static int get_special_property_bit(int element, int property_bit_nr)
2266 struct PropertyBitInfo
2272 static struct PropertyBitInfo pb_can_move_into_acid[] =
2274 /* the player may be able fall into acid when gravity is activated */
2279 { EL_SP_MURPHY, 0 },
2280 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2282 /* all elements that can move may be able to also move into acid */
2285 { EL_BUG_RIGHT, 1 },
2288 { EL_SPACESHIP, 2 },
2289 { EL_SPACESHIP_LEFT, 2 },
2290 { EL_SPACESHIP_RIGHT, 2 },
2291 { EL_SPACESHIP_UP, 2 },
2292 { EL_SPACESHIP_DOWN, 2 },
2293 { EL_BD_BUTTERFLY, 3 },
2294 { EL_BD_BUTTERFLY_LEFT, 3 },
2295 { EL_BD_BUTTERFLY_RIGHT, 3 },
2296 { EL_BD_BUTTERFLY_UP, 3 },
2297 { EL_BD_BUTTERFLY_DOWN, 3 },
2298 { EL_BD_FIREFLY, 4 },
2299 { EL_BD_FIREFLY_LEFT, 4 },
2300 { EL_BD_FIREFLY_RIGHT, 4 },
2301 { EL_BD_FIREFLY_UP, 4 },
2302 { EL_BD_FIREFLY_DOWN, 4 },
2304 { EL_YAMYAM_LEFT, 5 },
2305 { EL_YAMYAM_RIGHT, 5 },
2306 { EL_YAMYAM_UP, 5 },
2307 { EL_YAMYAM_DOWN, 5 },
2308 { EL_DARK_YAMYAM, 6 },
2311 { EL_PACMAN_LEFT, 8 },
2312 { EL_PACMAN_RIGHT, 8 },
2313 { EL_PACMAN_UP, 8 },
2314 { EL_PACMAN_DOWN, 8 },
2316 { EL_MOLE_LEFT, 9 },
2317 { EL_MOLE_RIGHT, 9 },
2319 { EL_MOLE_DOWN, 9 },
2323 { EL_SATELLITE, 13 },
2324 { EL_SP_SNIKSNAK, 14 },
2325 { EL_SP_ELECTRON, 15 },
2328 { EL_EMC_ANDROID, 18 },
2333 static struct PropertyBitInfo pb_dont_collide_with[] =
2335 { EL_SP_SNIKSNAK, 0 },
2336 { EL_SP_ELECTRON, 1 },
2344 struct PropertyBitInfo *pb_info;
2347 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2348 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2353 struct PropertyBitInfo *pb_info = NULL;
2356 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2357 if (pb_definition[i].bit_nr == property_bit_nr)
2358 pb_info = pb_definition[i].pb_info;
2360 if (pb_info == NULL)
2363 for (i = 0; pb_info[i].element != -1; i++)
2364 if (pb_info[i].element == element)
2365 return pb_info[i].bit_nr;
2370 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2371 boolean property_value)
2373 int bit_nr = get_special_property_bit(element, property_bit_nr);
2378 *bitfield |= (1 << bit_nr);
2380 *bitfield &= ~(1 << bit_nr);
2384 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2386 int bit_nr = get_special_property_bit(element, property_bit_nr);
2389 return ((*bitfield & (1 << bit_nr)) != 0);
2394 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2396 static int group_nr;
2397 static struct ElementGroupInfo *group;
2398 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2401 if (actual_group == NULL) /* not yet initialized */
2404 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2406 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2407 group_element - EL_GROUP_START + 1);
2409 /* replace element which caused too deep recursion by question mark */
2410 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2415 if (recursion_depth == 0) /* initialization */
2417 group = actual_group;
2418 group_nr = GROUP_NR(group_element);
2420 group->num_elements_resolved = 0;
2421 group->choice_pos = 0;
2423 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2424 element_info[i].in_group[group_nr] = FALSE;
2427 for (i = 0; i < actual_group->num_elements; i++)
2429 int element = actual_group->element[i];
2431 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2434 if (IS_GROUP_ELEMENT(element))
2435 ResolveGroupElementExt(element, recursion_depth + 1);
2438 group->element_resolved[group->num_elements_resolved++] = element;
2439 element_info[element].in_group[group_nr] = TRUE;
2444 void ResolveGroupElement(int group_element)
2446 ResolveGroupElementExt(group_element, 0);
2449 void InitElementPropertiesStatic()
2451 static boolean clipboard_elements_initialized = FALSE;
2453 static int ep_diggable[] =
2458 EL_SP_BUGGY_BASE_ACTIVATING,
2461 EL_INVISIBLE_SAND_ACTIVE,
2464 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2465 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2470 EL_SP_BUGGY_BASE_ACTIVE,
2477 static int ep_collectible_only[] =
2499 EL_DYNABOMB_INCREASE_NUMBER,
2500 EL_DYNABOMB_INCREASE_SIZE,
2501 EL_DYNABOMB_INCREASE_POWER,
2519 /* !!! handle separately !!! */
2520 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2526 static int ep_dont_run_into[] =
2528 /* same elements as in 'ep_dont_touch' */
2534 /* same elements as in 'ep_dont_collide_with' */
2546 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2551 EL_SP_BUGGY_BASE_ACTIVE,
2558 static int ep_dont_collide_with[] =
2560 /* same elements as in 'ep_dont_touch' */
2577 static int ep_dont_touch[] =
2587 static int ep_indestructible[] =
2591 EL_ACID_POOL_TOPLEFT,
2592 EL_ACID_POOL_TOPRIGHT,
2593 EL_ACID_POOL_BOTTOMLEFT,
2594 EL_ACID_POOL_BOTTOM,
2595 EL_ACID_POOL_BOTTOMRIGHT,
2596 EL_SP_HARDWARE_GRAY,
2597 EL_SP_HARDWARE_GREEN,
2598 EL_SP_HARDWARE_BLUE,
2600 EL_SP_HARDWARE_YELLOW,
2601 EL_SP_HARDWARE_BASE_1,
2602 EL_SP_HARDWARE_BASE_2,
2603 EL_SP_HARDWARE_BASE_3,
2604 EL_SP_HARDWARE_BASE_4,
2605 EL_SP_HARDWARE_BASE_5,
2606 EL_SP_HARDWARE_BASE_6,
2607 EL_INVISIBLE_STEELWALL,
2608 EL_INVISIBLE_STEELWALL_ACTIVE,
2609 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2610 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2611 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2612 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2613 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2614 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2615 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2616 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2617 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2618 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2619 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2620 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2622 EL_LIGHT_SWITCH_ACTIVE,
2623 EL_SIGN_EXCLAMATION,
2624 EL_SIGN_RADIOACTIVITY,
2631 EL_SIGN_ENTRY_FORBIDDEN,
2632 EL_SIGN_EMERGENCY_EXIT,
2640 EL_STEEL_EXIT_CLOSED,
2642 EL_STEEL_EXIT_OPENING,
2643 EL_STEEL_EXIT_CLOSING,
2644 EL_EM_STEEL_EXIT_CLOSED,
2645 EL_EM_STEEL_EXIT_OPEN,
2646 EL_EM_STEEL_EXIT_OPENING,
2647 EL_EM_STEEL_EXIT_CLOSING,
2648 EL_DC_STEELWALL_1_LEFT,
2649 EL_DC_STEELWALL_1_RIGHT,
2650 EL_DC_STEELWALL_1_TOP,
2651 EL_DC_STEELWALL_1_BOTTOM,
2652 EL_DC_STEELWALL_1_HORIZONTAL,
2653 EL_DC_STEELWALL_1_VERTICAL,
2654 EL_DC_STEELWALL_1_TOPLEFT,
2655 EL_DC_STEELWALL_1_TOPRIGHT,
2656 EL_DC_STEELWALL_1_BOTTOMLEFT,
2657 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2658 EL_DC_STEELWALL_1_TOPLEFT_2,
2659 EL_DC_STEELWALL_1_TOPRIGHT_2,
2660 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2661 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2662 EL_DC_STEELWALL_2_LEFT,
2663 EL_DC_STEELWALL_2_RIGHT,
2664 EL_DC_STEELWALL_2_TOP,
2665 EL_DC_STEELWALL_2_BOTTOM,
2666 EL_DC_STEELWALL_2_HORIZONTAL,
2667 EL_DC_STEELWALL_2_VERTICAL,
2668 EL_DC_STEELWALL_2_MIDDLE,
2669 EL_DC_STEELWALL_2_SINGLE,
2670 EL_STEELWALL_SLIPPERY,
2684 EL_GATE_1_GRAY_ACTIVE,
2685 EL_GATE_2_GRAY_ACTIVE,
2686 EL_GATE_3_GRAY_ACTIVE,
2687 EL_GATE_4_GRAY_ACTIVE,
2696 EL_EM_GATE_1_GRAY_ACTIVE,
2697 EL_EM_GATE_2_GRAY_ACTIVE,
2698 EL_EM_GATE_3_GRAY_ACTIVE,
2699 EL_EM_GATE_4_GRAY_ACTIVE,
2708 EL_EMC_GATE_5_GRAY_ACTIVE,
2709 EL_EMC_GATE_6_GRAY_ACTIVE,
2710 EL_EMC_GATE_7_GRAY_ACTIVE,
2711 EL_EMC_GATE_8_GRAY_ACTIVE,
2713 EL_DC_GATE_WHITE_GRAY,
2714 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2715 EL_DC_GATE_FAKE_GRAY,
2717 EL_SWITCHGATE_OPENING,
2718 EL_SWITCHGATE_CLOSED,
2719 EL_SWITCHGATE_CLOSING,
2720 EL_DC_SWITCHGATE_SWITCH_UP,
2721 EL_DC_SWITCHGATE_SWITCH_DOWN,
2723 EL_TIMEGATE_OPENING,
2725 EL_TIMEGATE_CLOSING,
2726 EL_DC_TIMEGATE_SWITCH,
2727 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2731 EL_TUBE_VERTICAL_LEFT,
2732 EL_TUBE_VERTICAL_RIGHT,
2733 EL_TUBE_HORIZONTAL_UP,
2734 EL_TUBE_HORIZONTAL_DOWN,
2739 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2740 EL_EXPANDABLE_STEELWALL_VERTICAL,
2741 EL_EXPANDABLE_STEELWALL_ANY,
2746 static int ep_slippery[] =
2760 EL_ROBOT_WHEEL_ACTIVE,
2766 EL_ACID_POOL_TOPLEFT,
2767 EL_ACID_POOL_TOPRIGHT,
2777 EL_STEELWALL_SLIPPERY,
2780 EL_EMC_WALL_SLIPPERY_1,
2781 EL_EMC_WALL_SLIPPERY_2,
2782 EL_EMC_WALL_SLIPPERY_3,
2783 EL_EMC_WALL_SLIPPERY_4,
2785 EL_EMC_MAGIC_BALL_ACTIVE,
2790 static int ep_can_change[] =
2795 static int ep_can_move[] =
2797 /* same elements as in 'pb_can_move_into_acid' */
2820 static int ep_can_fall[] =
2834 EL_QUICKSAND_FAST_FULL,
2836 EL_BD_MAGIC_WALL_FULL,
2837 EL_DC_MAGIC_WALL_FULL,
2851 static int ep_can_smash_player[] =
2877 static int ep_can_smash_enemies[] =
2886 static int ep_can_smash_everything[] =
2895 static int ep_explodes_by_fire[] =
2897 /* same elements as in 'ep_explodes_impact' */
2902 /* same elements as in 'ep_explodes_smashed' */
2912 EL_EM_DYNAMITE_ACTIVE,
2913 EL_DYNABOMB_PLAYER_1_ACTIVE,
2914 EL_DYNABOMB_PLAYER_2_ACTIVE,
2915 EL_DYNABOMB_PLAYER_3_ACTIVE,
2916 EL_DYNABOMB_PLAYER_4_ACTIVE,
2917 EL_DYNABOMB_INCREASE_NUMBER,
2918 EL_DYNABOMB_INCREASE_SIZE,
2919 EL_DYNABOMB_INCREASE_POWER,
2920 EL_SP_DISK_RED_ACTIVE,
2934 static int ep_explodes_smashed[] =
2936 /* same elements as in 'ep_explodes_impact' */
2950 static int ep_explodes_impact[] =
2959 static int ep_walkable_over[] =
2963 EL_SOKOBAN_FIELD_EMPTY,
2970 EL_EM_STEEL_EXIT_OPEN,
2971 EL_EM_STEEL_EXIT_OPENING,
2980 EL_GATE_1_GRAY_ACTIVE,
2981 EL_GATE_2_GRAY_ACTIVE,
2982 EL_GATE_3_GRAY_ACTIVE,
2983 EL_GATE_4_GRAY_ACTIVE,
2991 static int ep_walkable_inside[] =
2996 EL_TUBE_VERTICAL_LEFT,
2997 EL_TUBE_VERTICAL_RIGHT,
2998 EL_TUBE_HORIZONTAL_UP,
2999 EL_TUBE_HORIZONTAL_DOWN,
3008 static int ep_walkable_under[] =
3013 static int ep_passable_over[] =
3023 EL_EM_GATE_1_GRAY_ACTIVE,
3024 EL_EM_GATE_2_GRAY_ACTIVE,
3025 EL_EM_GATE_3_GRAY_ACTIVE,
3026 EL_EM_GATE_4_GRAY_ACTIVE,
3035 EL_EMC_GATE_5_GRAY_ACTIVE,
3036 EL_EMC_GATE_6_GRAY_ACTIVE,
3037 EL_EMC_GATE_7_GRAY_ACTIVE,
3038 EL_EMC_GATE_8_GRAY_ACTIVE,
3040 EL_DC_GATE_WHITE_GRAY,
3041 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3048 static int ep_passable_inside[] =
3054 EL_SP_PORT_HORIZONTAL,
3055 EL_SP_PORT_VERTICAL,
3057 EL_SP_GRAVITY_PORT_LEFT,
3058 EL_SP_GRAVITY_PORT_RIGHT,
3059 EL_SP_GRAVITY_PORT_UP,
3060 EL_SP_GRAVITY_PORT_DOWN,
3061 EL_SP_GRAVITY_ON_PORT_LEFT,
3062 EL_SP_GRAVITY_ON_PORT_RIGHT,
3063 EL_SP_GRAVITY_ON_PORT_UP,
3064 EL_SP_GRAVITY_ON_PORT_DOWN,
3065 EL_SP_GRAVITY_OFF_PORT_LEFT,
3066 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3067 EL_SP_GRAVITY_OFF_PORT_UP,
3068 EL_SP_GRAVITY_OFF_PORT_DOWN,
3073 static int ep_passable_under[] =
3078 static int ep_droppable[] =
3083 static int ep_explodes_1x1_old[] =
3088 static int ep_pushable[] =
3100 EL_SOKOBAN_FIELD_FULL,
3109 static int ep_explodes_cross_old[] =
3114 static int ep_protected[] =
3116 /* same elements as in 'ep_walkable_inside' */
3120 EL_TUBE_VERTICAL_LEFT,
3121 EL_TUBE_VERTICAL_RIGHT,
3122 EL_TUBE_HORIZONTAL_UP,
3123 EL_TUBE_HORIZONTAL_DOWN,
3129 /* same elements as in 'ep_passable_over' */
3138 EL_EM_GATE_1_GRAY_ACTIVE,
3139 EL_EM_GATE_2_GRAY_ACTIVE,
3140 EL_EM_GATE_3_GRAY_ACTIVE,
3141 EL_EM_GATE_4_GRAY_ACTIVE,
3150 EL_EMC_GATE_5_GRAY_ACTIVE,
3151 EL_EMC_GATE_6_GRAY_ACTIVE,
3152 EL_EMC_GATE_7_GRAY_ACTIVE,
3153 EL_EMC_GATE_8_GRAY_ACTIVE,
3155 EL_DC_GATE_WHITE_GRAY,
3156 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3160 /* same elements as in 'ep_passable_inside' */
3165 EL_SP_PORT_HORIZONTAL,
3166 EL_SP_PORT_VERTICAL,
3168 EL_SP_GRAVITY_PORT_LEFT,
3169 EL_SP_GRAVITY_PORT_RIGHT,
3170 EL_SP_GRAVITY_PORT_UP,
3171 EL_SP_GRAVITY_PORT_DOWN,
3172 EL_SP_GRAVITY_ON_PORT_LEFT,
3173 EL_SP_GRAVITY_ON_PORT_RIGHT,
3174 EL_SP_GRAVITY_ON_PORT_UP,
3175 EL_SP_GRAVITY_ON_PORT_DOWN,
3176 EL_SP_GRAVITY_OFF_PORT_LEFT,
3177 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3178 EL_SP_GRAVITY_OFF_PORT_UP,
3179 EL_SP_GRAVITY_OFF_PORT_DOWN,
3184 static int ep_throwable[] =
3189 static int ep_can_explode[] =
3191 /* same elements as in 'ep_explodes_impact' */
3196 /* same elements as in 'ep_explodes_smashed' */
3202 /* elements that can explode by explosion or by dragonfire */
3206 EL_EM_DYNAMITE_ACTIVE,
3207 EL_DYNABOMB_PLAYER_1_ACTIVE,
3208 EL_DYNABOMB_PLAYER_2_ACTIVE,
3209 EL_DYNABOMB_PLAYER_3_ACTIVE,
3210 EL_DYNABOMB_PLAYER_4_ACTIVE,
3211 EL_DYNABOMB_INCREASE_NUMBER,
3212 EL_DYNABOMB_INCREASE_SIZE,
3213 EL_DYNABOMB_INCREASE_POWER,
3214 EL_SP_DISK_RED_ACTIVE,
3222 /* elements that can explode only by explosion */
3228 static int ep_gravity_reachable[] =
3234 EL_INVISIBLE_SAND_ACTIVE,
3239 EL_SP_PORT_HORIZONTAL,
3240 EL_SP_PORT_VERTICAL,
3242 EL_SP_GRAVITY_PORT_LEFT,
3243 EL_SP_GRAVITY_PORT_RIGHT,
3244 EL_SP_GRAVITY_PORT_UP,
3245 EL_SP_GRAVITY_PORT_DOWN,
3246 EL_SP_GRAVITY_ON_PORT_LEFT,
3247 EL_SP_GRAVITY_ON_PORT_RIGHT,
3248 EL_SP_GRAVITY_ON_PORT_UP,
3249 EL_SP_GRAVITY_ON_PORT_DOWN,
3250 EL_SP_GRAVITY_OFF_PORT_LEFT,
3251 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3252 EL_SP_GRAVITY_OFF_PORT_UP,
3253 EL_SP_GRAVITY_OFF_PORT_DOWN,
3259 static int ep_player[] =
3266 EL_SOKOBAN_FIELD_PLAYER,
3272 static int ep_can_pass_magic_wall[] =
3286 static int ep_can_pass_dc_magic_wall[] =
3302 static int ep_switchable[] =
3306 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3307 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3308 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3309 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3310 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3311 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3312 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3313 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3314 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3315 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3316 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3317 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3318 EL_SWITCHGATE_SWITCH_UP,
3319 EL_SWITCHGATE_SWITCH_DOWN,
3320 EL_DC_SWITCHGATE_SWITCH_UP,
3321 EL_DC_SWITCHGATE_SWITCH_DOWN,
3323 EL_LIGHT_SWITCH_ACTIVE,
3325 EL_DC_TIMEGATE_SWITCH,
3326 EL_BALLOON_SWITCH_LEFT,
3327 EL_BALLOON_SWITCH_RIGHT,
3328 EL_BALLOON_SWITCH_UP,
3329 EL_BALLOON_SWITCH_DOWN,
3330 EL_BALLOON_SWITCH_ANY,
3331 EL_BALLOON_SWITCH_NONE,
3334 EL_EMC_MAGIC_BALL_SWITCH,
3335 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3340 static int ep_bd_element[] =
3374 static int ep_sp_element[] =
3376 /* should always be valid */
3379 /* standard classic Supaplex elements */
3386 EL_SP_HARDWARE_GRAY,
3394 EL_SP_GRAVITY_PORT_RIGHT,
3395 EL_SP_GRAVITY_PORT_DOWN,
3396 EL_SP_GRAVITY_PORT_LEFT,
3397 EL_SP_GRAVITY_PORT_UP,
3402 EL_SP_PORT_VERTICAL,
3403 EL_SP_PORT_HORIZONTAL,
3409 EL_SP_HARDWARE_BASE_1,
3410 EL_SP_HARDWARE_GREEN,
3411 EL_SP_HARDWARE_BLUE,
3413 EL_SP_HARDWARE_YELLOW,
3414 EL_SP_HARDWARE_BASE_2,
3415 EL_SP_HARDWARE_BASE_3,
3416 EL_SP_HARDWARE_BASE_4,
3417 EL_SP_HARDWARE_BASE_5,
3418 EL_SP_HARDWARE_BASE_6,
3422 /* additional elements that appeared in newer Supaplex levels */
3425 /* additional gravity port elements (not switching, but setting gravity) */
3426 EL_SP_GRAVITY_ON_PORT_LEFT,
3427 EL_SP_GRAVITY_ON_PORT_RIGHT,
3428 EL_SP_GRAVITY_ON_PORT_UP,
3429 EL_SP_GRAVITY_ON_PORT_DOWN,
3430 EL_SP_GRAVITY_OFF_PORT_LEFT,
3431 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3432 EL_SP_GRAVITY_OFF_PORT_UP,
3433 EL_SP_GRAVITY_OFF_PORT_DOWN,
3435 /* more than one Murphy in a level results in an inactive clone */
3438 /* runtime Supaplex elements */
3439 EL_SP_DISK_RED_ACTIVE,
3440 EL_SP_TERMINAL_ACTIVE,
3441 EL_SP_BUGGY_BASE_ACTIVATING,
3442 EL_SP_BUGGY_BASE_ACTIVE,
3449 static int ep_sb_element[] =
3454 EL_SOKOBAN_FIELD_EMPTY,
3455 EL_SOKOBAN_FIELD_FULL,
3456 EL_SOKOBAN_FIELD_PLAYER,
3461 EL_INVISIBLE_STEELWALL,
3466 static int ep_gem[] =
3478 static int ep_food_dark_yamyam[] =
3506 static int ep_food_penguin[] =
3520 static int ep_food_pig[] =
3532 static int ep_historic_wall[] =
3543 EL_GATE_1_GRAY_ACTIVE,
3544 EL_GATE_2_GRAY_ACTIVE,
3545 EL_GATE_3_GRAY_ACTIVE,
3546 EL_GATE_4_GRAY_ACTIVE,
3555 EL_EM_GATE_1_GRAY_ACTIVE,
3556 EL_EM_GATE_2_GRAY_ACTIVE,
3557 EL_EM_GATE_3_GRAY_ACTIVE,
3558 EL_EM_GATE_4_GRAY_ACTIVE,
3565 EL_EXPANDABLE_WALL_HORIZONTAL,
3566 EL_EXPANDABLE_WALL_VERTICAL,
3567 EL_EXPANDABLE_WALL_ANY,
3568 EL_EXPANDABLE_WALL_GROWING,
3569 EL_BD_EXPANDABLE_WALL,
3576 EL_SP_HARDWARE_GRAY,
3577 EL_SP_HARDWARE_GREEN,
3578 EL_SP_HARDWARE_BLUE,
3580 EL_SP_HARDWARE_YELLOW,
3581 EL_SP_HARDWARE_BASE_1,
3582 EL_SP_HARDWARE_BASE_2,
3583 EL_SP_HARDWARE_BASE_3,
3584 EL_SP_HARDWARE_BASE_4,
3585 EL_SP_HARDWARE_BASE_5,
3586 EL_SP_HARDWARE_BASE_6,
3588 EL_SP_TERMINAL_ACTIVE,
3591 EL_INVISIBLE_STEELWALL,
3592 EL_INVISIBLE_STEELWALL_ACTIVE,
3594 EL_INVISIBLE_WALL_ACTIVE,
3595 EL_STEELWALL_SLIPPERY,
3612 static int ep_historic_solid[] =
3616 EL_EXPANDABLE_WALL_HORIZONTAL,
3617 EL_EXPANDABLE_WALL_VERTICAL,
3618 EL_EXPANDABLE_WALL_ANY,
3619 EL_BD_EXPANDABLE_WALL,
3632 EL_QUICKSAND_FILLING,
3633 EL_QUICKSAND_EMPTYING,
3635 EL_MAGIC_WALL_ACTIVE,
3636 EL_MAGIC_WALL_EMPTYING,
3637 EL_MAGIC_WALL_FILLING,
3641 EL_BD_MAGIC_WALL_ACTIVE,
3642 EL_BD_MAGIC_WALL_EMPTYING,
3643 EL_BD_MAGIC_WALL_FULL,
3644 EL_BD_MAGIC_WALL_FILLING,
3645 EL_BD_MAGIC_WALL_DEAD,
3654 EL_SP_TERMINAL_ACTIVE,
3658 EL_INVISIBLE_WALL_ACTIVE,
3659 EL_SWITCHGATE_SWITCH_UP,
3660 EL_SWITCHGATE_SWITCH_DOWN,
3661 EL_DC_SWITCHGATE_SWITCH_UP,
3662 EL_DC_SWITCHGATE_SWITCH_DOWN,
3664 EL_TIMEGATE_SWITCH_ACTIVE,
3665 EL_DC_TIMEGATE_SWITCH,
3666 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3678 /* the following elements are a direct copy of "indestructible" elements,
3679 except "EL_ACID", which is "indestructible", but not "solid"! */
3684 EL_ACID_POOL_TOPLEFT,
3685 EL_ACID_POOL_TOPRIGHT,
3686 EL_ACID_POOL_BOTTOMLEFT,
3687 EL_ACID_POOL_BOTTOM,
3688 EL_ACID_POOL_BOTTOMRIGHT,
3689 EL_SP_HARDWARE_GRAY,
3690 EL_SP_HARDWARE_GREEN,
3691 EL_SP_HARDWARE_BLUE,
3693 EL_SP_HARDWARE_YELLOW,
3694 EL_SP_HARDWARE_BASE_1,
3695 EL_SP_HARDWARE_BASE_2,
3696 EL_SP_HARDWARE_BASE_3,
3697 EL_SP_HARDWARE_BASE_4,
3698 EL_SP_HARDWARE_BASE_5,
3699 EL_SP_HARDWARE_BASE_6,
3700 EL_INVISIBLE_STEELWALL,
3701 EL_INVISIBLE_STEELWALL_ACTIVE,
3702 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3703 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3704 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3705 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3706 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3707 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3708 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3709 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3710 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3711 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3712 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3713 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3715 EL_LIGHT_SWITCH_ACTIVE,
3716 EL_SIGN_EXCLAMATION,
3717 EL_SIGN_RADIOACTIVITY,
3724 EL_SIGN_ENTRY_FORBIDDEN,
3725 EL_SIGN_EMERGENCY_EXIT,
3733 EL_STEEL_EXIT_CLOSED,
3735 EL_DC_STEELWALL_1_LEFT,
3736 EL_DC_STEELWALL_1_RIGHT,
3737 EL_DC_STEELWALL_1_TOP,
3738 EL_DC_STEELWALL_1_BOTTOM,
3739 EL_DC_STEELWALL_1_HORIZONTAL,
3740 EL_DC_STEELWALL_1_VERTICAL,
3741 EL_DC_STEELWALL_1_TOPLEFT,
3742 EL_DC_STEELWALL_1_TOPRIGHT,
3743 EL_DC_STEELWALL_1_BOTTOMLEFT,
3744 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3745 EL_DC_STEELWALL_1_TOPLEFT_2,
3746 EL_DC_STEELWALL_1_TOPRIGHT_2,
3747 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3748 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3749 EL_DC_STEELWALL_2_LEFT,
3750 EL_DC_STEELWALL_2_RIGHT,
3751 EL_DC_STEELWALL_2_TOP,
3752 EL_DC_STEELWALL_2_BOTTOM,
3753 EL_DC_STEELWALL_2_HORIZONTAL,
3754 EL_DC_STEELWALL_2_VERTICAL,
3755 EL_DC_STEELWALL_2_MIDDLE,
3756 EL_DC_STEELWALL_2_SINGLE,
3757 EL_STEELWALL_SLIPPERY,
3771 EL_GATE_1_GRAY_ACTIVE,
3772 EL_GATE_2_GRAY_ACTIVE,
3773 EL_GATE_3_GRAY_ACTIVE,
3774 EL_GATE_4_GRAY_ACTIVE,
3783 EL_EM_GATE_1_GRAY_ACTIVE,
3784 EL_EM_GATE_2_GRAY_ACTIVE,
3785 EL_EM_GATE_3_GRAY_ACTIVE,
3786 EL_EM_GATE_4_GRAY_ACTIVE,
3788 EL_SWITCHGATE_OPENING,
3789 EL_SWITCHGATE_CLOSED,
3790 EL_SWITCHGATE_CLOSING,
3792 EL_TIMEGATE_OPENING,
3794 EL_TIMEGATE_CLOSING,
3798 EL_TUBE_VERTICAL_LEFT,
3799 EL_TUBE_VERTICAL_RIGHT,
3800 EL_TUBE_HORIZONTAL_UP,
3801 EL_TUBE_HORIZONTAL_DOWN,
3810 static int ep_classic_enemy[] =
3827 static int ep_belt[] =
3829 EL_CONVEYOR_BELT_1_LEFT,
3830 EL_CONVEYOR_BELT_1_MIDDLE,
3831 EL_CONVEYOR_BELT_1_RIGHT,
3832 EL_CONVEYOR_BELT_2_LEFT,
3833 EL_CONVEYOR_BELT_2_MIDDLE,
3834 EL_CONVEYOR_BELT_2_RIGHT,
3835 EL_CONVEYOR_BELT_3_LEFT,
3836 EL_CONVEYOR_BELT_3_MIDDLE,
3837 EL_CONVEYOR_BELT_3_RIGHT,
3838 EL_CONVEYOR_BELT_4_LEFT,
3839 EL_CONVEYOR_BELT_4_MIDDLE,
3840 EL_CONVEYOR_BELT_4_RIGHT,
3845 static int ep_belt_active[] =
3847 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3848 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3849 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3850 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3851 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3852 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3853 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3854 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3855 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3856 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3857 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3858 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3863 static int ep_belt_switch[] =
3865 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3866 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3867 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3868 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3869 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3870 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3871 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3872 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3873 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3874 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3875 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3876 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3881 static int ep_tube[] =
3888 EL_TUBE_HORIZONTAL_UP,
3889 EL_TUBE_HORIZONTAL_DOWN,
3891 EL_TUBE_VERTICAL_LEFT,
3892 EL_TUBE_VERTICAL_RIGHT,
3898 static int ep_acid_pool[] =
3900 EL_ACID_POOL_TOPLEFT,
3901 EL_ACID_POOL_TOPRIGHT,
3902 EL_ACID_POOL_BOTTOMLEFT,
3903 EL_ACID_POOL_BOTTOM,
3904 EL_ACID_POOL_BOTTOMRIGHT,
3909 static int ep_keygate[] =
3919 EL_GATE_1_GRAY_ACTIVE,
3920 EL_GATE_2_GRAY_ACTIVE,
3921 EL_GATE_3_GRAY_ACTIVE,
3922 EL_GATE_4_GRAY_ACTIVE,
3931 EL_EM_GATE_1_GRAY_ACTIVE,
3932 EL_EM_GATE_2_GRAY_ACTIVE,
3933 EL_EM_GATE_3_GRAY_ACTIVE,
3934 EL_EM_GATE_4_GRAY_ACTIVE,
3943 EL_EMC_GATE_5_GRAY_ACTIVE,
3944 EL_EMC_GATE_6_GRAY_ACTIVE,
3945 EL_EMC_GATE_7_GRAY_ACTIVE,
3946 EL_EMC_GATE_8_GRAY_ACTIVE,
3948 EL_DC_GATE_WHITE_GRAY,
3949 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3954 static int ep_amoeboid[] =
3966 static int ep_amoebalive[] =
3977 static int ep_has_editor_content[] =
3983 EL_SOKOBAN_FIELD_PLAYER,
4000 static int ep_can_turn_each_move[] =
4002 /* !!! do something with this one !!! */
4006 static int ep_can_grow[] =
4020 static int ep_active_bomb[] =
4023 EL_EM_DYNAMITE_ACTIVE,
4024 EL_DYNABOMB_PLAYER_1_ACTIVE,
4025 EL_DYNABOMB_PLAYER_2_ACTIVE,
4026 EL_DYNABOMB_PLAYER_3_ACTIVE,
4027 EL_DYNABOMB_PLAYER_4_ACTIVE,
4028 EL_SP_DISK_RED_ACTIVE,
4033 static int ep_inactive[] =
4043 EL_QUICKSAND_FAST_EMPTY,
4066 EL_GATE_1_GRAY_ACTIVE,
4067 EL_GATE_2_GRAY_ACTIVE,
4068 EL_GATE_3_GRAY_ACTIVE,
4069 EL_GATE_4_GRAY_ACTIVE,
4078 EL_EM_GATE_1_GRAY_ACTIVE,
4079 EL_EM_GATE_2_GRAY_ACTIVE,
4080 EL_EM_GATE_3_GRAY_ACTIVE,
4081 EL_EM_GATE_4_GRAY_ACTIVE,
4090 EL_EMC_GATE_5_GRAY_ACTIVE,
4091 EL_EMC_GATE_6_GRAY_ACTIVE,
4092 EL_EMC_GATE_7_GRAY_ACTIVE,
4093 EL_EMC_GATE_8_GRAY_ACTIVE,
4095 EL_DC_GATE_WHITE_GRAY,
4096 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4097 EL_DC_GATE_FAKE_GRAY,
4100 EL_INVISIBLE_STEELWALL,
4108 EL_WALL_EMERALD_YELLOW,
4109 EL_DYNABOMB_INCREASE_NUMBER,
4110 EL_DYNABOMB_INCREASE_SIZE,
4111 EL_DYNABOMB_INCREASE_POWER,
4115 EL_SOKOBAN_FIELD_EMPTY,
4116 EL_SOKOBAN_FIELD_FULL,
4117 EL_WALL_EMERALD_RED,
4118 EL_WALL_EMERALD_PURPLE,
4119 EL_ACID_POOL_TOPLEFT,
4120 EL_ACID_POOL_TOPRIGHT,
4121 EL_ACID_POOL_BOTTOMLEFT,
4122 EL_ACID_POOL_BOTTOM,
4123 EL_ACID_POOL_BOTTOMRIGHT,
4127 EL_BD_MAGIC_WALL_DEAD,
4129 EL_DC_MAGIC_WALL_DEAD,
4130 EL_AMOEBA_TO_DIAMOND,
4138 EL_SP_GRAVITY_PORT_RIGHT,
4139 EL_SP_GRAVITY_PORT_DOWN,
4140 EL_SP_GRAVITY_PORT_LEFT,
4141 EL_SP_GRAVITY_PORT_UP,
4142 EL_SP_PORT_HORIZONTAL,
4143 EL_SP_PORT_VERTICAL,
4154 EL_SP_HARDWARE_GRAY,
4155 EL_SP_HARDWARE_GREEN,
4156 EL_SP_HARDWARE_BLUE,
4158 EL_SP_HARDWARE_YELLOW,
4159 EL_SP_HARDWARE_BASE_1,
4160 EL_SP_HARDWARE_BASE_2,
4161 EL_SP_HARDWARE_BASE_3,
4162 EL_SP_HARDWARE_BASE_4,
4163 EL_SP_HARDWARE_BASE_5,
4164 EL_SP_HARDWARE_BASE_6,
4165 EL_SP_GRAVITY_ON_PORT_LEFT,
4166 EL_SP_GRAVITY_ON_PORT_RIGHT,
4167 EL_SP_GRAVITY_ON_PORT_UP,
4168 EL_SP_GRAVITY_ON_PORT_DOWN,
4169 EL_SP_GRAVITY_OFF_PORT_LEFT,
4170 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4171 EL_SP_GRAVITY_OFF_PORT_UP,
4172 EL_SP_GRAVITY_OFF_PORT_DOWN,
4173 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4174 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4175 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4176 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4177 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4178 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4179 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4180 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4181 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4182 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4183 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4184 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4185 EL_SIGN_EXCLAMATION,
4186 EL_SIGN_RADIOACTIVITY,
4193 EL_SIGN_ENTRY_FORBIDDEN,
4194 EL_SIGN_EMERGENCY_EXIT,
4202 EL_DC_STEELWALL_1_LEFT,
4203 EL_DC_STEELWALL_1_RIGHT,
4204 EL_DC_STEELWALL_1_TOP,
4205 EL_DC_STEELWALL_1_BOTTOM,
4206 EL_DC_STEELWALL_1_HORIZONTAL,
4207 EL_DC_STEELWALL_1_VERTICAL,
4208 EL_DC_STEELWALL_1_TOPLEFT,
4209 EL_DC_STEELWALL_1_TOPRIGHT,
4210 EL_DC_STEELWALL_1_BOTTOMLEFT,
4211 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4212 EL_DC_STEELWALL_1_TOPLEFT_2,
4213 EL_DC_STEELWALL_1_TOPRIGHT_2,
4214 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4215 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4216 EL_DC_STEELWALL_2_LEFT,
4217 EL_DC_STEELWALL_2_RIGHT,
4218 EL_DC_STEELWALL_2_TOP,
4219 EL_DC_STEELWALL_2_BOTTOM,
4220 EL_DC_STEELWALL_2_HORIZONTAL,
4221 EL_DC_STEELWALL_2_VERTICAL,
4222 EL_DC_STEELWALL_2_MIDDLE,
4223 EL_DC_STEELWALL_2_SINGLE,
4224 EL_STEELWALL_SLIPPERY,
4229 EL_EMC_WALL_SLIPPERY_1,
4230 EL_EMC_WALL_SLIPPERY_2,
4231 EL_EMC_WALL_SLIPPERY_3,
4232 EL_EMC_WALL_SLIPPERY_4,
4253 static int ep_em_slippery_wall[] =
4258 static int ep_gfx_crumbled[] =
4269 static int ep_editor_cascade_active[] =
4271 EL_INTERNAL_CASCADE_BD_ACTIVE,
4272 EL_INTERNAL_CASCADE_EM_ACTIVE,
4273 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4274 EL_INTERNAL_CASCADE_RND_ACTIVE,
4275 EL_INTERNAL_CASCADE_SB_ACTIVE,
4276 EL_INTERNAL_CASCADE_SP_ACTIVE,
4277 EL_INTERNAL_CASCADE_DC_ACTIVE,
4278 EL_INTERNAL_CASCADE_DX_ACTIVE,
4279 EL_INTERNAL_CASCADE_MM_ACTIVE,
4280 EL_INTERNAL_CASCADE_DF_ACTIVE,
4281 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4282 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4283 EL_INTERNAL_CASCADE_CE_ACTIVE,
4284 EL_INTERNAL_CASCADE_GE_ACTIVE,
4285 EL_INTERNAL_CASCADE_REF_ACTIVE,
4286 EL_INTERNAL_CASCADE_USER_ACTIVE,
4287 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4292 static int ep_editor_cascade_inactive[] =
4294 EL_INTERNAL_CASCADE_BD,
4295 EL_INTERNAL_CASCADE_EM,
4296 EL_INTERNAL_CASCADE_EMC,
4297 EL_INTERNAL_CASCADE_RND,
4298 EL_INTERNAL_CASCADE_SB,
4299 EL_INTERNAL_CASCADE_SP,
4300 EL_INTERNAL_CASCADE_DC,
4301 EL_INTERNAL_CASCADE_DX,
4302 EL_INTERNAL_CASCADE_MM,
4303 EL_INTERNAL_CASCADE_DF,
4304 EL_INTERNAL_CASCADE_CHARS,
4305 EL_INTERNAL_CASCADE_STEEL_CHARS,
4306 EL_INTERNAL_CASCADE_CE,
4307 EL_INTERNAL_CASCADE_GE,
4308 EL_INTERNAL_CASCADE_REF,
4309 EL_INTERNAL_CASCADE_USER,
4310 EL_INTERNAL_CASCADE_DYNAMIC,
4315 static int ep_obsolete[] =
4319 EL_EM_KEY_1_FILE_OBSOLETE,
4320 EL_EM_KEY_2_FILE_OBSOLETE,
4321 EL_EM_KEY_3_FILE_OBSOLETE,
4322 EL_EM_KEY_4_FILE_OBSOLETE,
4323 EL_ENVELOPE_OBSOLETE,
4332 } element_properties[] =
4334 { ep_diggable, EP_DIGGABLE },
4335 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4336 { ep_dont_run_into, EP_DONT_RUN_INTO },
4337 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4338 { ep_dont_touch, EP_DONT_TOUCH },
4339 { ep_indestructible, EP_INDESTRUCTIBLE },
4340 { ep_slippery, EP_SLIPPERY },
4341 { ep_can_change, EP_CAN_CHANGE },
4342 { ep_can_move, EP_CAN_MOVE },
4343 { ep_can_fall, EP_CAN_FALL },
4344 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4345 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4346 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4347 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4348 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4349 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4350 { ep_walkable_over, EP_WALKABLE_OVER },
4351 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4352 { ep_walkable_under, EP_WALKABLE_UNDER },
4353 { ep_passable_over, EP_PASSABLE_OVER },
4354 { ep_passable_inside, EP_PASSABLE_INSIDE },
4355 { ep_passable_under, EP_PASSABLE_UNDER },
4356 { ep_droppable, EP_DROPPABLE },
4357 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4358 { ep_pushable, EP_PUSHABLE },
4359 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4360 { ep_protected, EP_PROTECTED },
4361 { ep_throwable, EP_THROWABLE },
4362 { ep_can_explode, EP_CAN_EXPLODE },
4363 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4365 { ep_player, EP_PLAYER },
4366 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4367 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4368 { ep_switchable, EP_SWITCHABLE },
4369 { ep_bd_element, EP_BD_ELEMENT },
4370 { ep_sp_element, EP_SP_ELEMENT },
4371 { ep_sb_element, EP_SB_ELEMENT },
4373 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4374 { ep_food_penguin, EP_FOOD_PENGUIN },
4375 { ep_food_pig, EP_FOOD_PIG },
4376 { ep_historic_wall, EP_HISTORIC_WALL },
4377 { ep_historic_solid, EP_HISTORIC_SOLID },
4378 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4379 { ep_belt, EP_BELT },
4380 { ep_belt_active, EP_BELT_ACTIVE },
4381 { ep_belt_switch, EP_BELT_SWITCH },
4382 { ep_tube, EP_TUBE },
4383 { ep_acid_pool, EP_ACID_POOL },
4384 { ep_keygate, EP_KEYGATE },
4385 { ep_amoeboid, EP_AMOEBOID },
4386 { ep_amoebalive, EP_AMOEBALIVE },
4387 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4388 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4389 { ep_can_grow, EP_CAN_GROW },
4390 { ep_active_bomb, EP_ACTIVE_BOMB },
4391 { ep_inactive, EP_INACTIVE },
4393 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4395 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4397 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4398 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4400 { ep_obsolete, EP_OBSOLETE },
4407 /* always start with reliable default values (element has no properties) */
4408 /* (but never initialize clipboard elements after the very first time) */
4409 /* (to be able to use clipboard elements between several levels) */
4410 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4411 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4412 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4413 SET_PROPERTY(i, j, FALSE);
4415 /* set all base element properties from above array definitions */
4416 for (i = 0; element_properties[i].elements != NULL; i++)
4417 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4418 SET_PROPERTY((element_properties[i].elements)[j],
4419 element_properties[i].property, TRUE);
4421 /* copy properties to some elements that are only stored in level file */
4422 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4423 for (j = 0; copy_properties[j][0] != -1; j++)
4424 if (HAS_PROPERTY(copy_properties[j][0], i))
4425 for (k = 1; k <= 4; k++)
4426 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4428 /* set static element properties that are not listed in array definitions */
4429 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4430 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4432 clipboard_elements_initialized = TRUE;
4435 void InitElementPropertiesEngine(int engine_version)
4437 static int no_wall_properties[] =
4440 EP_COLLECTIBLE_ONLY,
4442 EP_DONT_COLLIDE_WITH,
4445 EP_CAN_SMASH_PLAYER,
4446 EP_CAN_SMASH_ENEMIES,
4447 EP_CAN_SMASH_EVERYTHING,
4452 EP_FOOD_DARK_YAMYAM,
4468 /* important: after initialization in InitElementPropertiesStatic(), the
4469 elements are not again initialized to a default value; therefore all
4470 changes have to make sure that they leave the element with a defined
4471 property (which means that conditional property changes must be set to
4472 a reliable default value before) */
4474 /* resolve group elements */
4475 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4476 ResolveGroupElement(EL_GROUP_START + i);
4478 /* set all special, combined or engine dependent element properties */
4479 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4481 /* do not change (already initialized) clipboard elements here */
4482 if (IS_CLIPBOARD_ELEMENT(i))
4485 /* ---------- INACTIVE ------------------------------------------------- */
4486 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4487 i <= EL_CHAR_END) ||
4488 (i >= EL_STEEL_CHAR_START &&
4489 i <= EL_STEEL_CHAR_END)));
4491 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4492 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4493 IS_WALKABLE_INSIDE(i) ||
4494 IS_WALKABLE_UNDER(i)));
4496 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4497 IS_PASSABLE_INSIDE(i) ||
4498 IS_PASSABLE_UNDER(i)));
4500 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4501 IS_PASSABLE_OVER(i)));
4503 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4504 IS_PASSABLE_INSIDE(i)));
4506 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4507 IS_PASSABLE_UNDER(i)));
4509 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4512 /* ---------- COLLECTIBLE ---------------------------------------------- */
4513 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4517 /* ---------- SNAPPABLE ------------------------------------------------ */
4518 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4519 IS_COLLECTIBLE(i) ||
4523 /* ---------- WALL ----------------------------------------------------- */
4524 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4526 for (j = 0; no_wall_properties[j] != -1; j++)
4527 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4528 i >= EL_FIRST_RUNTIME_UNREAL)
4529 SET_PROPERTY(i, EP_WALL, FALSE);
4531 if (IS_HISTORIC_WALL(i))
4532 SET_PROPERTY(i, EP_WALL, TRUE);
4534 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4535 if (engine_version < VERSION_IDENT(2,2,0,0))
4536 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4538 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4540 !IS_COLLECTIBLE(i)));
4542 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4543 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4544 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4546 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4547 IS_INDESTRUCTIBLE(i)));
4549 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4551 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4552 else if (engine_version < VERSION_IDENT(2,2,0,0))
4553 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4555 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4559 if (IS_CUSTOM_ELEMENT(i))
4561 /* these are additional properties which are initially false when set */
4563 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4565 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4566 if (DONT_COLLIDE_WITH(i))
4567 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4569 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4570 if (CAN_SMASH_EVERYTHING(i))
4571 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4572 if (CAN_SMASH_ENEMIES(i))
4573 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4576 /* ---------- CAN_SMASH ------------------------------------------------ */
4577 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4578 CAN_SMASH_ENEMIES(i) ||
4579 CAN_SMASH_EVERYTHING(i)));
4581 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4582 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4583 EXPLODES_BY_FIRE(i)));
4585 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4586 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4587 EXPLODES_SMASHED(i)));
4589 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4590 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4591 EXPLODES_IMPACT(i)));
4593 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4594 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4596 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4597 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4598 i == EL_BLACK_ORB));
4600 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4601 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4603 IS_CUSTOM_ELEMENT(i)));
4605 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4606 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4607 i == EL_SP_ELECTRON));
4609 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4610 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4611 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4612 getMoveIntoAcidProperty(&level, i));
4614 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4615 if (MAYBE_DONT_COLLIDE_WITH(i))
4616 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4617 getDontCollideWithProperty(&level, i));
4619 /* ---------- SP_PORT -------------------------------------------------- */
4620 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4621 IS_PASSABLE_INSIDE(i)));
4623 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4624 for (j = 0; j < level.num_android_clone_elements; j++)
4625 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4627 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4629 /* ---------- CAN_CHANGE ----------------------------------------------- */
4630 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4631 for (j = 0; j < element_info[i].num_change_pages; j++)
4632 if (element_info[i].change_page[j].can_change)
4633 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4635 /* ---------- HAS_ACTION ----------------------------------------------- */
4636 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4637 for (j = 0; j < element_info[i].num_change_pages; j++)
4638 if (element_info[i].change_page[j].has_action)
4639 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4641 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4642 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4645 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4646 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4647 element_info[i].crumbled[ACTION_DEFAULT] !=
4648 element_info[i].graphic[ACTION_DEFAULT]);
4650 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4651 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4652 IS_EDITOR_CASCADE_INACTIVE(i)));
4655 /* dynamically adjust element properties according to game engine version */
4657 static int ep_em_slippery_wall[] =
4662 EL_EXPANDABLE_WALL_HORIZONTAL,
4663 EL_EXPANDABLE_WALL_VERTICAL,
4664 EL_EXPANDABLE_WALL_ANY,
4665 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4666 EL_EXPANDABLE_STEELWALL_VERTICAL,
4667 EL_EXPANDABLE_STEELWALL_ANY,
4668 EL_EXPANDABLE_STEELWALL_GROWING,
4672 static int ep_em_explodes_by_fire[] =
4675 EL_EM_DYNAMITE_ACTIVE,
4680 /* special EM style gems behaviour */
4681 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4682 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4683 level.em_slippery_gems);
4685 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4686 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4687 (level.em_slippery_gems &&
4688 engine_version > VERSION_IDENT(2,0,1,0)));
4690 /* special EM style explosion behaviour regarding chain reactions */
4691 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4692 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4693 level.em_explodes_by_fire);
4696 /* this is needed because some graphics depend on element properties */
4697 if (game_status == GAME_MODE_PLAYING)
4698 InitElementGraphicInfo();
4701 void InitElementPropertiesGfxElement()
4705 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4707 struct ElementInfo *ei = &element_info[i];
4709 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4713 static void InitGlobal()
4718 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4720 /* check if element_name_info entry defined for each element in "main.h" */
4721 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4722 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4724 element_info[i].token_name = element_name_info[i].token_name;
4725 element_info[i].class_name = element_name_info[i].class_name;
4726 element_info[i].editor_description= element_name_info[i].editor_description;
4729 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4731 /* check if global_anim_name_info defined for each entry in "main.h" */
4732 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4733 global_anim_name_info[i].token_name == NULL)
4734 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4736 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4739 /* create hash from image config list */
4740 image_config_hash = newSetupFileHash();
4741 for (i = 0; image_config[i].token != NULL; i++)
4742 setHashEntry(image_config_hash,
4743 image_config[i].token,
4744 image_config[i].value);
4746 /* create hash from element token list */
4747 element_token_hash = newSetupFileHash();
4748 for (i = 0; element_name_info[i].token_name != NULL; i++)
4749 setHashEntry(element_token_hash,
4750 element_name_info[i].token_name,
4753 /* create hash from graphic token list */
4754 graphic_token_hash = newSetupFileHash();
4755 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4756 if (strSuffix(image_config[i].value, ".png") ||
4757 strSuffix(image_config[i].value, ".pcx") ||
4758 strSuffix(image_config[i].value, ".wav") ||
4759 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4760 setHashEntry(graphic_token_hash,
4761 image_config[i].token,
4762 int2str(graphic++, 0));
4764 /* create hash from font token list */
4765 font_token_hash = newSetupFileHash();
4766 for (i = 0; font_info[i].token_name != NULL; i++)
4767 setHashEntry(font_token_hash,
4768 font_info[i].token_name,
4771 /* set default filenames for all cloned graphics in static configuration */
4772 for (i = 0; image_config[i].token != NULL; i++)
4774 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4776 char *token = image_config[i].token;
4777 char *token_clone_from = getStringCat2(token, ".clone_from");
4778 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4780 if (token_cloned != NULL)
4782 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4784 if (value_cloned != NULL)
4786 /* set default filename in static configuration */
4787 image_config[i].value = value_cloned;
4789 /* set default filename in image config hash */
4790 setHashEntry(image_config_hash, token, value_cloned);
4794 free(token_clone_from);
4798 /* always start with reliable default values (all elements) */
4799 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4800 ActiveElement[i] = i;
4802 /* now add all entries that have an active state (active elements) */
4803 for (i = 0; element_with_active_state[i].element != -1; i++)
4805 int element = element_with_active_state[i].element;
4806 int element_active = element_with_active_state[i].element_active;
4808 ActiveElement[element] = element_active;
4811 /* always start with reliable default values (all buttons) */
4812 for (i = 0; i < NUM_IMAGE_FILES; i++)
4813 ActiveButton[i] = i;
4815 /* now add all entries that have an active state (active buttons) */
4816 for (i = 0; button_with_active_state[i].button != -1; i++)
4818 int button = button_with_active_state[i].button;
4819 int button_active = button_with_active_state[i].button_active;
4821 ActiveButton[button] = button_active;
4824 /* always start with reliable default values (all fonts) */
4825 for (i = 0; i < NUM_FONTS; i++)
4828 /* now add all entries that have an active state (active fonts) */
4829 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4831 int font = font_with_active_state[i].font_nr;
4832 int font_active = font_with_active_state[i].font_nr_active;
4834 ActiveFont[font] = font_active;
4837 global.autoplay_leveldir = NULL;
4838 global.convert_leveldir = NULL;
4839 global.create_images_dir = NULL;
4841 global.frames_per_second = 0;
4842 global.show_frames_per_second = FALSE;
4844 global.border_status = GAME_MODE_LOADING;
4845 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4847 global.use_envelope_request = FALSE;
4850 void Execute_Command(char *command)
4854 if (strEqual(command, "print graphicsinfo.conf"))
4856 Print("# You can configure additional/alternative image files here.\n");
4857 Print("# (The entries below are default and therefore commented out.)\n");
4859 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4861 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4864 for (i = 0; image_config[i].token != NULL; i++)
4865 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4866 image_config[i].value));
4870 else if (strEqual(command, "print soundsinfo.conf"))
4872 Print("# You can configure additional/alternative sound files here.\n");
4873 Print("# (The entries below are default and therefore commented out.)\n");
4875 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4877 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4880 for (i = 0; sound_config[i].token != NULL; i++)
4881 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4882 sound_config[i].value));
4886 else if (strEqual(command, "print musicinfo.conf"))
4888 Print("# You can configure additional/alternative music files here.\n");
4889 Print("# (The entries below are default and therefore commented out.)\n");
4891 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4893 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4896 for (i = 0; music_config[i].token != NULL; i++)
4897 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4898 music_config[i].value));
4902 else if (strEqual(command, "print editorsetup.conf"))
4904 Print("# You can configure your personal editor element list here.\n");
4905 Print("# (The entries below are default and therefore commented out.)\n");
4908 /* this is needed to be able to check element list for cascade elements */
4909 InitElementPropertiesStatic();
4910 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4912 PrintEditorElementList();
4916 else if (strEqual(command, "print helpanim.conf"))
4918 Print("# You can configure different element help animations here.\n");
4919 Print("# (The entries below are default and therefore commented out.)\n");
4922 for (i = 0; helpanim_config[i].token != NULL; i++)
4924 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4925 helpanim_config[i].value));
4927 if (strEqual(helpanim_config[i].token, "end"))
4933 else if (strEqual(command, "print helptext.conf"))
4935 Print("# You can configure different element help text here.\n");
4936 Print("# (The entries below are default and therefore commented out.)\n");
4939 for (i = 0; helptext_config[i].token != NULL; i++)
4940 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4941 helptext_config[i].value));
4945 else if (strPrefix(command, "dump level "))
4947 char *filename = &command[11];
4949 if (!fileExists(filename))
4950 Error(ERR_EXIT, "cannot open file '%s'", filename);
4952 LoadLevelFromFilename(&level, filename);
4957 else if (strPrefix(command, "dump tape "))
4959 char *filename = &command[10];
4961 if (!fileExists(filename))
4962 Error(ERR_EXIT, "cannot open file '%s'", filename);
4964 LoadTapeFromFilename(filename);
4969 else if (strPrefix(command, "autotest ") ||
4970 strPrefix(command, "autoplay ") ||
4971 strPrefix(command, "autoffwd ") ||
4972 strPrefix(command, "autowarp "))
4974 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4976 global.autoplay_mode =
4977 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
4978 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
4979 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
4980 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
4981 AUTOPLAY_MODE_NONE);
4983 while (*str_ptr != '\0') /* continue parsing string */
4985 /* cut leading whitespace from string, replace it by string terminator */
4986 while (*str_ptr == ' ' || *str_ptr == '\t')
4989 if (*str_ptr == '\0') /* end of string reached */
4992 if (global.autoplay_leveldir == NULL) /* read level set string */
4994 global.autoplay_leveldir = str_ptr;
4995 global.autoplay_all = TRUE; /* default: play all tapes */
4997 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4998 global.autoplay_level[i] = FALSE;
5000 else /* read level number string */
5002 int level_nr = atoi(str_ptr); /* get level_nr value */
5004 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5005 global.autoplay_level[level_nr] = TRUE;
5007 global.autoplay_all = FALSE;
5010 /* advance string pointer to the next whitespace (or end of string) */
5011 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5015 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5016 program.headless = TRUE;
5018 else if (strPrefix(command, "convert "))
5020 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5021 char *str_ptr = strchr(str_copy, ' ');
5023 global.convert_leveldir = str_copy;
5024 global.convert_level_nr = -1;
5026 if (str_ptr != NULL) /* level number follows */
5028 *str_ptr++ = '\0'; /* terminate leveldir string */
5029 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5032 program.headless = TRUE;
5034 else if (strPrefix(command, "create images "))
5036 global.create_images_dir = getStringCopy(&command[14]);
5038 if (access(global.create_images_dir, W_OK) != 0)
5039 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5040 global.create_images_dir);
5042 else if (strPrefix(command, "create CE image "))
5044 CreateCustomElementImages(&command[16]);
5050 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5054 static void InitSetup()
5056 LoadSetup(); /* global setup info */
5057 LoadSetup_AutoSetup(); /* global auto setup info */
5059 /* set some options from setup file */
5061 if (setup.options.verbose)
5062 options.verbose = TRUE;
5064 if (setup.debug.show_frames_per_second)
5065 global.show_frames_per_second = TRUE;
5068 static void InitGameInfo()
5070 game.restart_level = FALSE;
5073 static void InitPlayerInfo()
5077 /* choose default local player */
5078 local_player = &stored_player[0];
5080 for (i = 0; i < MAX_PLAYERS; i++)
5081 stored_player[i].connected = FALSE;
5083 local_player->connected = TRUE;
5086 static void InitArtworkInfo()
5091 static char *get_string_in_brackets(char *string)
5093 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5095 sprintf(string_in_brackets, "[%s]", string);
5097 return string_in_brackets;
5100 static char *get_level_id_suffix(int id_nr)
5102 char *id_suffix = checked_malloc(1 + 3 + 1);
5104 if (id_nr < 0 || id_nr > 999)
5107 sprintf(id_suffix, ".%03d", id_nr);
5112 static void InitArtworkConfig()
5114 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5116 NUM_GLOBAL_ANIM_TOKENS + 1];
5117 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5118 NUM_GLOBAL_ANIM_TOKENS + 1];
5119 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5120 NUM_GLOBAL_ANIM_TOKENS + 1];
5121 static char *action_id_suffix[NUM_ACTIONS + 1];
5122 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5123 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5124 static char *level_id_suffix[MAX_LEVELS + 1];
5125 static char *dummy[1] = { NULL };
5126 static char *ignore_generic_tokens[] =
5132 static char **ignore_image_tokens;
5133 static char **ignore_sound_tokens;
5134 static char **ignore_music_tokens;
5135 int num_ignore_generic_tokens;
5136 int num_ignore_image_tokens;
5137 int num_ignore_sound_tokens;
5138 int num_ignore_music_tokens;
5141 /* dynamically determine list of generic tokens to be ignored */
5142 num_ignore_generic_tokens = 0;
5143 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5144 num_ignore_generic_tokens++;
5146 /* dynamically determine list of image tokens to be ignored */
5147 num_ignore_image_tokens = num_ignore_generic_tokens;
5148 for (i = 0; image_config_vars[i].token != NULL; i++)
5149 num_ignore_image_tokens++;
5150 ignore_image_tokens =
5151 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5152 for (i = 0; i < num_ignore_generic_tokens; i++)
5153 ignore_image_tokens[i] = ignore_generic_tokens[i];
5154 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5155 ignore_image_tokens[num_ignore_generic_tokens + i] =
5156 image_config_vars[i].token;
5157 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5159 /* dynamically determine list of sound tokens to be ignored */
5160 num_ignore_sound_tokens = num_ignore_generic_tokens;
5161 ignore_sound_tokens =
5162 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5163 for (i = 0; i < num_ignore_generic_tokens; i++)
5164 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5165 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5167 /* dynamically determine list of music tokens to be ignored */
5168 num_ignore_music_tokens = num_ignore_generic_tokens;
5169 ignore_music_tokens =
5170 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5171 for (i = 0; i < num_ignore_generic_tokens; i++)
5172 ignore_music_tokens[i] = ignore_generic_tokens[i];
5173 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5175 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5176 image_id_prefix[i] = element_info[i].token_name;
5177 for (i = 0; i < NUM_FONTS; i++)
5178 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5179 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5180 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5181 global_anim_info[i].token_name;
5182 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5184 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5185 sound_id_prefix[i] = element_info[i].token_name;
5186 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5187 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5188 get_string_in_brackets(element_info[i].class_name);
5189 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5190 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5191 global_anim_info[i].token_name;
5192 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5194 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5195 music_id_prefix[i] = music_prefix_info[i].prefix;
5196 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5197 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5198 global_anim_info[i].token_name;
5199 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5201 for (i = 0; i < NUM_ACTIONS; i++)
5202 action_id_suffix[i] = element_action_info[i].suffix;
5203 action_id_suffix[NUM_ACTIONS] = NULL;
5205 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5206 direction_id_suffix[i] = element_direction_info[i].suffix;
5207 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5209 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5210 special_id_suffix[i] = special_suffix_info[i].suffix;
5211 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5213 for (i = 0; i < MAX_LEVELS; i++)
5214 level_id_suffix[i] = get_level_id_suffix(i);
5215 level_id_suffix[MAX_LEVELS] = NULL;
5217 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5218 image_id_prefix, action_id_suffix, direction_id_suffix,
5219 special_id_suffix, ignore_image_tokens);
5220 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5221 sound_id_prefix, action_id_suffix, dummy,
5222 special_id_suffix, ignore_sound_tokens);
5223 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5224 music_id_prefix, action_id_suffix, special_id_suffix,
5225 level_id_suffix, ignore_music_tokens);
5228 static void InitMixer()
5235 void InitGfxBuffers()
5237 static int win_xsize_last = -1;
5238 static int win_ysize_last = -1;
5240 /* create additional image buffers for double-buffering and cross-fading */
5242 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5244 /* used to temporarily store the backbuffer -- only re-create if changed */
5245 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5246 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5248 win_xsize_last = WIN_XSIZE;
5249 win_ysize_last = WIN_YSIZE;
5252 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5253 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5254 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5255 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5257 /* initialize screen properties */
5258 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5259 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5261 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5262 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5263 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5264 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5265 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5266 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5268 /* required if door size definitions have changed */
5269 InitGraphicCompatibilityInfo_Doors();
5271 InitGfxBuffers_EM();
5272 InitGfxBuffers_SP();
5277 struct GraphicInfo *graphic_info_last = graphic_info;
5278 char *filename_font_initial = NULL;
5279 char *filename_anim_initial = NULL;
5280 Bitmap *bitmap_font_initial = NULL;
5284 /* determine settings for initial font (for displaying startup messages) */
5285 for (i = 0; image_config[i].token != NULL; i++)
5287 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5289 char font_token[128];
5292 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5293 len_font_token = strlen(font_token);
5295 if (strEqual(image_config[i].token, font_token))
5296 filename_font_initial = image_config[i].value;
5297 else if (strlen(image_config[i].token) > len_font_token &&
5298 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5300 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5301 font_initial[j].src_x = atoi(image_config[i].value);
5302 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5303 font_initial[j].src_y = atoi(image_config[i].value);
5304 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5305 font_initial[j].width = atoi(image_config[i].value);
5306 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5307 font_initial[j].height = atoi(image_config[i].value);
5312 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5314 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5315 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5318 if (filename_font_initial == NULL) /* should not happen */
5319 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5322 InitGfxCustomArtworkInfo();
5323 InitGfxOtherSettings();
5325 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5327 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5328 font_initial[j].bitmap = bitmap_font_initial;
5330 InitFontGraphicInfo();
5332 font_height = getFontHeight(FC_RED);
5334 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5335 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5336 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5339 DrawInitText("Loading graphics", 120, FC_GREEN);
5341 /* initialize settings for busy animation with default values */
5342 int parameter[NUM_GFX_ARGS];
5343 for (i = 0; i < NUM_GFX_ARGS; i++)
5344 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5345 image_config_suffix[i].token,
5346 image_config_suffix[i].type);
5348 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5349 int len_anim_token = strlen(anim_token);
5351 /* read settings for busy animation from default custom artwork config */
5352 char *gfx_config_filename = getPath3(options.graphics_directory,
5354 GRAPHICSINFO_FILENAME);
5356 if (fileExists(gfx_config_filename))
5358 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5360 if (setup_file_hash)
5362 char *filename = getHashEntry(setup_file_hash, anim_token);
5366 filename_anim_initial = getStringCopy(filename);
5368 for (j = 0; image_config_suffix[j].token != NULL; j++)
5370 int type = image_config_suffix[j].type;
5371 char *suffix = image_config_suffix[j].token;
5372 char *token = getStringCat2(anim_token, suffix);
5373 char *value = getHashEntry(setup_file_hash, token);
5375 checked_free(token);
5378 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5382 freeSetupFileHash(setup_file_hash);
5386 if (filename_anim_initial == NULL)
5388 /* read settings for busy animation from static default artwork config */
5389 for (i = 0; image_config[i].token != NULL; i++)
5391 if (strEqual(image_config[i].token, anim_token))
5392 filename_anim_initial = getStringCopy(image_config[i].value);
5393 else if (strlen(image_config[i].token) > len_anim_token &&
5394 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5396 for (j = 0; image_config_suffix[j].token != NULL; j++)
5398 if (strEqual(&image_config[i].token[len_anim_token],
5399 image_config_suffix[j].token))
5401 get_graphic_parameter_value(image_config[i].value,
5402 image_config_suffix[j].token,
5403 image_config_suffix[j].type);
5409 if (filename_anim_initial == NULL) /* should not happen */
5410 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5412 anim_initial.bitmaps =
5413 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5415 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5416 LoadCustomImage(filename_anim_initial);
5418 checked_free(filename_anim_initial);
5420 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5422 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5424 graphic_info = graphic_info_last;
5426 init.busy.width = anim_initial.width;
5427 init.busy.height = anim_initial.height;
5429 InitMenuDesignSettings_Static();
5431 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5432 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5433 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5435 gfx.fade_border_source_status = global.border_status;
5436 gfx.fade_border_target_status = global.border_status;
5437 gfx.masked_border_bitmap_ptr = backbuffer;
5439 /* use copy of busy animation to prevent change while reloading artwork */
5443 void InitGfxBackground()
5445 fieldbuffer = bitmap_db_field;
5446 SetDrawtoField(DRAW_TO_BACKBUFFER);
5448 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5450 redraw_mask = REDRAW_ALL;
5453 static void InitLevelInfo()
5455 LoadLevelInfo(); /* global level info */
5456 LoadLevelSetup_LastSeries(); /* last played series info */
5457 LoadLevelSetup_SeriesInfo(); /* last played level info */
5459 if (global.autoplay_leveldir &&
5460 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5462 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5463 global.autoplay_leveldir);
5464 if (leveldir_current == NULL)
5465 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5469 static void InitLevelArtworkInfo()
5471 LoadLevelArtworkInfo();
5474 static void InitImages()
5476 print_timestamp_init("InitImages");
5479 printf("::: leveldir_current->identifier == '%s'\n",
5480 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5481 printf("::: leveldir_current->graphics_path == '%s'\n",
5482 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5483 printf("::: leveldir_current->graphics_set == '%s'\n",
5484 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5485 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5486 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5489 setLevelArtworkDir(artwork.gfx_first);
5492 printf("::: leveldir_current->identifier == '%s'\n",
5493 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5494 printf("::: leveldir_current->graphics_path == '%s'\n",
5495 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5496 printf("::: leveldir_current->graphics_set == '%s'\n",
5497 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5498 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5499 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5503 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5504 leveldir_current->identifier,
5505 artwork.gfx_current_identifier,
5506 artwork.gfx_current->identifier,
5507 leveldir_current->graphics_set,
5508 leveldir_current->graphics_path);
5511 UPDATE_BUSY_STATE();
5513 ReloadCustomImages();
5514 print_timestamp_time("ReloadCustomImages");
5516 UPDATE_BUSY_STATE();
5518 LoadCustomElementDescriptions();
5519 print_timestamp_time("LoadCustomElementDescriptions");
5521 UPDATE_BUSY_STATE();
5523 LoadMenuDesignSettings();
5524 print_timestamp_time("LoadMenuDesignSettings");
5526 UPDATE_BUSY_STATE();
5528 ReinitializeGraphics();
5529 print_timestamp_time("ReinitializeGraphics");
5531 LoadMenuDesignSettings_AfterGraphics();
5532 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5534 UPDATE_BUSY_STATE();
5536 print_timestamp_done("InitImages");
5539 static void InitSound(char *identifier)
5541 print_timestamp_init("InitSound");
5543 if (identifier == NULL)
5544 identifier = artwork.snd_current->identifier;
5546 /* set artwork path to send it to the sound server process */
5547 setLevelArtworkDir(artwork.snd_first);
5549 InitReloadCustomSounds(identifier);
5550 print_timestamp_time("InitReloadCustomSounds");
5552 ReinitializeSounds();
5553 print_timestamp_time("ReinitializeSounds");
5555 print_timestamp_done("InitSound");
5558 static void InitMusic(char *identifier)
5560 print_timestamp_init("InitMusic");
5562 if (identifier == NULL)
5563 identifier = artwork.mus_current->identifier;
5565 /* set artwork path to send it to the sound server process */
5566 setLevelArtworkDir(artwork.mus_first);
5568 InitReloadCustomMusic(identifier);
5569 print_timestamp_time("InitReloadCustomMusic");
5571 ReinitializeMusic();
5572 print_timestamp_time("ReinitializeMusic");
5574 print_timestamp_done("InitMusic");
5577 static void InitArtworkDone()
5579 if (program.headless)
5582 InitGlobalAnimations();
5585 void InitNetworkServer()
5587 #if defined(NETWORK_AVALIABLE)
5591 if (!options.network)
5594 #if defined(NETWORK_AVALIABLE)
5595 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5597 if (!ConnectToServer(options.server_host, options.server_port))
5598 Error(ERR_EXIT, "cannot connect to network game server");
5600 SendToServer_PlayerName(setup.player_name);
5601 SendToServer_ProtocolVersion();
5604 SendToServer_NrWanted(nr_wanted);
5608 static boolean CheckArtworkConfigForCustomElements(char *filename)
5610 SetupFileHash *setup_file_hash;
5611 boolean redefined_ce_found = FALSE;
5613 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5615 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5617 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5619 char *token = HASH_ITERATION_TOKEN(itr);
5621 if (strPrefix(token, "custom_"))
5623 redefined_ce_found = TRUE;
5628 END_HASH_ITERATION(setup_file_hash, itr)
5630 freeSetupFileHash(setup_file_hash);
5633 return redefined_ce_found;
5636 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5638 char *filename_base, *filename_local;
5639 boolean redefined_ce_found = FALSE;
5641 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5644 printf("::: leveldir_current->identifier == '%s'\n",
5645 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5646 printf("::: leveldir_current->graphics_path == '%s'\n",
5647 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5648 printf("::: leveldir_current->graphics_set == '%s'\n",
5649 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5650 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5651 leveldir_current == NULL ? "[NULL]" :
5652 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5655 /* first look for special artwork configured in level series config */
5656 filename_base = getCustomArtworkLevelConfigFilename(type);
5659 printf("::: filename_base == '%s'\n", filename_base);
5662 if (fileExists(filename_base))
5663 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5665 filename_local = getCustomArtworkConfigFilename(type);
5668 printf("::: filename_local == '%s'\n", filename_local);
5671 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5672 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5675 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5678 return redefined_ce_found;
5681 static void InitOverrideArtwork()
5683 boolean redefined_ce_found = FALSE;
5685 /* to check if this level set redefines any CEs, do not use overriding */
5686 gfx.override_level_graphics = FALSE;
5687 gfx.override_level_sounds = FALSE;
5688 gfx.override_level_music = FALSE;
5690 /* now check if this level set has definitions for custom elements */
5691 if (setup.override_level_graphics == AUTO ||
5692 setup.override_level_sounds == AUTO ||
5693 setup.override_level_music == AUTO)
5694 redefined_ce_found =
5695 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5696 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5697 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5700 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5703 if (redefined_ce_found)
5705 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5706 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5707 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5708 gfx.override_level_music = (setup.override_level_music == TRUE);
5712 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5713 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5714 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5715 gfx.override_level_music = (setup.override_level_music != FALSE);
5719 printf("::: => %d, %d, %d\n",
5720 gfx.override_level_graphics,
5721 gfx.override_level_sounds,
5722 gfx.override_level_music);
5726 static char *getNewArtworkIdentifier(int type)
5728 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5729 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5730 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5731 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5732 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5733 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5734 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5735 char *leveldir_identifier = leveldir_current->identifier;
5736 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5737 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5738 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5739 char *artwork_current_identifier;
5740 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5742 /* leveldir_current may be invalid (level group, parent link) */
5743 if (!validLevelSeries(leveldir_current))
5746 /* 1st step: determine artwork set to be activated in descending order:
5747 --------------------------------------------------------------------
5748 1. setup artwork (when configured to override everything else)
5749 2. artwork set configured in "levelinfo.conf" of current level set
5750 (artwork in level directory will have priority when loading later)
5751 3. artwork in level directory (stored in artwork sub-directory)
5752 4. setup artwork (currently configured in setup menu) */
5754 if (setup_override_artwork)
5755 artwork_current_identifier = setup_artwork_set;
5756 else if (leveldir_artwork_set != NULL)
5757 artwork_current_identifier = leveldir_artwork_set;
5758 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5759 artwork_current_identifier = leveldir_identifier;
5761 artwork_current_identifier = setup_artwork_set;
5764 /* 2nd step: check if it is really needed to reload artwork set
5765 ------------------------------------------------------------ */
5767 /* ---------- reload if level set and also artwork set has changed ------- */
5768 if (leveldir_current_identifier[type] != leveldir_identifier &&
5769 (last_has_level_artwork_set[type] || has_level_artwork_set))
5770 artwork_new_identifier = artwork_current_identifier;
5772 leveldir_current_identifier[type] = leveldir_identifier;
5773 last_has_level_artwork_set[type] = has_level_artwork_set;
5775 /* ---------- reload if "override artwork" setting has changed ----------- */
5776 if (last_override_level_artwork[type] != setup_override_artwork)
5777 artwork_new_identifier = artwork_current_identifier;
5779 last_override_level_artwork[type] = setup_override_artwork;
5781 /* ---------- reload if current artwork identifier has changed ----------- */
5782 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5783 artwork_current_identifier))
5784 artwork_new_identifier = artwork_current_identifier;
5786 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5788 /* ---------- do not reload directly after starting ---------------------- */
5789 if (!initialized[type])
5790 artwork_new_identifier = NULL;
5792 initialized[type] = TRUE;
5794 return artwork_new_identifier;
5797 void ReloadCustomArtwork(int force_reload)
5799 int last_game_status = game_status; /* save current game status */
5800 char *gfx_new_identifier;
5801 char *snd_new_identifier;
5802 char *mus_new_identifier;
5803 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5804 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5805 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5806 boolean reload_needed;
5808 InitOverrideArtwork();
5810 force_reload_gfx |= AdjustGraphicsForEMC();
5812 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5813 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5814 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5816 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5817 snd_new_identifier != NULL || force_reload_snd ||
5818 mus_new_identifier != NULL || force_reload_mus);
5823 print_timestamp_init("ReloadCustomArtwork");
5825 SetGameStatus(GAME_MODE_LOADING);
5827 FadeOut(REDRAW_ALL);
5829 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5830 print_timestamp_time("ClearRectangle");
5834 if (gfx_new_identifier != NULL || force_reload_gfx)
5837 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5838 artwork.gfx_current_identifier,
5840 artwork.gfx_current->identifier,
5841 leveldir_current->graphics_set);
5845 print_timestamp_time("InitImages");
5848 if (snd_new_identifier != NULL || force_reload_snd)
5850 InitSound(snd_new_identifier);
5851 print_timestamp_time("InitSound");
5854 if (mus_new_identifier != NULL || force_reload_mus)
5856 InitMusic(mus_new_identifier);
5857 print_timestamp_time("InitMusic");
5862 SetGameStatus(last_game_status); /* restore current game status */
5864 init_last = init; /* switch to new busy animation */
5866 FadeOut(REDRAW_ALL);
5868 RedrawGlobalBorder();
5870 /* force redraw of (open or closed) door graphics */
5871 SetDoorState(DOOR_OPEN_ALL);
5872 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5874 FadeSetEnterScreen();
5875 FadeSkipNextFadeOut();
5877 print_timestamp_done("ReloadCustomArtwork");
5879 LimitScreenUpdates(FALSE);
5882 void KeyboardAutoRepeatOffUnlessAutoplay()
5884 if (global.autoplay_leveldir == NULL)
5885 KeyboardAutoRepeatOff();
5888 void DisplayExitMessage(char *format, va_list ap)
5890 // also check for initialized video (headless flag may be temporarily unset)
5891 if (program.headless || !video.initialized)
5894 // check if draw buffer and fonts for exit message are already available
5895 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5898 int font_1 = FC_RED;
5899 int font_2 = FC_YELLOW;
5900 int font_3 = FC_BLUE;
5901 int font_width = getFontWidth(font_2);
5902 int font_height = getFontHeight(font_2);
5905 int sxsize = WIN_XSIZE - 2 * sx;
5906 int sysize = WIN_YSIZE - 2 * sy;
5907 int line_length = sxsize / font_width;
5908 int max_lines = sysize / font_height;
5909 int num_lines_printed;
5913 gfx.sxsize = sxsize;
5914 gfx.sysize = sysize;
5918 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5920 DrawTextSCentered(sy, font_1, "Fatal error:");
5921 sy += 3 * font_height;;
5924 DrawTextBufferVA(sx, sy, format, ap, font_2,
5925 line_length, line_length, max_lines,
5926 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5927 sy += (num_lines_printed + 3) * font_height;
5929 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5930 sy += 3 * font_height;
5933 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5934 line_length, line_length, max_lines,
5935 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5937 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5939 redraw_mask = REDRAW_ALL;
5941 /* force drawing exit message even if screen updates are currently limited */
5942 LimitScreenUpdates(FALSE);
5946 /* deactivate toons on error message screen */
5947 setup.toons = FALSE;
5949 WaitForEventToContinue();
5953 /* ========================================================================= */
5955 /* ========================================================================= */
5959 print_timestamp_init("OpenAll");
5961 SetGameStatus(GAME_MODE_LOADING);
5965 InitGlobal(); /* initialize some global variables */
5967 print_timestamp_time("[init global stuff]");
5971 print_timestamp_time("[init setup/config stuff (1)]");
5975 if (options.execute_command)
5976 Execute_Command(options.execute_command);
5978 if (options.serveronly)
5980 #if defined(PLATFORM_UNIX)
5981 NetworkServer(options.server_port, options.serveronly);
5983 Error(ERR_WARN, "networking only supported in Unix version");
5986 exit(0); /* never reached, server loops forever */
5990 print_timestamp_time("[init setup/config stuff (2)]");
5992 print_timestamp_time("[init setup/config stuff (3)]");
5993 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5994 print_timestamp_time("[init setup/config stuff (4)]");
5995 InitArtworkConfig(); /* needed before forking sound child process */
5996 print_timestamp_time("[init setup/config stuff (5)]");
5998 print_timestamp_time("[init setup/config stuff (6)]");
6000 InitRND(NEW_RANDOMIZE);
6001 InitSimpleRandom(NEW_RANDOMIZE);
6005 print_timestamp_time("[init setup/config stuff]");
6007 InitVideoDefaults();
6009 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6013 print_timestamp_time("[init video stuff]");
6015 InitElementPropertiesStatic();
6016 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6017 InitElementPropertiesGfxElement();
6019 print_timestamp_time("[init element properties stuff]");
6023 print_timestamp_time("InitGfx");
6026 print_timestamp_time("InitLevelInfo");
6028 InitLevelArtworkInfo();
6029 print_timestamp_time("InitLevelArtworkInfo");
6031 InitOverrideArtwork(); /* needs to know current level directory */
6032 print_timestamp_time("InitOverrideArtwork");
6034 InitImages(); /* needs to know current level directory */
6035 print_timestamp_time("InitImages");
6037 InitSound(NULL); /* needs to know current level directory */
6038 print_timestamp_time("InitSound");
6040 InitMusic(NULL); /* needs to know current level directory */
6041 print_timestamp_time("InitMusic");
6045 InitGfxBackground();
6051 if (global.autoplay_leveldir)
6056 else if (global.convert_leveldir)
6061 else if (global.create_images_dir)
6063 CreateLevelSketchImages();
6067 SetGameStatus(GAME_MODE_MAIN);
6069 FadeSetEnterScreen();
6070 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6071 FadeSkipNextFadeOut();
6073 print_timestamp_time("[post-artwork]");
6075 print_timestamp_done("OpenAll");
6079 InitNetworkServer();
6082 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6084 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6085 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6086 #if defined(PLATFORM_ANDROID)
6087 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6088 SDL_AndroidGetInternalStoragePath());
6089 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6090 SDL_AndroidGetExternalStoragePath());
6091 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6092 (SDL_AndroidGetExternalStorageState() &
6093 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6094 SDL_AndroidGetExternalStorageState() &
6095 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6100 void CloseAllAndExit(int exit_value)
6105 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6112 #if defined(TARGET_SDL)
6113 #if defined(TARGET_SDL2)
6115 // set a flag to tell the network server thread to quit and wait for it
6116 // using SDL_WaitThread()
6118 if (network_server) /* terminate network server */
6119 SDL_KillThread(server_thread);
6123 CloseVideoDisplay();
6124 ClosePlatformDependentStuff();
6126 if (exit_value != 0 && !options.execute_command)
6128 /* fall back to default level set (current set may have caused an error) */
6129 SaveLevelSetup_LastSeries_Deactivate();
6131 /* tell user where to find error log file which may contain more details */
6132 // (error notification now directly displayed on screen inside R'n'D
6133 // NotifyUserAboutErrorFile(); /* currently only works for Windows */