1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #include "conf_e2g.c" /* include auto-generated data structure definitions */
28 #include "conf_esg.c" /* include auto-generated data structure definitions */
29 #include "conf_e2s.c" /* include auto-generated data structure definitions */
30 #include "conf_fnt.c" /* include auto-generated data structure definitions */
31 #include "conf_g2s.c" /* include auto-generated data structure definitions */
32 #include "conf_g2m.c" /* include auto-generated data structure definitions */
33 #include "conf_act.c" /* include auto-generated data structure definitions */
36 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41 static struct GraphicInfo anim_initial;
43 static int copy_properties[][5] =
47 EL_BUG_LEFT, EL_BUG_RIGHT,
48 EL_BUG_UP, EL_BUG_DOWN
52 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
53 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
57 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
58 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
62 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
63 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
67 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
68 EL_PACMAN_UP, EL_PACMAN_DOWN
72 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
73 EL_YAMYAM_UP, EL_YAMYAM_DOWN
77 EL_MOLE_LEFT, EL_MOLE_RIGHT,
78 EL_MOLE_UP, EL_MOLE_DOWN
89 struct GraphicInfo *graphic_info_last = graphic_info;
91 static unsigned int action_delay = 0;
92 unsigned int action_delay_value = GameFrameDelay;
93 int sync_frame = FrameCounter;
96 if (game_status != GAME_MODE_LOADING)
99 if (anim_initial.bitmap == NULL || window == NULL)
102 if (!DelayReached(&action_delay, action_delay_value))
105 if (init_last.busy.x == -1)
106 init_last.busy.x = WIN_XSIZE / 2;
107 if (init_last.busy.y == -1)
108 init_last.busy.y = WIN_YSIZE / 2;
110 x = ALIGNED_TEXT_XPOS(&init_last.busy);
111 y = ALIGNED_TEXT_YPOS(&init_last.busy);
113 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
115 if (sync_frame % anim_initial.anim_delay == 0)
119 int width = graphic_info[graphic].width;
120 int height = graphic_info[graphic].height;
121 int frame = getGraphicAnimationFrame(graphic, sync_frame);
123 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
124 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
127 graphic_info = graphic_info_last;
134 FreeLevelEditorGadgets();
143 static boolean gadgets_initialized = FALSE;
145 if (gadgets_initialized)
148 CreateLevelEditorGadgets();
152 CreateScreenGadgets();
154 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
156 gadgets_initialized = TRUE;
159 inline static void InitElementSmallImagesScaledUp(int graphic)
161 struct GraphicInfo *g = &graphic_info[graphic];
163 // create small and game tile sized bitmaps (and scale up, if needed)
164 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
167 void InitElementSmallImages()
169 print_timestamp_init("InitElementSmallImages");
171 static int special_graphics[] =
185 IMG_EDITOR_ELEMENT_BORDER,
186 IMG_EDITOR_ELEMENT_BORDER_INPUT,
187 IMG_EDITOR_CASCADE_LIST,
188 IMG_EDITOR_CASCADE_LIST_ACTIVE,
191 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
192 int num_property_mappings = getImageListPropertyMappingSize();
195 print_timestamp_time("getImageListPropertyMapping/Size");
197 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
198 /* initialize normal element images from static configuration */
199 for (i = 0; element_to_graphic[i].element > -1; i++)
200 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
201 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
203 /* initialize special element images from static configuration */
204 for (i = 0; element_to_special_graphic[i].element > -1; i++)
205 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
206 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
208 /* initialize element images from dynamic configuration */
209 for (i = 0; i < num_property_mappings; i++)
210 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
211 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
212 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
214 /* initialize special non-element images from above list */
215 for (i = 0; special_graphics[i] > -1; i++)
216 InitElementSmallImagesScaledUp(special_graphics[i]);
217 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
219 print_timestamp_done("InitElementSmallImages");
222 inline static void InitScaledImagesScaledUp(int graphic)
224 struct GraphicInfo *g = &graphic_info[graphic];
226 ScaleImage(graphic, g->scale_up_factor);
229 void InitScaledImages()
231 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
232 int num_property_mappings = getImageListPropertyMappingSize();
235 /* scale normal images from static configuration, if not already scaled */
236 for (i = 0; i < NUM_IMAGE_FILES; i++)
237 InitScaledImagesScaledUp(i);
239 /* scale images from dynamic configuration, if not already scaled */
240 for (i = 0; i < num_property_mappings; i++)
241 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
244 void InitBitmapPointers()
246 int num_images = getImageListSize();
249 // standard size bitmap may have changed -- update default bitmap pointer
250 for (i = 0; i < num_images; i++)
251 if (graphic_info[i].bitmaps)
252 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
255 void InitImageTextures()
259 FreeAllImageTextures();
261 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
262 CreateImageTextures(i);
264 for (i = 0; i < MAX_NUM_TOONS; i++)
265 CreateImageTextures(IMG_TOON_1 + i);
267 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
269 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
271 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
273 int graphic = global_anim_info[i].graphic[j][k];
275 if (graphic == IMG_UNDEFINED)
278 CreateImageTextures(graphic);
285 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
286 void SetBitmaps_EM(Bitmap **em_bitmap)
288 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
289 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
294 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
295 void SetBitmaps_SP(Bitmap **sp_bitmap)
297 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
301 static int getFontBitmapID(int font_nr)
305 /* (special case: do not use special font for GAME_MODE_LOADING) */
306 if (game_status >= GAME_MODE_TITLE_INITIAL &&
307 game_status <= GAME_MODE_PSEUDO_PREVIEW)
308 special = game_status;
309 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
310 special = GFX_SPECIAL_ARG_MAIN;
313 return font_info[font_nr].special_bitmap_id[special];
318 static int getFontFromToken(char *token)
320 char *value = getHashEntry(font_token_hash, token);
325 /* if font not found, use reliable default value */
326 return FONT_INITIAL_1;
329 void InitFontGraphicInfo()
331 static struct FontBitmapInfo *font_bitmap_info = NULL;
332 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
333 int num_property_mappings = getImageListPropertyMappingSize();
334 int num_font_bitmaps = NUM_FONTS;
337 if (graphic_info == NULL) /* still at startup phase */
339 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
340 getFontBitmapID, getFontFromToken);
345 /* ---------- initialize font graphic definitions ---------- */
347 /* always start with reliable default values (normal font graphics) */
348 for (i = 0; i < NUM_FONTS; i++)
349 font_info[i].graphic = IMG_FONT_INITIAL_1;
351 /* initialize normal font/graphic mapping from static configuration */
352 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
354 int font_nr = font_to_graphic[i].font_nr;
355 int special = font_to_graphic[i].special;
356 int graphic = font_to_graphic[i].graphic;
361 font_info[font_nr].graphic = graphic;
364 /* always start with reliable default values (special font graphics) */
365 for (i = 0; i < NUM_FONTS; i++)
367 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
369 font_info[i].special_graphic[j] = font_info[i].graphic;
370 font_info[i].special_bitmap_id[j] = i;
374 /* initialize special font/graphic mapping from static configuration */
375 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
377 int font_nr = font_to_graphic[i].font_nr;
378 int special = font_to_graphic[i].special;
379 int graphic = font_to_graphic[i].graphic;
380 int base_graphic = font2baseimg(font_nr);
382 if (IS_SPECIAL_GFX_ARG(special))
384 boolean base_redefined =
385 getImageListEntryFromImageID(base_graphic)->redefined;
386 boolean special_redefined =
387 getImageListEntryFromImageID(graphic)->redefined;
388 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
390 /* if the base font ("font.title_1", for example) has been redefined,
391 but not the special font ("font.title_1.LEVELS", for example), do not
392 use an existing (in this case considered obsolete) special font
393 anymore, but use the automatically determined default font */
394 /* special case: cloned special fonts must be explicitly redefined,
395 but are not automatically redefined by redefining base font */
396 if (base_redefined && !special_redefined && !special_cloned)
399 font_info[font_nr].special_graphic[special] = graphic;
400 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
405 /* initialize special font/graphic mapping from dynamic configuration */
406 for (i = 0; i < num_property_mappings; i++)
408 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
409 int special = property_mapping[i].ext3_index;
410 int graphic = property_mapping[i].artwork_index;
415 if (IS_SPECIAL_GFX_ARG(special))
417 font_info[font_nr].special_graphic[special] = graphic;
418 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
423 /* correct special font/graphic mapping for cloned fonts for downwards
424 compatibility of PREVIEW fonts -- this is only needed for implicit
425 redefinition of special font by redefined base font, and only if other
426 fonts are cloned from this special font (like in the "Zelda" level set) */
427 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
429 int font_nr = font_to_graphic[i].font_nr;
430 int special = font_to_graphic[i].special;
431 int graphic = font_to_graphic[i].graphic;
433 if (IS_SPECIAL_GFX_ARG(special))
435 boolean special_redefined =
436 getImageListEntryFromImageID(graphic)->redefined;
437 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
439 if (special_cloned && !special_redefined)
443 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
445 int font_nr2 = font_to_graphic[j].font_nr;
446 int special2 = font_to_graphic[j].special;
447 int graphic2 = font_to_graphic[j].graphic;
449 if (IS_SPECIAL_GFX_ARG(special2) &&
450 graphic2 == graphic_info[graphic].clone_from)
452 font_info[font_nr].special_graphic[special] =
453 font_info[font_nr2].special_graphic[special2];
454 font_info[font_nr].special_bitmap_id[special] =
455 font_info[font_nr2].special_bitmap_id[special2];
462 /* reset non-redefined ".active" font graphics if normal font is redefined */
463 /* (this different treatment is needed because normal and active fonts are
464 independently defined ("active" is not a property of font definitions!) */
465 for (i = 0; i < NUM_FONTS; i++)
467 int font_nr_base = i;
468 int font_nr_active = FONT_ACTIVE(font_nr_base);
470 /* check only those fonts with exist as normal and ".active" variant */
471 if (font_nr_base != font_nr_active)
473 int base_graphic = font_info[font_nr_base].graphic;
474 int active_graphic = font_info[font_nr_active].graphic;
475 boolean base_redefined =
476 getImageListEntryFromImageID(base_graphic)->redefined;
477 boolean active_redefined =
478 getImageListEntryFromImageID(active_graphic)->redefined;
480 /* if the base font ("font.menu_1", for example) has been redefined,
481 but not the active font ("font.menu_1.active", for example), do not
482 use an existing (in this case considered obsolete) active font
483 anymore, but use the automatically determined default font */
484 if (base_redefined && !active_redefined)
485 font_info[font_nr_active].graphic = base_graphic;
487 /* now also check each "special" font (which may be the same as above) */
488 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
490 int base_graphic = font_info[font_nr_base].special_graphic[j];
491 int active_graphic = font_info[font_nr_active].special_graphic[j];
492 boolean base_redefined =
493 getImageListEntryFromImageID(base_graphic)->redefined;
494 boolean active_redefined =
495 getImageListEntryFromImageID(active_graphic)->redefined;
497 /* same as above, but check special graphic definitions, for example:
498 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
499 if (base_redefined && !active_redefined)
501 font_info[font_nr_active].special_graphic[j] =
502 font_info[font_nr_base].special_graphic[j];
503 font_info[font_nr_active].special_bitmap_id[j] =
504 font_info[font_nr_base].special_bitmap_id[j];
510 /* ---------- initialize font bitmap array ---------- */
512 if (font_bitmap_info != NULL)
513 FreeFontInfo(font_bitmap_info);
516 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
518 /* ---------- initialize font bitmap definitions ---------- */
520 for (i = 0; i < NUM_FONTS; i++)
522 if (i < NUM_INITIAL_FONTS)
524 font_bitmap_info[i] = font_initial[i];
528 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
530 int font_bitmap_id = font_info[i].special_bitmap_id[j];
531 int graphic = font_info[i].special_graphic[j];
533 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
534 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
536 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
537 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
540 /* copy font relevant information from graphics information */
541 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
542 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
543 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
544 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
545 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
547 font_bitmap_info[font_bitmap_id].draw_xoffset =
548 graphic_info[graphic].draw_xoffset;
549 font_bitmap_info[font_bitmap_id].draw_yoffset =
550 graphic_info[graphic].draw_yoffset;
552 font_bitmap_info[font_bitmap_id].num_chars =
553 graphic_info[graphic].anim_frames;
554 font_bitmap_info[font_bitmap_id].num_chars_per_line =
555 graphic_info[graphic].anim_frames_per_line;
559 InitFontInfo(font_bitmap_info, num_font_bitmaps,
560 getFontBitmapID, getFontFromToken);
563 void InitGlobalAnimGraphicInfo()
565 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
566 int num_property_mappings = getImageListPropertyMappingSize();
569 if (graphic_info == NULL) /* still at startup phase */
572 /* always start with reliable default values (no global animations) */
573 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
574 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
575 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
576 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
578 /* initialize global animation definitions from static configuration */
579 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
581 int j = GLOBAL_ANIM_ID_PART_BASE;
582 int k = GFX_SPECIAL_ARG_DEFAULT;
584 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
587 /* initialize global animation definitions from dynamic configuration */
588 for (i = 0; i < num_property_mappings; i++)
590 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
591 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
592 int special = property_mapping[i].ext3_index;
593 int graphic = property_mapping[i].artwork_index;
595 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
598 /* set animation part to base part, if not specified */
599 if (!IS_GLOBAL_ANIM_PART(part_nr))
600 part_nr = GLOBAL_ANIM_ID_PART_BASE;
602 /* set animation screen to default, if not specified */
603 if (!IS_SPECIAL_GFX_ARG(special))
604 special = GFX_SPECIAL_ARG_DEFAULT;
606 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
610 printf("::: InitGlobalAnimGraphicInfo\n");
612 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
613 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
614 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
615 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
616 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
617 printf("::: - anim %d, part %d, mode %d => %d\n",
618 i, j, k, global_anim_info[i].graphic[j][k]);
622 void InitGlobalAnimSoundInfo()
624 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
625 int num_property_mappings = getSoundListPropertyMappingSize();
628 /* always start with reliable default values (no global animation sounds) */
629 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
630 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
631 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
632 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
634 /* initialize global animation sound definitions from dynamic configuration */
635 for (i = 0; i < num_property_mappings; i++)
637 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
638 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
639 int special = property_mapping[i].ext3_index;
640 int sound = property_mapping[i].artwork_index;
642 // sound uses control definition; map it to position of graphic (artwork)
643 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
645 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
648 /* set animation part to base part, if not specified */
649 if (!IS_GLOBAL_ANIM_PART(part_nr))
650 part_nr = GLOBAL_ANIM_ID_PART_BASE;
652 /* set animation screen to default, if not specified */
653 if (!IS_SPECIAL_GFX_ARG(special))
654 special = GFX_SPECIAL_ARG_DEFAULT;
656 global_anim_info[anim_nr].sound[part_nr][special] = sound;
660 printf("::: InitGlobalAnimSoundInfo\n");
662 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
663 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
664 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
665 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
666 printf("::: - anim %d, part %d, mode %d => %d\n",
667 i, j, k, global_anim_info[i].sound[j][k]);
671 void InitGlobalAnimMusicInfo()
673 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
674 int num_property_mappings = getMusicListPropertyMappingSize();
677 /* always start with reliable default values (no global animation music) */
678 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
679 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
680 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
681 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
683 /* initialize global animation music definitions from dynamic configuration */
684 for (i = 0; i < num_property_mappings; i++)
686 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
687 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
688 int special = property_mapping[i].ext2_index;
689 int music = property_mapping[i].artwork_index;
691 // music uses control definition; map it to position of graphic (artwork)
692 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
694 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
697 /* set animation part to base part, if not specified */
698 if (!IS_GLOBAL_ANIM_PART(part_nr))
699 part_nr = GLOBAL_ANIM_ID_PART_BASE;
701 /* set animation screen to default, if not specified */
702 if (!IS_SPECIAL_GFX_ARG(special))
703 special = GFX_SPECIAL_ARG_DEFAULT;
705 global_anim_info[anim_nr].music[part_nr][special] = music;
709 printf("::: InitGlobalAnimMusicInfo\n");
711 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
712 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
713 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
714 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
715 printf("::: - anim %d, part %d, mode %d => %d\n",
716 i, j, k, global_anim_info[i].music[j][k]);
720 void InitElementGraphicInfo()
722 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
723 int num_property_mappings = getImageListPropertyMappingSize();
726 if (graphic_info == NULL) /* still at startup phase */
729 /* set values to -1 to identify later as "uninitialized" values */
730 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
732 for (act = 0; act < NUM_ACTIONS; act++)
734 element_info[i].graphic[act] = -1;
735 element_info[i].crumbled[act] = -1;
737 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
739 element_info[i].direction_graphic[act][dir] = -1;
740 element_info[i].direction_crumbled[act][dir] = -1;
747 /* initialize normal element/graphic mapping from static configuration */
748 for (i = 0; element_to_graphic[i].element > -1; i++)
750 int element = element_to_graphic[i].element;
751 int action = element_to_graphic[i].action;
752 int direction = element_to_graphic[i].direction;
753 boolean crumbled = element_to_graphic[i].crumbled;
754 int graphic = element_to_graphic[i].graphic;
755 int base_graphic = el2baseimg(element);
757 if (graphic_info[graphic].bitmap == NULL)
760 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
763 boolean base_redefined =
764 getImageListEntryFromImageID(base_graphic)->redefined;
765 boolean act_dir_redefined =
766 getImageListEntryFromImageID(graphic)->redefined;
768 /* if the base graphic ("emerald", for example) has been redefined,
769 but not the action graphic ("emerald.falling", for example), do not
770 use an existing (in this case considered obsolete) action graphic
771 anymore, but use the automatically determined default graphic */
772 if (base_redefined && !act_dir_redefined)
777 action = ACTION_DEFAULT;
782 element_info[element].direction_crumbled[action][direction] = graphic;
784 element_info[element].crumbled[action] = graphic;
789 element_info[element].direction_graphic[action][direction] = graphic;
791 element_info[element].graphic[action] = graphic;
795 /* initialize normal element/graphic mapping from dynamic configuration */
796 for (i = 0; i < num_property_mappings; i++)
798 int element = property_mapping[i].base_index;
799 int action = property_mapping[i].ext1_index;
800 int direction = property_mapping[i].ext2_index;
801 int special = property_mapping[i].ext3_index;
802 int graphic = property_mapping[i].artwork_index;
803 boolean crumbled = FALSE;
805 if (special == GFX_SPECIAL_ARG_CRUMBLED)
811 if (graphic_info[graphic].bitmap == NULL)
814 if (element >= MAX_NUM_ELEMENTS || special != -1)
818 action = ACTION_DEFAULT;
823 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
824 element_info[element].direction_crumbled[action][dir] = -1;
827 element_info[element].direction_crumbled[action][direction] = graphic;
829 element_info[element].crumbled[action] = graphic;
834 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
835 element_info[element].direction_graphic[action][dir] = -1;
838 element_info[element].direction_graphic[action][direction] = graphic;
840 element_info[element].graphic[action] = graphic;
844 /* now copy all graphics that are defined to be cloned from other graphics */
845 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
847 int graphic = element_info[i].graphic[ACTION_DEFAULT];
848 int crumbled_like, diggable_like;
853 crumbled_like = graphic_info[graphic].crumbled_like;
854 diggable_like = graphic_info[graphic].diggable_like;
856 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
858 for (act = 0; act < NUM_ACTIONS; act++)
859 element_info[i].crumbled[act] =
860 element_info[crumbled_like].crumbled[act];
861 for (act = 0; act < NUM_ACTIONS; act++)
862 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
863 element_info[i].direction_crumbled[act][dir] =
864 element_info[crumbled_like].direction_crumbled[act][dir];
867 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
869 element_info[i].graphic[ACTION_DIGGING] =
870 element_info[diggable_like].graphic[ACTION_DIGGING];
871 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
872 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
873 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
877 /* set hardcoded definitions for some runtime elements without graphic */
878 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
880 /* set hardcoded definitions for some internal elements without graphic */
881 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
883 if (IS_EDITOR_CASCADE_INACTIVE(i))
884 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
885 else if (IS_EDITOR_CASCADE_ACTIVE(i))
886 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
889 /* now set all undefined/invalid graphics to -1 to set to default after it */
890 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
892 for (act = 0; act < NUM_ACTIONS; act++)
896 graphic = element_info[i].graphic[act];
897 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
898 element_info[i].graphic[act] = -1;
900 graphic = element_info[i].crumbled[act];
901 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
902 element_info[i].crumbled[act] = -1;
904 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
906 graphic = element_info[i].direction_graphic[act][dir];
907 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
908 element_info[i].direction_graphic[act][dir] = -1;
910 graphic = element_info[i].direction_crumbled[act][dir];
911 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
912 element_info[i].direction_crumbled[act][dir] = -1;
919 /* adjust graphics with 2nd tile for movement according to direction
920 (do this before correcting '-1' values to minimize calculations) */
921 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
923 for (act = 0; act < NUM_ACTIONS; act++)
925 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
927 int graphic = element_info[i].direction_graphic[act][dir];
928 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
930 if (act == ACTION_FALLING) /* special case */
931 graphic = element_info[i].graphic[act];
934 graphic_info[graphic].double_movement &&
935 graphic_info[graphic].swap_double_tiles != 0)
937 struct GraphicInfo *g = &graphic_info[graphic];
938 int src_x_front = g->src_x;
939 int src_y_front = g->src_y;
940 int src_x_back = g->src_x + g->offset2_x;
941 int src_y_back = g->src_y + g->offset2_y;
942 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
944 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
945 src_y_front < src_y_back);
946 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
947 boolean swap_movement_tiles_autodetected =
948 (!frames_are_ordered_diagonally &&
949 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
950 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
951 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
952 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
954 /* swap frontside and backside graphic tile coordinates, if needed */
955 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
957 /* get current (wrong) backside tile coordinates */
958 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
960 /* set frontside tile coordinates to backside tile coordinates */
961 g->src_x = src_x_back;
962 g->src_y = src_y_back;
964 /* invert tile offset to point to new backside tile coordinates */
968 /* do not swap front and backside tiles again after correction */
969 g->swap_double_tiles = 0;
978 /* now set all '-1' values to element specific default values */
979 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
981 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
982 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
983 int default_direction_graphic[NUM_DIRECTIONS_FULL];
984 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
986 if (default_graphic == -1)
987 default_graphic = IMG_UNKNOWN;
989 if (default_crumbled == -1)
990 default_crumbled = default_graphic;
992 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
994 default_direction_graphic[dir] =
995 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
996 default_direction_crumbled[dir] =
997 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
999 if (default_direction_graphic[dir] == -1)
1000 default_direction_graphic[dir] = default_graphic;
1002 if (default_direction_crumbled[dir] == -1)
1003 default_direction_crumbled[dir] = default_direction_graphic[dir];
1006 for (act = 0; act < NUM_ACTIONS; act++)
1008 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1009 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1010 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1011 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1012 act == ACTION_TURNING_FROM_RIGHT ||
1013 act == ACTION_TURNING_FROM_UP ||
1014 act == ACTION_TURNING_FROM_DOWN);
1016 /* generic default action graphic (defined by "[default]" directive) */
1017 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1018 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1019 int default_remove_graphic = IMG_EMPTY;
1021 if (act_remove && default_action_graphic != -1)
1022 default_remove_graphic = default_action_graphic;
1024 /* look for special default action graphic (classic game specific) */
1025 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1026 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1027 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1028 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1029 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1030 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1032 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1033 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1034 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1035 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1036 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1037 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1039 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1040 /* !!! make this better !!! */
1041 if (i == EL_EMPTY_SPACE)
1043 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1044 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1047 if (default_action_graphic == -1)
1048 default_action_graphic = default_graphic;
1050 if (default_action_crumbled == -1)
1051 default_action_crumbled = default_action_graphic;
1053 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1055 /* use action graphic as the default direction graphic, if undefined */
1056 int default_action_direction_graphic = element_info[i].graphic[act];
1057 int default_action_direction_crumbled = element_info[i].crumbled[act];
1059 /* no graphic for current action -- use default direction graphic */
1060 if (default_action_direction_graphic == -1)
1061 default_action_direction_graphic =
1062 (act_remove ? default_remove_graphic :
1064 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1065 default_action_graphic != default_graphic ?
1066 default_action_graphic :
1067 default_direction_graphic[dir]);
1069 if (element_info[i].direction_graphic[act][dir] == -1)
1070 element_info[i].direction_graphic[act][dir] =
1071 default_action_direction_graphic;
1073 if (default_action_direction_crumbled == -1)
1074 default_action_direction_crumbled =
1075 element_info[i].direction_graphic[act][dir];
1077 if (element_info[i].direction_crumbled[act][dir] == -1)
1078 element_info[i].direction_crumbled[act][dir] =
1079 default_action_direction_crumbled;
1082 /* no graphic for this specific action -- use default action graphic */
1083 if (element_info[i].graphic[act] == -1)
1084 element_info[i].graphic[act] =
1085 (act_remove ? default_remove_graphic :
1086 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1087 default_action_graphic);
1089 if (element_info[i].crumbled[act] == -1)
1090 element_info[i].crumbled[act] = element_info[i].graphic[act];
1094 UPDATE_BUSY_STATE();
1097 void InitElementSpecialGraphicInfo()
1099 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1100 int num_property_mappings = getImageListPropertyMappingSize();
1103 /* always start with reliable default values */
1104 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1105 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1106 element_info[i].special_graphic[j] =
1107 element_info[i].graphic[ACTION_DEFAULT];
1109 /* initialize special element/graphic mapping from static configuration */
1110 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1112 int element = element_to_special_graphic[i].element;
1113 int special = element_to_special_graphic[i].special;
1114 int graphic = element_to_special_graphic[i].graphic;
1115 int base_graphic = el2baseimg(element);
1116 boolean base_redefined =
1117 getImageListEntryFromImageID(base_graphic)->redefined;
1118 boolean special_redefined =
1119 getImageListEntryFromImageID(graphic)->redefined;
1121 /* if the base graphic ("emerald", for example) has been redefined,
1122 but not the special graphic ("emerald.EDITOR", for example), do not
1123 use an existing (in this case considered obsolete) special graphic
1124 anymore, but use the automatically created (down-scaled) graphic */
1125 if (base_redefined && !special_redefined)
1128 element_info[element].special_graphic[special] = graphic;
1131 /* initialize special element/graphic mapping from dynamic configuration */
1132 for (i = 0; i < num_property_mappings; i++)
1134 int element = property_mapping[i].base_index;
1135 int action = property_mapping[i].ext1_index;
1136 int direction = property_mapping[i].ext2_index;
1137 int special = property_mapping[i].ext3_index;
1138 int graphic = property_mapping[i].artwork_index;
1140 /* for action ".active", replace element with active element, if exists */
1141 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1143 element = ELEMENT_ACTIVE(element);
1147 if (element >= MAX_NUM_ELEMENTS)
1150 /* do not change special graphic if action or direction was specified */
1151 if (action != -1 || direction != -1)
1154 if (IS_SPECIAL_GFX_ARG(special))
1155 element_info[element].special_graphic[special] = graphic;
1158 /* now set all undefined/invalid graphics to default */
1159 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1160 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1161 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1162 element_info[i].special_graphic[j] =
1163 element_info[i].graphic[ACTION_DEFAULT];
1166 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1168 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1169 return get_parameter_value(value_raw, suffix, type);
1171 if (strEqual(value_raw, ARG_UNDEFINED))
1172 return ARG_UNDEFINED_VALUE;
1174 if (type == TYPE_ELEMENT)
1176 char *value = getHashEntry(element_token_hash, value_raw);
1180 Error(ERR_INFO_LINE, "-");
1181 Error(ERR_INFO, "warning: error found in config file:");
1182 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1183 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1184 Error(ERR_INFO, "custom graphic rejected for this element/action");
1185 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1186 Error(ERR_INFO_LINE, "-");
1189 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1191 else if (type == TYPE_GRAPHIC)
1193 char *value = getHashEntry(graphic_token_hash, value_raw);
1194 int fallback_graphic = IMG_CHAR_EXCLAM;
1198 Error(ERR_INFO_LINE, "-");
1199 Error(ERR_INFO, "warning: error found in config file:");
1200 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1201 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1202 Error(ERR_INFO, "custom graphic rejected for this element/action");
1203 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1204 Error(ERR_INFO_LINE, "-");
1207 return (value != NULL ? atoi(value) : fallback_graphic);
1213 static int get_scaled_graphic_width(int graphic)
1215 int original_width = getOriginalImageWidthFromImageID(graphic);
1216 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1218 return original_width * scale_up_factor;
1221 static int get_scaled_graphic_height(int graphic)
1223 int original_height = getOriginalImageHeightFromImageID(graphic);
1224 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1226 return original_height * scale_up_factor;
1229 static void set_graphic_parameters_ext(int graphic, int *parameter,
1230 Bitmap **src_bitmaps)
1232 struct GraphicInfo *g = &graphic_info[graphic];
1233 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1234 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1235 int anim_frames_per_line = 1;
1237 /* always start with reliable default values */
1238 g->src_image_width = 0;
1239 g->src_image_height = 0;
1242 g->width = TILEX; /* default for element graphics */
1243 g->height = TILEY; /* default for element graphics */
1244 g->offset_x = 0; /* one or both of these values ... */
1245 g->offset_y = 0; /* ... will be corrected later */
1246 g->offset2_x = 0; /* one or both of these values ... */
1247 g->offset2_y = 0; /* ... will be corrected later */
1248 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1249 g->crumbled_like = -1; /* do not use clone element */
1250 g->diggable_like = -1; /* do not use clone element */
1251 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1252 g->scale_up_factor = 1; /* default: no scaling up */
1253 g->tile_size = TILESIZE; /* default: standard tile size */
1254 g->clone_from = -1; /* do not use clone graphic */
1255 g->init_delay_fixed = 0;
1256 g->init_delay_random = 0;
1257 g->anim_delay_fixed = 0;
1258 g->anim_delay_random = 0;
1259 g->post_delay_fixed = 0;
1260 g->post_delay_random = 0;
1262 g->fade_mode = FADE_MODE_DEFAULT;
1266 g->align = ALIGN_CENTER; /* default for title screens */
1267 g->valign = VALIGN_MIDDLE; /* default for title screens */
1268 g->sort_priority = 0; /* default for title screens */
1270 g->style = STYLE_DEFAULT;
1272 g->bitmaps = src_bitmaps;
1273 g->bitmap = src_bitmap;
1275 /* optional zoom factor for scaling up the image to a larger size */
1276 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1277 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1278 if (g->scale_up_factor < 1)
1279 g->scale_up_factor = 1; /* no scaling */
1281 /* optional tile size for using non-standard image size */
1282 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1284 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1287 // CHECK: should tile sizes less than standard tile size be allowed?
1288 if (g->tile_size < TILESIZE)
1289 g->tile_size = TILESIZE; /* standard tile size */
1292 // when setting tile size, also set width and height accordingly
1293 g->width = g->tile_size;
1294 g->height = g->tile_size;
1297 if (g->use_image_size)
1299 /* set new default bitmap size (with scaling, but without small images) */
1300 g->width = get_scaled_graphic_width(graphic);
1301 g->height = get_scaled_graphic_height(graphic);
1304 /* optional width and height of each animation frame */
1305 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1306 g->width = parameter[GFX_ARG_WIDTH];
1307 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1308 g->height = parameter[GFX_ARG_HEIGHT];
1310 /* optional x and y tile position of animation frame sequence */
1311 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1312 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1313 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1314 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1316 /* optional x and y pixel position of animation frame sequence */
1317 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1318 g->src_x = parameter[GFX_ARG_X];
1319 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1320 g->src_y = parameter[GFX_ARG_Y];
1326 Error(ERR_INFO_LINE, "-");
1327 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1328 g->width, getTokenFromImageID(graphic), TILEX);
1329 Error(ERR_INFO_LINE, "-");
1331 g->width = TILEX; /* will be checked to be inside bitmap later */
1336 Error(ERR_INFO_LINE, "-");
1337 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1338 g->height, getTokenFromImageID(graphic), TILEY);
1339 Error(ERR_INFO_LINE, "-");
1341 g->height = TILEY; /* will be checked to be inside bitmap later */
1347 /* get final bitmap size (with scaling, but without small images) */
1348 int src_image_width = get_scaled_graphic_width(graphic);
1349 int src_image_height = get_scaled_graphic_height(graphic);
1351 if (src_image_width == 0 || src_image_height == 0)
1353 /* only happens when loaded outside artwork system (like "global.busy") */
1354 src_image_width = src_bitmap->width;
1355 src_image_height = src_bitmap->height;
1358 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1360 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1361 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1365 anim_frames_per_row = MAX(1, src_image_width / g->width);
1366 anim_frames_per_col = MAX(1, src_image_height / g->height);
1369 g->src_image_width = src_image_width;
1370 g->src_image_height = src_image_height;
1373 /* correct x or y offset dependent of vertical or horizontal frame order */
1374 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1376 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1377 parameter[GFX_ARG_OFFSET] : g->height);
1378 anim_frames_per_line = anim_frames_per_col;
1380 else /* frames are ordered horizontally */
1382 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1383 parameter[GFX_ARG_OFFSET] : g->width);
1384 anim_frames_per_line = anim_frames_per_row;
1387 /* optionally, the x and y offset of frames can be specified directly */
1388 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1389 g->offset_x = parameter[GFX_ARG_XOFFSET];
1390 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1391 g->offset_y = parameter[GFX_ARG_YOFFSET];
1393 /* optionally, moving animations may have separate start and end graphics */
1394 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1396 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1397 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1399 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1400 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1401 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1402 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1403 else /* frames are ordered horizontally */
1404 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1405 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1407 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1408 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1409 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1410 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1411 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1413 /* optionally, the second movement tile can be specified as start tile */
1414 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1415 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1417 /* automatically determine correct number of frames, if not defined */
1418 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1419 g->anim_frames = parameter[GFX_ARG_FRAMES];
1420 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1421 g->anim_frames = anim_frames_per_row;
1422 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1423 g->anim_frames = anim_frames_per_col;
1427 if (g->anim_frames == 0) /* frames must be at least 1 */
1430 g->anim_frames_per_line =
1431 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1432 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1434 g->anim_delay = parameter[GFX_ARG_DELAY];
1435 if (g->anim_delay == 0) /* delay must be at least 1 */
1438 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1440 /* automatically determine correct start frame, if not defined */
1441 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1442 g->anim_start_frame = 0;
1443 else if (g->anim_mode & ANIM_REVERSE)
1444 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1446 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1448 /* animation synchronized with global frame counter, not move position */
1449 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1451 /* optional element for cloning crumble graphics */
1452 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1453 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1455 /* optional element for cloning digging graphics */
1456 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1457 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1459 /* optional border size for "crumbling" diggable graphics */
1460 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1461 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1463 /* used for global animations and player "boring" and "sleeping" actions */
1464 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1465 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1466 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1467 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1468 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1469 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1470 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1471 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1472 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1473 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1474 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1475 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1477 /* used for toon animations and global animations */
1478 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1479 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1480 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1481 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1482 g->direction = parameter[GFX_ARG_DIRECTION];
1483 g->position = parameter[GFX_ARG_POSITION];
1484 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1485 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1487 /* this is only used for drawing font characters */
1488 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1489 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1491 /* this is only used for drawing envelope graphics */
1492 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1494 /* used for toon animations and global animations */
1495 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1496 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1498 /* optional graphic for cloning all graphics settings */
1499 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1500 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1502 /* optional settings for drawing title screens and title messages */
1503 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1504 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1505 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1506 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1507 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1508 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1509 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1510 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1511 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1512 g->align = parameter[GFX_ARG_ALIGN];
1513 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1514 g->valign = parameter[GFX_ARG_VALIGN];
1515 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1516 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1518 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1519 g->class = parameter[GFX_ARG_CLASS];
1520 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1521 g->style = parameter[GFX_ARG_STYLE];
1523 /* this is only used for drawing menu buttons and text */
1524 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1525 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1526 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1527 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1530 static void set_graphic_parameters(int graphic)
1532 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1533 char **parameter_raw = image->parameter;
1534 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1535 int parameter[NUM_GFX_ARGS];
1538 /* if fallback to default artwork is done, also use the default parameters */
1539 if (image->fallback_to_default)
1540 parameter_raw = image->default_parameter;
1542 /* get integer values from string parameters */
1543 for (i = 0; i < NUM_GFX_ARGS; i++)
1544 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1545 image_config_suffix[i].token,
1546 image_config_suffix[i].type);
1548 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1550 UPDATE_BUSY_STATE();
1553 static void set_cloned_graphic_parameters(int graphic)
1555 int fallback_graphic = IMG_CHAR_EXCLAM;
1556 int max_num_images = getImageListSize();
1557 int clone_graphic = graphic_info[graphic].clone_from;
1558 int num_references_followed = 1;
1560 while (graphic_info[clone_graphic].clone_from != -1 &&
1561 num_references_followed < max_num_images)
1563 clone_graphic = graphic_info[clone_graphic].clone_from;
1565 num_references_followed++;
1568 if (num_references_followed >= max_num_images)
1570 Error(ERR_INFO_LINE, "-");
1571 Error(ERR_INFO, "warning: error found in config file:");
1572 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1573 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1574 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1575 Error(ERR_INFO, "custom graphic rejected for this element/action");
1577 if (graphic == fallback_graphic)
1578 Error(ERR_EXIT, "no fallback graphic available");
1580 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1581 Error(ERR_INFO_LINE, "-");
1583 graphic_info[graphic] = graphic_info[fallback_graphic];
1587 graphic_info[graphic] = graphic_info[clone_graphic];
1588 graphic_info[graphic].clone_from = clone_graphic;
1592 static void InitGraphicInfo()
1594 int fallback_graphic = IMG_CHAR_EXCLAM;
1595 int num_images = getImageListSize();
1598 /* use image size as default values for width and height for these images */
1599 static int full_size_graphics[] =
1602 IMG_GLOBAL_BORDER_MAIN,
1603 IMG_GLOBAL_BORDER_SCORES,
1604 IMG_GLOBAL_BORDER_EDITOR,
1605 IMG_GLOBAL_BORDER_PLAYING,
1608 IMG_BACKGROUND_ENVELOPE_1,
1609 IMG_BACKGROUND_ENVELOPE_2,
1610 IMG_BACKGROUND_ENVELOPE_3,
1611 IMG_BACKGROUND_ENVELOPE_4,
1612 IMG_BACKGROUND_REQUEST,
1615 IMG_BACKGROUND_TITLE_INITIAL,
1616 IMG_BACKGROUND_TITLE,
1617 IMG_BACKGROUND_MAIN,
1618 IMG_BACKGROUND_LEVELS,
1619 IMG_BACKGROUND_LEVELNR,
1620 IMG_BACKGROUND_SCORES,
1621 IMG_BACKGROUND_EDITOR,
1622 IMG_BACKGROUND_INFO,
1623 IMG_BACKGROUND_INFO_ELEMENTS,
1624 IMG_BACKGROUND_INFO_MUSIC,
1625 IMG_BACKGROUND_INFO_CREDITS,
1626 IMG_BACKGROUND_INFO_PROGRAM,
1627 IMG_BACKGROUND_INFO_VERSION,
1628 IMG_BACKGROUND_INFO_LEVELSET,
1629 IMG_BACKGROUND_SETUP,
1630 IMG_BACKGROUND_PLAYING,
1631 IMG_BACKGROUND_DOOR,
1632 IMG_BACKGROUND_TAPE,
1633 IMG_BACKGROUND_PANEL,
1634 IMG_BACKGROUND_PALETTE,
1635 IMG_BACKGROUND_TOOLBOX,
1637 IMG_TITLESCREEN_INITIAL_1,
1638 IMG_TITLESCREEN_INITIAL_2,
1639 IMG_TITLESCREEN_INITIAL_3,
1640 IMG_TITLESCREEN_INITIAL_4,
1641 IMG_TITLESCREEN_INITIAL_5,
1648 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1649 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1650 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1651 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1652 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1653 IMG_BACKGROUND_TITLEMESSAGE_1,
1654 IMG_BACKGROUND_TITLEMESSAGE_2,
1655 IMG_BACKGROUND_TITLEMESSAGE_3,
1656 IMG_BACKGROUND_TITLEMESSAGE_4,
1657 IMG_BACKGROUND_TITLEMESSAGE_5,
1662 checked_free(graphic_info);
1664 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1666 /* initialize "use_image_size" flag with default value */
1667 for (i = 0; i < num_images; i++)
1668 graphic_info[i].use_image_size = FALSE;
1670 /* initialize "use_image_size" flag from static configuration above */
1671 for (i = 0; full_size_graphics[i] != -1; i++)
1672 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1674 /* first set all graphic paramaters ... */
1675 for (i = 0; i < num_images; i++)
1676 set_graphic_parameters(i);
1678 /* ... then copy these parameters for cloned graphics */
1679 for (i = 0; i < num_images; i++)
1680 if (graphic_info[i].clone_from != -1)
1681 set_cloned_graphic_parameters(i);
1683 for (i = 0; i < num_images; i++)
1688 int first_frame, last_frame;
1689 int src_bitmap_width, src_bitmap_height;
1691 /* now check if no animation frames are outside of the loaded image */
1693 if (graphic_info[i].bitmap == NULL)
1694 continue; /* skip check for optional images that are undefined */
1696 /* get image size (this can differ from the standard element tile size!) */
1697 width = graphic_info[i].width;
1698 height = graphic_info[i].height;
1700 /* get final bitmap size (with scaling, but without small images) */
1701 src_bitmap_width = graphic_info[i].src_image_width;
1702 src_bitmap_height = graphic_info[i].src_image_height;
1704 /* check if first animation frame is inside specified bitmap */
1707 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1709 /* this avoids calculating wrong start position for out-of-bounds frame */
1710 src_x = graphic_info[i].src_x;
1711 src_y = graphic_info[i].src_y;
1713 if (program.headless)
1716 if (src_x < 0 || src_y < 0 ||
1717 src_x + width > src_bitmap_width ||
1718 src_y + height > src_bitmap_height)
1720 Error(ERR_INFO_LINE, "-");
1721 Error(ERR_INFO, "warning: error found in config file:");
1722 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1723 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1724 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1725 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1727 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1728 src_x, src_y, src_bitmap_width, src_bitmap_height);
1729 Error(ERR_INFO, "custom graphic rejected for this element/action");
1731 if (i == fallback_graphic)
1732 Error(ERR_EXIT, "no fallback graphic available");
1734 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1735 Error(ERR_INFO_LINE, "-");
1737 graphic_info[i] = graphic_info[fallback_graphic];
1740 /* check if last animation frame is inside specified bitmap */
1742 last_frame = graphic_info[i].anim_frames - 1;
1743 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1745 if (src_x < 0 || src_y < 0 ||
1746 src_x + width > src_bitmap_width ||
1747 src_y + height > src_bitmap_height)
1749 Error(ERR_INFO_LINE, "-");
1750 Error(ERR_INFO, "warning: error found in config file:");
1751 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1752 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1753 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1754 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1756 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1757 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1758 Error(ERR_INFO, "custom graphic rejected for this element/action");
1760 if (i == fallback_graphic)
1761 Error(ERR_EXIT, "no fallback graphic available");
1763 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1764 Error(ERR_INFO_LINE, "-");
1766 graphic_info[i] = graphic_info[fallback_graphic];
1771 static void InitGraphicCompatibilityInfo()
1773 struct FileInfo *fi_global_door =
1774 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1775 int num_images = getImageListSize();
1778 /* the following compatibility handling is needed for the following case:
1779 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1780 graphics mainly used for door and panel graphics, like editor, tape and
1781 in-game buttons with hard-coded bitmap positions and button sizes; as
1782 these graphics now have individual definitions, redefining "global.door"
1783 to change all these graphics at once like before does not work anymore
1784 (because all those individual definitions still have their default values);
1785 to solve this, remap all those individual definitions that are not
1786 redefined to the new bitmap of "global.door" if it was redefined */
1788 /* special compatibility handling if image "global.door" was redefined */
1789 if (fi_global_door->redefined)
1791 for (i = 0; i < num_images; i++)
1793 struct FileInfo *fi = getImageListEntryFromImageID(i);
1795 /* process only those images that still use the default settings */
1798 /* process all images which default to same image as "global.door" */
1799 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1801 // printf("::: special treatment needed for token '%s'\n", fi->token);
1803 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1804 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1810 InitGraphicCompatibilityInfo_Doors();
1813 static void InitElementSoundInfo()
1815 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1816 int num_property_mappings = getSoundListPropertyMappingSize();
1819 /* set values to -1 to identify later as "uninitialized" values */
1820 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1821 for (act = 0; act < NUM_ACTIONS; act++)
1822 element_info[i].sound[act] = -1;
1824 /* initialize element/sound mapping from static configuration */
1825 for (i = 0; element_to_sound[i].element > -1; i++)
1827 int element = element_to_sound[i].element;
1828 int action = element_to_sound[i].action;
1829 int sound = element_to_sound[i].sound;
1830 boolean is_class = element_to_sound[i].is_class;
1833 action = ACTION_DEFAULT;
1836 element_info[element].sound[action] = sound;
1838 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1839 if (strEqual(element_info[j].class_name,
1840 element_info[element].class_name))
1841 element_info[j].sound[action] = sound;
1844 /* initialize element class/sound mapping from dynamic configuration */
1845 for (i = 0; i < num_property_mappings; i++)
1847 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1848 int action = property_mapping[i].ext1_index;
1849 int sound = property_mapping[i].artwork_index;
1851 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1855 action = ACTION_DEFAULT;
1857 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1858 if (strEqual(element_info[j].class_name,
1859 element_info[element_class].class_name))
1860 element_info[j].sound[action] = sound;
1863 /* initialize element/sound mapping from dynamic configuration */
1864 for (i = 0; i < num_property_mappings; i++)
1866 int element = property_mapping[i].base_index;
1867 int action = property_mapping[i].ext1_index;
1868 int sound = property_mapping[i].artwork_index;
1870 if (element >= MAX_NUM_ELEMENTS)
1874 action = ACTION_DEFAULT;
1876 element_info[element].sound[action] = sound;
1879 /* now set all '-1' values to element specific default values */
1880 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1882 for (act = 0; act < NUM_ACTIONS; act++)
1884 /* generic default action sound (defined by "[default]" directive) */
1885 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1887 /* look for special default action sound (classic game specific) */
1888 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1889 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1890 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1891 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1892 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1893 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1895 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1896 /* !!! make this better !!! */
1897 if (i == EL_EMPTY_SPACE)
1898 default_action_sound = element_info[EL_DEFAULT].sound[act];
1900 /* no sound for this specific action -- use default action sound */
1901 if (element_info[i].sound[act] == -1)
1902 element_info[i].sound[act] = default_action_sound;
1906 /* copy sound settings to some elements that are only stored in level file
1907 in native R'n'D levels, but are used by game engine in native EM levels */
1908 for (i = 0; copy_properties[i][0] != -1; i++)
1909 for (j = 1; j <= 4; j++)
1910 for (act = 0; act < NUM_ACTIONS; act++)
1911 element_info[copy_properties[i][j]].sound[act] =
1912 element_info[copy_properties[i][0]].sound[act];
1915 static void InitGameModeSoundInfo()
1919 /* set values to -1 to identify later as "uninitialized" values */
1920 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1923 /* initialize gamemode/sound mapping from static configuration */
1924 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1926 int gamemode = gamemode_to_sound[i].gamemode;
1927 int sound = gamemode_to_sound[i].sound;
1930 gamemode = GAME_MODE_DEFAULT;
1932 menu.sound[gamemode] = sound;
1935 /* now set all '-1' values to levelset specific default values */
1936 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1937 if (menu.sound[i] == -1)
1938 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1941 static void set_sound_parameters(int sound, char **parameter_raw)
1943 int parameter[NUM_SND_ARGS];
1946 /* get integer values from string parameters */
1947 for (i = 0; i < NUM_SND_ARGS; i++)
1949 get_parameter_value(parameter_raw[i],
1950 sound_config_suffix[i].token,
1951 sound_config_suffix[i].type);
1953 /* explicit loop mode setting in configuration overrides default value */
1954 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1955 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1957 /* sound volume to change the original volume when loading the sound file */
1958 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1960 /* sound priority to give certain sounds a higher or lower priority */
1961 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1964 static void InitSoundInfo()
1966 int *sound_effect_properties;
1967 int num_sounds = getSoundListSize();
1970 checked_free(sound_info);
1972 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1973 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1975 /* initialize sound effect for all elements to "no sound" */
1976 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1977 for (j = 0; j < NUM_ACTIONS; j++)
1978 element_info[i].sound[j] = SND_UNDEFINED;
1980 for (i = 0; i < num_sounds; i++)
1982 struct FileInfo *sound = getSoundListEntry(i);
1983 int len_effect_text = strlen(sound->token);
1985 sound_effect_properties[i] = ACTION_OTHER;
1986 sound_info[i].loop = FALSE; /* default: play sound only once */
1988 /* determine all loop sounds and identify certain sound classes */
1990 for (j = 0; element_action_info[j].suffix; j++)
1992 int len_action_text = strlen(element_action_info[j].suffix);
1994 if (len_action_text < len_effect_text &&
1995 strEqual(&sound->token[len_effect_text - len_action_text],
1996 element_action_info[j].suffix))
1998 sound_effect_properties[i] = element_action_info[j].value;
1999 sound_info[i].loop = element_action_info[j].is_loop_sound;
2005 /* associate elements and some selected sound actions */
2007 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2009 if (element_info[j].class_name)
2011 int len_class_text = strlen(element_info[j].class_name);
2013 if (len_class_text + 1 < len_effect_text &&
2014 strncmp(sound->token,
2015 element_info[j].class_name, len_class_text) == 0 &&
2016 sound->token[len_class_text] == '.')
2018 int sound_action_value = sound_effect_properties[i];
2020 element_info[j].sound[sound_action_value] = i;
2025 set_sound_parameters(i, sound->parameter);
2028 free(sound_effect_properties);
2031 static void InitGameModeMusicInfo()
2033 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2034 int num_property_mappings = getMusicListPropertyMappingSize();
2035 int default_levelset_music = -1;
2038 /* set values to -1 to identify later as "uninitialized" values */
2039 for (i = 0; i < MAX_LEVELS; i++)
2040 levelset.music[i] = -1;
2041 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2044 /* initialize gamemode/music mapping from static configuration */
2045 for (i = 0; gamemode_to_music[i].music > -1; i++)
2047 int gamemode = gamemode_to_music[i].gamemode;
2048 int music = gamemode_to_music[i].music;
2051 gamemode = GAME_MODE_DEFAULT;
2053 menu.music[gamemode] = music;
2056 /* initialize gamemode/music mapping from dynamic configuration */
2057 for (i = 0; i < num_property_mappings; i++)
2059 int prefix = property_mapping[i].base_index;
2060 int gamemode = property_mapping[i].ext2_index;
2061 int level = property_mapping[i].ext3_index;
2062 int music = property_mapping[i].artwork_index;
2064 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2068 gamemode = GAME_MODE_DEFAULT;
2070 /* level specific music only allowed for in-game music */
2071 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2072 gamemode = GAME_MODE_PLAYING;
2077 default_levelset_music = music;
2080 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2081 levelset.music[level] = music;
2082 if (gamemode != GAME_MODE_PLAYING)
2083 menu.music[gamemode] = music;
2086 /* now set all '-1' values to menu specific default values */
2087 /* (undefined values of "levelset.music[]" might stay at "-1" to
2088 allow dynamic selection of music files from music directory!) */
2089 for (i = 0; i < MAX_LEVELS; i++)
2090 if (levelset.music[i] == -1)
2091 levelset.music[i] = default_levelset_music;
2092 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2093 if (menu.music[i] == -1)
2094 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2097 static void set_music_parameters(int music, char **parameter_raw)
2099 int parameter[NUM_MUS_ARGS];
2102 /* get integer values from string parameters */
2103 for (i = 0; i < NUM_MUS_ARGS; i++)
2105 get_parameter_value(parameter_raw[i],
2106 music_config_suffix[i].token,
2107 music_config_suffix[i].type);
2109 /* explicit loop mode setting in configuration overrides default value */
2110 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2111 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2114 static void InitMusicInfo()
2116 int num_music = getMusicListSize();
2119 checked_free(music_info);
2121 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2123 for (i = 0; i < num_music; i++)
2125 struct FileInfo *music = getMusicListEntry(i);
2126 int len_music_text = strlen(music->token);
2128 music_info[i].loop = TRUE; /* default: play music in loop mode */
2130 /* determine all loop music */
2132 for (j = 0; music_prefix_info[j].prefix; j++)
2134 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2136 if (len_prefix_text < len_music_text &&
2137 strncmp(music->token,
2138 music_prefix_info[j].prefix, len_prefix_text) == 0)
2140 music_info[i].loop = music_prefix_info[j].is_loop_music;
2146 set_music_parameters(i, music->parameter);
2150 static void ReinitializeGraphics()
2152 print_timestamp_init("ReinitializeGraphics");
2154 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2156 InitGraphicInfo(); /* graphic properties mapping */
2157 print_timestamp_time("InitGraphicInfo");
2158 InitElementGraphicInfo(); /* element game graphic mapping */
2159 print_timestamp_time("InitElementGraphicInfo");
2160 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2161 print_timestamp_time("InitElementSpecialGraphicInfo");
2163 InitElementSmallImages(); /* scale elements to all needed sizes */
2164 print_timestamp_time("InitElementSmallImages");
2165 InitScaledImages(); /* scale all other images, if needed */
2166 print_timestamp_time("InitScaledImages");
2167 InitBitmapPointers(); /* set standard size bitmap pointers */
2168 print_timestamp_time("InitBitmapPointers");
2169 InitFontGraphicInfo(); /* initialize text drawing functions */
2170 print_timestamp_time("InitFontGraphicInfo");
2171 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2172 print_timestamp_time("InitGlobalAnimGraphicInfo");
2174 InitImageTextures(); /* create textures for certain images */
2175 print_timestamp_time("InitImageTextures");
2177 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2178 print_timestamp_time("InitGraphicInfo_EM");
2180 InitGraphicCompatibilityInfo();
2181 print_timestamp_time("InitGraphicCompatibilityInfo");
2183 SetMainBackgroundImage(IMG_BACKGROUND);
2184 print_timestamp_time("SetMainBackgroundImage");
2185 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2186 print_timestamp_time("SetDoorBackgroundImage");
2189 print_timestamp_time("InitGadgets");
2191 print_timestamp_time("InitDoors");
2193 print_timestamp_done("ReinitializeGraphics");
2196 static void ReinitializeSounds()
2198 InitSoundInfo(); /* sound properties mapping */
2199 InitElementSoundInfo(); /* element game sound mapping */
2200 InitGameModeSoundInfo(); /* game mode sound mapping */
2201 InitGlobalAnimSoundInfo(); /* global animation sound settings */
2203 InitPlayLevelSound(); /* internal game sound settings */
2206 static void ReinitializeMusic()
2208 InitMusicInfo(); /* music properties mapping */
2209 InitGameModeMusicInfo(); /* game mode music mapping */
2210 InitGlobalAnimMusicInfo(); /* global animation music settings */
2213 static int get_special_property_bit(int element, int property_bit_nr)
2215 struct PropertyBitInfo
2221 static struct PropertyBitInfo pb_can_move_into_acid[] =
2223 /* the player may be able fall into acid when gravity is activated */
2228 { EL_SP_MURPHY, 0 },
2229 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2231 /* all elements that can move may be able to also move into acid */
2234 { EL_BUG_RIGHT, 1 },
2237 { EL_SPACESHIP, 2 },
2238 { EL_SPACESHIP_LEFT, 2 },
2239 { EL_SPACESHIP_RIGHT, 2 },
2240 { EL_SPACESHIP_UP, 2 },
2241 { EL_SPACESHIP_DOWN, 2 },
2242 { EL_BD_BUTTERFLY, 3 },
2243 { EL_BD_BUTTERFLY_LEFT, 3 },
2244 { EL_BD_BUTTERFLY_RIGHT, 3 },
2245 { EL_BD_BUTTERFLY_UP, 3 },
2246 { EL_BD_BUTTERFLY_DOWN, 3 },
2247 { EL_BD_FIREFLY, 4 },
2248 { EL_BD_FIREFLY_LEFT, 4 },
2249 { EL_BD_FIREFLY_RIGHT, 4 },
2250 { EL_BD_FIREFLY_UP, 4 },
2251 { EL_BD_FIREFLY_DOWN, 4 },
2253 { EL_YAMYAM_LEFT, 5 },
2254 { EL_YAMYAM_RIGHT, 5 },
2255 { EL_YAMYAM_UP, 5 },
2256 { EL_YAMYAM_DOWN, 5 },
2257 { EL_DARK_YAMYAM, 6 },
2260 { EL_PACMAN_LEFT, 8 },
2261 { EL_PACMAN_RIGHT, 8 },
2262 { EL_PACMAN_UP, 8 },
2263 { EL_PACMAN_DOWN, 8 },
2265 { EL_MOLE_LEFT, 9 },
2266 { EL_MOLE_RIGHT, 9 },
2268 { EL_MOLE_DOWN, 9 },
2272 { EL_SATELLITE, 13 },
2273 { EL_SP_SNIKSNAK, 14 },
2274 { EL_SP_ELECTRON, 15 },
2277 { EL_EMC_ANDROID, 18 },
2282 static struct PropertyBitInfo pb_dont_collide_with[] =
2284 { EL_SP_SNIKSNAK, 0 },
2285 { EL_SP_ELECTRON, 1 },
2293 struct PropertyBitInfo *pb_info;
2296 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2297 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2302 struct PropertyBitInfo *pb_info = NULL;
2305 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2306 if (pb_definition[i].bit_nr == property_bit_nr)
2307 pb_info = pb_definition[i].pb_info;
2309 if (pb_info == NULL)
2312 for (i = 0; pb_info[i].element != -1; i++)
2313 if (pb_info[i].element == element)
2314 return pb_info[i].bit_nr;
2319 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2320 boolean property_value)
2322 int bit_nr = get_special_property_bit(element, property_bit_nr);
2327 *bitfield |= (1 << bit_nr);
2329 *bitfield &= ~(1 << bit_nr);
2333 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2335 int bit_nr = get_special_property_bit(element, property_bit_nr);
2338 return ((*bitfield & (1 << bit_nr)) != 0);
2343 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2345 static int group_nr;
2346 static struct ElementGroupInfo *group;
2347 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2350 if (actual_group == NULL) /* not yet initialized */
2353 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2355 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2356 group_element - EL_GROUP_START + 1);
2358 /* replace element which caused too deep recursion by question mark */
2359 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2364 if (recursion_depth == 0) /* initialization */
2366 group = actual_group;
2367 group_nr = GROUP_NR(group_element);
2369 group->num_elements_resolved = 0;
2370 group->choice_pos = 0;
2372 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2373 element_info[i].in_group[group_nr] = FALSE;
2376 for (i = 0; i < actual_group->num_elements; i++)
2378 int element = actual_group->element[i];
2380 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2383 if (IS_GROUP_ELEMENT(element))
2384 ResolveGroupElementExt(element, recursion_depth + 1);
2387 group->element_resolved[group->num_elements_resolved++] = element;
2388 element_info[element].in_group[group_nr] = TRUE;
2393 void ResolveGroupElement(int group_element)
2395 ResolveGroupElementExt(group_element, 0);
2398 void InitElementPropertiesStatic()
2400 static boolean clipboard_elements_initialized = FALSE;
2402 static int ep_diggable[] =
2407 EL_SP_BUGGY_BASE_ACTIVATING,
2410 EL_INVISIBLE_SAND_ACTIVE,
2413 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2414 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2419 EL_SP_BUGGY_BASE_ACTIVE,
2426 static int ep_collectible_only[] =
2448 EL_DYNABOMB_INCREASE_NUMBER,
2449 EL_DYNABOMB_INCREASE_SIZE,
2450 EL_DYNABOMB_INCREASE_POWER,
2468 /* !!! handle separately !!! */
2469 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2475 static int ep_dont_run_into[] =
2477 /* same elements as in 'ep_dont_touch' */
2483 /* same elements as in 'ep_dont_collide_with' */
2495 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2500 EL_SP_BUGGY_BASE_ACTIVE,
2507 static int ep_dont_collide_with[] =
2509 /* same elements as in 'ep_dont_touch' */
2526 static int ep_dont_touch[] =
2536 static int ep_indestructible[] =
2540 EL_ACID_POOL_TOPLEFT,
2541 EL_ACID_POOL_TOPRIGHT,
2542 EL_ACID_POOL_BOTTOMLEFT,
2543 EL_ACID_POOL_BOTTOM,
2544 EL_ACID_POOL_BOTTOMRIGHT,
2545 EL_SP_HARDWARE_GRAY,
2546 EL_SP_HARDWARE_GREEN,
2547 EL_SP_HARDWARE_BLUE,
2549 EL_SP_HARDWARE_YELLOW,
2550 EL_SP_HARDWARE_BASE_1,
2551 EL_SP_HARDWARE_BASE_2,
2552 EL_SP_HARDWARE_BASE_3,
2553 EL_SP_HARDWARE_BASE_4,
2554 EL_SP_HARDWARE_BASE_5,
2555 EL_SP_HARDWARE_BASE_6,
2556 EL_INVISIBLE_STEELWALL,
2557 EL_INVISIBLE_STEELWALL_ACTIVE,
2558 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2559 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2560 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2561 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2562 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2563 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2564 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2565 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2566 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2567 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2568 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2569 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2571 EL_LIGHT_SWITCH_ACTIVE,
2572 EL_SIGN_EXCLAMATION,
2573 EL_SIGN_RADIOACTIVITY,
2580 EL_SIGN_ENTRY_FORBIDDEN,
2581 EL_SIGN_EMERGENCY_EXIT,
2589 EL_STEEL_EXIT_CLOSED,
2591 EL_STEEL_EXIT_OPENING,
2592 EL_STEEL_EXIT_CLOSING,
2593 EL_EM_STEEL_EXIT_CLOSED,
2594 EL_EM_STEEL_EXIT_OPEN,
2595 EL_EM_STEEL_EXIT_OPENING,
2596 EL_EM_STEEL_EXIT_CLOSING,
2597 EL_DC_STEELWALL_1_LEFT,
2598 EL_DC_STEELWALL_1_RIGHT,
2599 EL_DC_STEELWALL_1_TOP,
2600 EL_DC_STEELWALL_1_BOTTOM,
2601 EL_DC_STEELWALL_1_HORIZONTAL,
2602 EL_DC_STEELWALL_1_VERTICAL,
2603 EL_DC_STEELWALL_1_TOPLEFT,
2604 EL_DC_STEELWALL_1_TOPRIGHT,
2605 EL_DC_STEELWALL_1_BOTTOMLEFT,
2606 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2607 EL_DC_STEELWALL_1_TOPLEFT_2,
2608 EL_DC_STEELWALL_1_TOPRIGHT_2,
2609 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2610 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2611 EL_DC_STEELWALL_2_LEFT,
2612 EL_DC_STEELWALL_2_RIGHT,
2613 EL_DC_STEELWALL_2_TOP,
2614 EL_DC_STEELWALL_2_BOTTOM,
2615 EL_DC_STEELWALL_2_HORIZONTAL,
2616 EL_DC_STEELWALL_2_VERTICAL,
2617 EL_DC_STEELWALL_2_MIDDLE,
2618 EL_DC_STEELWALL_2_SINGLE,
2619 EL_STEELWALL_SLIPPERY,
2633 EL_GATE_1_GRAY_ACTIVE,
2634 EL_GATE_2_GRAY_ACTIVE,
2635 EL_GATE_3_GRAY_ACTIVE,
2636 EL_GATE_4_GRAY_ACTIVE,
2645 EL_EM_GATE_1_GRAY_ACTIVE,
2646 EL_EM_GATE_2_GRAY_ACTIVE,
2647 EL_EM_GATE_3_GRAY_ACTIVE,
2648 EL_EM_GATE_4_GRAY_ACTIVE,
2657 EL_EMC_GATE_5_GRAY_ACTIVE,
2658 EL_EMC_GATE_6_GRAY_ACTIVE,
2659 EL_EMC_GATE_7_GRAY_ACTIVE,
2660 EL_EMC_GATE_8_GRAY_ACTIVE,
2662 EL_DC_GATE_WHITE_GRAY,
2663 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2664 EL_DC_GATE_FAKE_GRAY,
2666 EL_SWITCHGATE_OPENING,
2667 EL_SWITCHGATE_CLOSED,
2668 EL_SWITCHGATE_CLOSING,
2669 EL_DC_SWITCHGATE_SWITCH_UP,
2670 EL_DC_SWITCHGATE_SWITCH_DOWN,
2672 EL_TIMEGATE_OPENING,
2674 EL_TIMEGATE_CLOSING,
2675 EL_DC_TIMEGATE_SWITCH,
2676 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2680 EL_TUBE_VERTICAL_LEFT,
2681 EL_TUBE_VERTICAL_RIGHT,
2682 EL_TUBE_HORIZONTAL_UP,
2683 EL_TUBE_HORIZONTAL_DOWN,
2688 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2689 EL_EXPANDABLE_STEELWALL_VERTICAL,
2690 EL_EXPANDABLE_STEELWALL_ANY,
2695 static int ep_slippery[] =
2709 EL_ROBOT_WHEEL_ACTIVE,
2715 EL_ACID_POOL_TOPLEFT,
2716 EL_ACID_POOL_TOPRIGHT,
2726 EL_STEELWALL_SLIPPERY,
2729 EL_EMC_WALL_SLIPPERY_1,
2730 EL_EMC_WALL_SLIPPERY_2,
2731 EL_EMC_WALL_SLIPPERY_3,
2732 EL_EMC_WALL_SLIPPERY_4,
2734 EL_EMC_MAGIC_BALL_ACTIVE,
2739 static int ep_can_change[] =
2744 static int ep_can_move[] =
2746 /* same elements as in 'pb_can_move_into_acid' */
2769 static int ep_can_fall[] =
2783 EL_QUICKSAND_FAST_FULL,
2785 EL_BD_MAGIC_WALL_FULL,
2786 EL_DC_MAGIC_WALL_FULL,
2800 static int ep_can_smash_player[] =
2826 static int ep_can_smash_enemies[] =
2835 static int ep_can_smash_everything[] =
2844 static int ep_explodes_by_fire[] =
2846 /* same elements as in 'ep_explodes_impact' */
2851 /* same elements as in 'ep_explodes_smashed' */
2861 EL_EM_DYNAMITE_ACTIVE,
2862 EL_DYNABOMB_PLAYER_1_ACTIVE,
2863 EL_DYNABOMB_PLAYER_2_ACTIVE,
2864 EL_DYNABOMB_PLAYER_3_ACTIVE,
2865 EL_DYNABOMB_PLAYER_4_ACTIVE,
2866 EL_DYNABOMB_INCREASE_NUMBER,
2867 EL_DYNABOMB_INCREASE_SIZE,
2868 EL_DYNABOMB_INCREASE_POWER,
2869 EL_SP_DISK_RED_ACTIVE,
2883 static int ep_explodes_smashed[] =
2885 /* same elements as in 'ep_explodes_impact' */
2899 static int ep_explodes_impact[] =
2908 static int ep_walkable_over[] =
2912 EL_SOKOBAN_FIELD_EMPTY,
2919 EL_EM_STEEL_EXIT_OPEN,
2920 EL_EM_STEEL_EXIT_OPENING,
2929 EL_GATE_1_GRAY_ACTIVE,
2930 EL_GATE_2_GRAY_ACTIVE,
2931 EL_GATE_3_GRAY_ACTIVE,
2932 EL_GATE_4_GRAY_ACTIVE,
2940 static int ep_walkable_inside[] =
2945 EL_TUBE_VERTICAL_LEFT,
2946 EL_TUBE_VERTICAL_RIGHT,
2947 EL_TUBE_HORIZONTAL_UP,
2948 EL_TUBE_HORIZONTAL_DOWN,
2957 static int ep_walkable_under[] =
2962 static int ep_passable_over[] =
2972 EL_EM_GATE_1_GRAY_ACTIVE,
2973 EL_EM_GATE_2_GRAY_ACTIVE,
2974 EL_EM_GATE_3_GRAY_ACTIVE,
2975 EL_EM_GATE_4_GRAY_ACTIVE,
2984 EL_EMC_GATE_5_GRAY_ACTIVE,
2985 EL_EMC_GATE_6_GRAY_ACTIVE,
2986 EL_EMC_GATE_7_GRAY_ACTIVE,
2987 EL_EMC_GATE_8_GRAY_ACTIVE,
2989 EL_DC_GATE_WHITE_GRAY,
2990 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2997 static int ep_passable_inside[] =
3003 EL_SP_PORT_HORIZONTAL,
3004 EL_SP_PORT_VERTICAL,
3006 EL_SP_GRAVITY_PORT_LEFT,
3007 EL_SP_GRAVITY_PORT_RIGHT,
3008 EL_SP_GRAVITY_PORT_UP,
3009 EL_SP_GRAVITY_PORT_DOWN,
3010 EL_SP_GRAVITY_ON_PORT_LEFT,
3011 EL_SP_GRAVITY_ON_PORT_RIGHT,
3012 EL_SP_GRAVITY_ON_PORT_UP,
3013 EL_SP_GRAVITY_ON_PORT_DOWN,
3014 EL_SP_GRAVITY_OFF_PORT_LEFT,
3015 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3016 EL_SP_GRAVITY_OFF_PORT_UP,
3017 EL_SP_GRAVITY_OFF_PORT_DOWN,
3022 static int ep_passable_under[] =
3027 static int ep_droppable[] =
3032 static int ep_explodes_1x1_old[] =
3037 static int ep_pushable[] =
3049 EL_SOKOBAN_FIELD_FULL,
3058 static int ep_explodes_cross_old[] =
3063 static int ep_protected[] =
3065 /* same elements as in 'ep_walkable_inside' */
3069 EL_TUBE_VERTICAL_LEFT,
3070 EL_TUBE_VERTICAL_RIGHT,
3071 EL_TUBE_HORIZONTAL_UP,
3072 EL_TUBE_HORIZONTAL_DOWN,
3078 /* same elements as in 'ep_passable_over' */
3087 EL_EM_GATE_1_GRAY_ACTIVE,
3088 EL_EM_GATE_2_GRAY_ACTIVE,
3089 EL_EM_GATE_3_GRAY_ACTIVE,
3090 EL_EM_GATE_4_GRAY_ACTIVE,
3099 EL_EMC_GATE_5_GRAY_ACTIVE,
3100 EL_EMC_GATE_6_GRAY_ACTIVE,
3101 EL_EMC_GATE_7_GRAY_ACTIVE,
3102 EL_EMC_GATE_8_GRAY_ACTIVE,
3104 EL_DC_GATE_WHITE_GRAY,
3105 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3109 /* same elements as in 'ep_passable_inside' */
3114 EL_SP_PORT_HORIZONTAL,
3115 EL_SP_PORT_VERTICAL,
3117 EL_SP_GRAVITY_PORT_LEFT,
3118 EL_SP_GRAVITY_PORT_RIGHT,
3119 EL_SP_GRAVITY_PORT_UP,
3120 EL_SP_GRAVITY_PORT_DOWN,
3121 EL_SP_GRAVITY_ON_PORT_LEFT,
3122 EL_SP_GRAVITY_ON_PORT_RIGHT,
3123 EL_SP_GRAVITY_ON_PORT_UP,
3124 EL_SP_GRAVITY_ON_PORT_DOWN,
3125 EL_SP_GRAVITY_OFF_PORT_LEFT,
3126 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3127 EL_SP_GRAVITY_OFF_PORT_UP,
3128 EL_SP_GRAVITY_OFF_PORT_DOWN,
3133 static int ep_throwable[] =
3138 static int ep_can_explode[] =
3140 /* same elements as in 'ep_explodes_impact' */
3145 /* same elements as in 'ep_explodes_smashed' */
3151 /* elements that can explode by explosion or by dragonfire */
3155 EL_EM_DYNAMITE_ACTIVE,
3156 EL_DYNABOMB_PLAYER_1_ACTIVE,
3157 EL_DYNABOMB_PLAYER_2_ACTIVE,
3158 EL_DYNABOMB_PLAYER_3_ACTIVE,
3159 EL_DYNABOMB_PLAYER_4_ACTIVE,
3160 EL_DYNABOMB_INCREASE_NUMBER,
3161 EL_DYNABOMB_INCREASE_SIZE,
3162 EL_DYNABOMB_INCREASE_POWER,
3163 EL_SP_DISK_RED_ACTIVE,
3171 /* elements that can explode only by explosion */
3177 static int ep_gravity_reachable[] =
3183 EL_INVISIBLE_SAND_ACTIVE,
3188 EL_SP_PORT_HORIZONTAL,
3189 EL_SP_PORT_VERTICAL,
3191 EL_SP_GRAVITY_PORT_LEFT,
3192 EL_SP_GRAVITY_PORT_RIGHT,
3193 EL_SP_GRAVITY_PORT_UP,
3194 EL_SP_GRAVITY_PORT_DOWN,
3195 EL_SP_GRAVITY_ON_PORT_LEFT,
3196 EL_SP_GRAVITY_ON_PORT_RIGHT,
3197 EL_SP_GRAVITY_ON_PORT_UP,
3198 EL_SP_GRAVITY_ON_PORT_DOWN,
3199 EL_SP_GRAVITY_OFF_PORT_LEFT,
3200 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3201 EL_SP_GRAVITY_OFF_PORT_UP,
3202 EL_SP_GRAVITY_OFF_PORT_DOWN,
3208 static int ep_player[] =
3215 EL_SOKOBAN_FIELD_PLAYER,
3221 static int ep_can_pass_magic_wall[] =
3235 static int ep_can_pass_dc_magic_wall[] =
3251 static int ep_switchable[] =
3255 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3256 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3257 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3258 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3259 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3260 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3261 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3262 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3263 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3264 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3265 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3266 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3267 EL_SWITCHGATE_SWITCH_UP,
3268 EL_SWITCHGATE_SWITCH_DOWN,
3269 EL_DC_SWITCHGATE_SWITCH_UP,
3270 EL_DC_SWITCHGATE_SWITCH_DOWN,
3272 EL_LIGHT_SWITCH_ACTIVE,
3274 EL_DC_TIMEGATE_SWITCH,
3275 EL_BALLOON_SWITCH_LEFT,
3276 EL_BALLOON_SWITCH_RIGHT,
3277 EL_BALLOON_SWITCH_UP,
3278 EL_BALLOON_SWITCH_DOWN,
3279 EL_BALLOON_SWITCH_ANY,
3280 EL_BALLOON_SWITCH_NONE,
3283 EL_EMC_MAGIC_BALL_SWITCH,
3284 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3289 static int ep_bd_element[] =
3323 static int ep_sp_element[] =
3325 /* should always be valid */
3328 /* standard classic Supaplex elements */
3335 EL_SP_HARDWARE_GRAY,
3343 EL_SP_GRAVITY_PORT_RIGHT,
3344 EL_SP_GRAVITY_PORT_DOWN,
3345 EL_SP_GRAVITY_PORT_LEFT,
3346 EL_SP_GRAVITY_PORT_UP,
3351 EL_SP_PORT_VERTICAL,
3352 EL_SP_PORT_HORIZONTAL,
3358 EL_SP_HARDWARE_BASE_1,
3359 EL_SP_HARDWARE_GREEN,
3360 EL_SP_HARDWARE_BLUE,
3362 EL_SP_HARDWARE_YELLOW,
3363 EL_SP_HARDWARE_BASE_2,
3364 EL_SP_HARDWARE_BASE_3,
3365 EL_SP_HARDWARE_BASE_4,
3366 EL_SP_HARDWARE_BASE_5,
3367 EL_SP_HARDWARE_BASE_6,
3371 /* additional elements that appeared in newer Supaplex levels */
3374 /* additional gravity port elements (not switching, but setting gravity) */
3375 EL_SP_GRAVITY_ON_PORT_LEFT,
3376 EL_SP_GRAVITY_ON_PORT_RIGHT,
3377 EL_SP_GRAVITY_ON_PORT_UP,
3378 EL_SP_GRAVITY_ON_PORT_DOWN,
3379 EL_SP_GRAVITY_OFF_PORT_LEFT,
3380 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3381 EL_SP_GRAVITY_OFF_PORT_UP,
3382 EL_SP_GRAVITY_OFF_PORT_DOWN,
3384 /* more than one Murphy in a level results in an inactive clone */
3387 /* runtime Supaplex elements */
3388 EL_SP_DISK_RED_ACTIVE,
3389 EL_SP_TERMINAL_ACTIVE,
3390 EL_SP_BUGGY_BASE_ACTIVATING,
3391 EL_SP_BUGGY_BASE_ACTIVE,
3398 static int ep_sb_element[] =
3403 EL_SOKOBAN_FIELD_EMPTY,
3404 EL_SOKOBAN_FIELD_FULL,
3405 EL_SOKOBAN_FIELD_PLAYER,
3410 EL_INVISIBLE_STEELWALL,
3415 static int ep_gem[] =
3427 static int ep_food_dark_yamyam[] =
3455 static int ep_food_penguin[] =
3469 static int ep_food_pig[] =
3481 static int ep_historic_wall[] =
3492 EL_GATE_1_GRAY_ACTIVE,
3493 EL_GATE_2_GRAY_ACTIVE,
3494 EL_GATE_3_GRAY_ACTIVE,
3495 EL_GATE_4_GRAY_ACTIVE,
3504 EL_EM_GATE_1_GRAY_ACTIVE,
3505 EL_EM_GATE_2_GRAY_ACTIVE,
3506 EL_EM_GATE_3_GRAY_ACTIVE,
3507 EL_EM_GATE_4_GRAY_ACTIVE,
3514 EL_EXPANDABLE_WALL_HORIZONTAL,
3515 EL_EXPANDABLE_WALL_VERTICAL,
3516 EL_EXPANDABLE_WALL_ANY,
3517 EL_EXPANDABLE_WALL_GROWING,
3518 EL_BD_EXPANDABLE_WALL,
3525 EL_SP_HARDWARE_GRAY,
3526 EL_SP_HARDWARE_GREEN,
3527 EL_SP_HARDWARE_BLUE,
3529 EL_SP_HARDWARE_YELLOW,
3530 EL_SP_HARDWARE_BASE_1,
3531 EL_SP_HARDWARE_BASE_2,
3532 EL_SP_HARDWARE_BASE_3,
3533 EL_SP_HARDWARE_BASE_4,
3534 EL_SP_HARDWARE_BASE_5,
3535 EL_SP_HARDWARE_BASE_6,
3537 EL_SP_TERMINAL_ACTIVE,
3540 EL_INVISIBLE_STEELWALL,
3541 EL_INVISIBLE_STEELWALL_ACTIVE,
3543 EL_INVISIBLE_WALL_ACTIVE,
3544 EL_STEELWALL_SLIPPERY,
3561 static int ep_historic_solid[] =
3565 EL_EXPANDABLE_WALL_HORIZONTAL,
3566 EL_EXPANDABLE_WALL_VERTICAL,
3567 EL_EXPANDABLE_WALL_ANY,
3568 EL_BD_EXPANDABLE_WALL,
3581 EL_QUICKSAND_FILLING,
3582 EL_QUICKSAND_EMPTYING,
3584 EL_MAGIC_WALL_ACTIVE,
3585 EL_MAGIC_WALL_EMPTYING,
3586 EL_MAGIC_WALL_FILLING,
3590 EL_BD_MAGIC_WALL_ACTIVE,
3591 EL_BD_MAGIC_WALL_EMPTYING,
3592 EL_BD_MAGIC_WALL_FULL,
3593 EL_BD_MAGIC_WALL_FILLING,
3594 EL_BD_MAGIC_WALL_DEAD,
3603 EL_SP_TERMINAL_ACTIVE,
3607 EL_INVISIBLE_WALL_ACTIVE,
3608 EL_SWITCHGATE_SWITCH_UP,
3609 EL_SWITCHGATE_SWITCH_DOWN,
3610 EL_DC_SWITCHGATE_SWITCH_UP,
3611 EL_DC_SWITCHGATE_SWITCH_DOWN,
3613 EL_TIMEGATE_SWITCH_ACTIVE,
3614 EL_DC_TIMEGATE_SWITCH,
3615 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3627 /* the following elements are a direct copy of "indestructible" elements,
3628 except "EL_ACID", which is "indestructible", but not "solid"! */
3633 EL_ACID_POOL_TOPLEFT,
3634 EL_ACID_POOL_TOPRIGHT,
3635 EL_ACID_POOL_BOTTOMLEFT,
3636 EL_ACID_POOL_BOTTOM,
3637 EL_ACID_POOL_BOTTOMRIGHT,
3638 EL_SP_HARDWARE_GRAY,
3639 EL_SP_HARDWARE_GREEN,
3640 EL_SP_HARDWARE_BLUE,
3642 EL_SP_HARDWARE_YELLOW,
3643 EL_SP_HARDWARE_BASE_1,
3644 EL_SP_HARDWARE_BASE_2,
3645 EL_SP_HARDWARE_BASE_3,
3646 EL_SP_HARDWARE_BASE_4,
3647 EL_SP_HARDWARE_BASE_5,
3648 EL_SP_HARDWARE_BASE_6,
3649 EL_INVISIBLE_STEELWALL,
3650 EL_INVISIBLE_STEELWALL_ACTIVE,
3651 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3652 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3653 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3654 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3655 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3656 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3657 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3658 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3659 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3660 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3661 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3662 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3664 EL_LIGHT_SWITCH_ACTIVE,
3665 EL_SIGN_EXCLAMATION,
3666 EL_SIGN_RADIOACTIVITY,
3673 EL_SIGN_ENTRY_FORBIDDEN,
3674 EL_SIGN_EMERGENCY_EXIT,
3682 EL_STEEL_EXIT_CLOSED,
3684 EL_DC_STEELWALL_1_LEFT,
3685 EL_DC_STEELWALL_1_RIGHT,
3686 EL_DC_STEELWALL_1_TOP,
3687 EL_DC_STEELWALL_1_BOTTOM,
3688 EL_DC_STEELWALL_1_HORIZONTAL,
3689 EL_DC_STEELWALL_1_VERTICAL,
3690 EL_DC_STEELWALL_1_TOPLEFT,
3691 EL_DC_STEELWALL_1_TOPRIGHT,
3692 EL_DC_STEELWALL_1_BOTTOMLEFT,
3693 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3694 EL_DC_STEELWALL_1_TOPLEFT_2,
3695 EL_DC_STEELWALL_1_TOPRIGHT_2,
3696 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3697 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3698 EL_DC_STEELWALL_2_LEFT,
3699 EL_DC_STEELWALL_2_RIGHT,
3700 EL_DC_STEELWALL_2_TOP,
3701 EL_DC_STEELWALL_2_BOTTOM,
3702 EL_DC_STEELWALL_2_HORIZONTAL,
3703 EL_DC_STEELWALL_2_VERTICAL,
3704 EL_DC_STEELWALL_2_MIDDLE,
3705 EL_DC_STEELWALL_2_SINGLE,
3706 EL_STEELWALL_SLIPPERY,
3720 EL_GATE_1_GRAY_ACTIVE,
3721 EL_GATE_2_GRAY_ACTIVE,
3722 EL_GATE_3_GRAY_ACTIVE,
3723 EL_GATE_4_GRAY_ACTIVE,
3732 EL_EM_GATE_1_GRAY_ACTIVE,
3733 EL_EM_GATE_2_GRAY_ACTIVE,
3734 EL_EM_GATE_3_GRAY_ACTIVE,
3735 EL_EM_GATE_4_GRAY_ACTIVE,
3737 EL_SWITCHGATE_OPENING,
3738 EL_SWITCHGATE_CLOSED,
3739 EL_SWITCHGATE_CLOSING,
3741 EL_TIMEGATE_OPENING,
3743 EL_TIMEGATE_CLOSING,
3747 EL_TUBE_VERTICAL_LEFT,
3748 EL_TUBE_VERTICAL_RIGHT,
3749 EL_TUBE_HORIZONTAL_UP,
3750 EL_TUBE_HORIZONTAL_DOWN,
3759 static int ep_classic_enemy[] =
3776 static int ep_belt[] =
3778 EL_CONVEYOR_BELT_1_LEFT,
3779 EL_CONVEYOR_BELT_1_MIDDLE,
3780 EL_CONVEYOR_BELT_1_RIGHT,
3781 EL_CONVEYOR_BELT_2_LEFT,
3782 EL_CONVEYOR_BELT_2_MIDDLE,
3783 EL_CONVEYOR_BELT_2_RIGHT,
3784 EL_CONVEYOR_BELT_3_LEFT,
3785 EL_CONVEYOR_BELT_3_MIDDLE,
3786 EL_CONVEYOR_BELT_3_RIGHT,
3787 EL_CONVEYOR_BELT_4_LEFT,
3788 EL_CONVEYOR_BELT_4_MIDDLE,
3789 EL_CONVEYOR_BELT_4_RIGHT,
3794 static int ep_belt_active[] =
3796 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3797 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3798 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3799 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3800 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3801 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3802 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3803 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3804 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3805 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3806 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3807 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3812 static int ep_belt_switch[] =
3814 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3815 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3816 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3817 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3818 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3819 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3820 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3821 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3822 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3823 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3824 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3825 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3830 static int ep_tube[] =
3837 EL_TUBE_HORIZONTAL_UP,
3838 EL_TUBE_HORIZONTAL_DOWN,
3840 EL_TUBE_VERTICAL_LEFT,
3841 EL_TUBE_VERTICAL_RIGHT,
3847 static int ep_acid_pool[] =
3849 EL_ACID_POOL_TOPLEFT,
3850 EL_ACID_POOL_TOPRIGHT,
3851 EL_ACID_POOL_BOTTOMLEFT,
3852 EL_ACID_POOL_BOTTOM,
3853 EL_ACID_POOL_BOTTOMRIGHT,
3858 static int ep_keygate[] =
3868 EL_GATE_1_GRAY_ACTIVE,
3869 EL_GATE_2_GRAY_ACTIVE,
3870 EL_GATE_3_GRAY_ACTIVE,
3871 EL_GATE_4_GRAY_ACTIVE,
3880 EL_EM_GATE_1_GRAY_ACTIVE,
3881 EL_EM_GATE_2_GRAY_ACTIVE,
3882 EL_EM_GATE_3_GRAY_ACTIVE,
3883 EL_EM_GATE_4_GRAY_ACTIVE,
3892 EL_EMC_GATE_5_GRAY_ACTIVE,
3893 EL_EMC_GATE_6_GRAY_ACTIVE,
3894 EL_EMC_GATE_7_GRAY_ACTIVE,
3895 EL_EMC_GATE_8_GRAY_ACTIVE,
3897 EL_DC_GATE_WHITE_GRAY,
3898 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3903 static int ep_amoeboid[] =
3915 static int ep_amoebalive[] =
3926 static int ep_has_editor_content[] =
3932 EL_SOKOBAN_FIELD_PLAYER,
3949 static int ep_can_turn_each_move[] =
3951 /* !!! do something with this one !!! */
3955 static int ep_can_grow[] =
3969 static int ep_active_bomb[] =
3972 EL_EM_DYNAMITE_ACTIVE,
3973 EL_DYNABOMB_PLAYER_1_ACTIVE,
3974 EL_DYNABOMB_PLAYER_2_ACTIVE,
3975 EL_DYNABOMB_PLAYER_3_ACTIVE,
3976 EL_DYNABOMB_PLAYER_4_ACTIVE,
3977 EL_SP_DISK_RED_ACTIVE,
3982 static int ep_inactive[] =
3992 EL_QUICKSAND_FAST_EMPTY,
4015 EL_GATE_1_GRAY_ACTIVE,
4016 EL_GATE_2_GRAY_ACTIVE,
4017 EL_GATE_3_GRAY_ACTIVE,
4018 EL_GATE_4_GRAY_ACTIVE,
4027 EL_EM_GATE_1_GRAY_ACTIVE,
4028 EL_EM_GATE_2_GRAY_ACTIVE,
4029 EL_EM_GATE_3_GRAY_ACTIVE,
4030 EL_EM_GATE_4_GRAY_ACTIVE,
4039 EL_EMC_GATE_5_GRAY_ACTIVE,
4040 EL_EMC_GATE_6_GRAY_ACTIVE,
4041 EL_EMC_GATE_7_GRAY_ACTIVE,
4042 EL_EMC_GATE_8_GRAY_ACTIVE,
4044 EL_DC_GATE_WHITE_GRAY,
4045 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4046 EL_DC_GATE_FAKE_GRAY,
4049 EL_INVISIBLE_STEELWALL,
4057 EL_WALL_EMERALD_YELLOW,
4058 EL_DYNABOMB_INCREASE_NUMBER,
4059 EL_DYNABOMB_INCREASE_SIZE,
4060 EL_DYNABOMB_INCREASE_POWER,
4064 EL_SOKOBAN_FIELD_EMPTY,
4065 EL_SOKOBAN_FIELD_FULL,
4066 EL_WALL_EMERALD_RED,
4067 EL_WALL_EMERALD_PURPLE,
4068 EL_ACID_POOL_TOPLEFT,
4069 EL_ACID_POOL_TOPRIGHT,
4070 EL_ACID_POOL_BOTTOMLEFT,
4071 EL_ACID_POOL_BOTTOM,
4072 EL_ACID_POOL_BOTTOMRIGHT,
4076 EL_BD_MAGIC_WALL_DEAD,
4078 EL_DC_MAGIC_WALL_DEAD,
4079 EL_AMOEBA_TO_DIAMOND,
4087 EL_SP_GRAVITY_PORT_RIGHT,
4088 EL_SP_GRAVITY_PORT_DOWN,
4089 EL_SP_GRAVITY_PORT_LEFT,
4090 EL_SP_GRAVITY_PORT_UP,
4091 EL_SP_PORT_HORIZONTAL,
4092 EL_SP_PORT_VERTICAL,
4103 EL_SP_HARDWARE_GRAY,
4104 EL_SP_HARDWARE_GREEN,
4105 EL_SP_HARDWARE_BLUE,
4107 EL_SP_HARDWARE_YELLOW,
4108 EL_SP_HARDWARE_BASE_1,
4109 EL_SP_HARDWARE_BASE_2,
4110 EL_SP_HARDWARE_BASE_3,
4111 EL_SP_HARDWARE_BASE_4,
4112 EL_SP_HARDWARE_BASE_5,
4113 EL_SP_HARDWARE_BASE_6,
4114 EL_SP_GRAVITY_ON_PORT_LEFT,
4115 EL_SP_GRAVITY_ON_PORT_RIGHT,
4116 EL_SP_GRAVITY_ON_PORT_UP,
4117 EL_SP_GRAVITY_ON_PORT_DOWN,
4118 EL_SP_GRAVITY_OFF_PORT_LEFT,
4119 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4120 EL_SP_GRAVITY_OFF_PORT_UP,
4121 EL_SP_GRAVITY_OFF_PORT_DOWN,
4122 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4123 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4124 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4125 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4126 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4127 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4128 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4129 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4130 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4131 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4132 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4133 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4134 EL_SIGN_EXCLAMATION,
4135 EL_SIGN_RADIOACTIVITY,
4142 EL_SIGN_ENTRY_FORBIDDEN,
4143 EL_SIGN_EMERGENCY_EXIT,
4151 EL_DC_STEELWALL_1_LEFT,
4152 EL_DC_STEELWALL_1_RIGHT,
4153 EL_DC_STEELWALL_1_TOP,
4154 EL_DC_STEELWALL_1_BOTTOM,
4155 EL_DC_STEELWALL_1_HORIZONTAL,
4156 EL_DC_STEELWALL_1_VERTICAL,
4157 EL_DC_STEELWALL_1_TOPLEFT,
4158 EL_DC_STEELWALL_1_TOPRIGHT,
4159 EL_DC_STEELWALL_1_BOTTOMLEFT,
4160 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4161 EL_DC_STEELWALL_1_TOPLEFT_2,
4162 EL_DC_STEELWALL_1_TOPRIGHT_2,
4163 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4164 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4165 EL_DC_STEELWALL_2_LEFT,
4166 EL_DC_STEELWALL_2_RIGHT,
4167 EL_DC_STEELWALL_2_TOP,
4168 EL_DC_STEELWALL_2_BOTTOM,
4169 EL_DC_STEELWALL_2_HORIZONTAL,
4170 EL_DC_STEELWALL_2_VERTICAL,
4171 EL_DC_STEELWALL_2_MIDDLE,
4172 EL_DC_STEELWALL_2_SINGLE,
4173 EL_STEELWALL_SLIPPERY,
4178 EL_EMC_WALL_SLIPPERY_1,
4179 EL_EMC_WALL_SLIPPERY_2,
4180 EL_EMC_WALL_SLIPPERY_3,
4181 EL_EMC_WALL_SLIPPERY_4,
4202 static int ep_em_slippery_wall[] =
4207 static int ep_gfx_crumbled[] =
4218 static int ep_editor_cascade_active[] =
4220 EL_INTERNAL_CASCADE_BD_ACTIVE,
4221 EL_INTERNAL_CASCADE_EM_ACTIVE,
4222 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4223 EL_INTERNAL_CASCADE_RND_ACTIVE,
4224 EL_INTERNAL_CASCADE_SB_ACTIVE,
4225 EL_INTERNAL_CASCADE_SP_ACTIVE,
4226 EL_INTERNAL_CASCADE_DC_ACTIVE,
4227 EL_INTERNAL_CASCADE_DX_ACTIVE,
4228 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4229 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4230 EL_INTERNAL_CASCADE_CE_ACTIVE,
4231 EL_INTERNAL_CASCADE_GE_ACTIVE,
4232 EL_INTERNAL_CASCADE_REF_ACTIVE,
4233 EL_INTERNAL_CASCADE_USER_ACTIVE,
4234 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4239 static int ep_editor_cascade_inactive[] =
4241 EL_INTERNAL_CASCADE_BD,
4242 EL_INTERNAL_CASCADE_EM,
4243 EL_INTERNAL_CASCADE_EMC,
4244 EL_INTERNAL_CASCADE_RND,
4245 EL_INTERNAL_CASCADE_SB,
4246 EL_INTERNAL_CASCADE_SP,
4247 EL_INTERNAL_CASCADE_DC,
4248 EL_INTERNAL_CASCADE_DX,
4249 EL_INTERNAL_CASCADE_CHARS,
4250 EL_INTERNAL_CASCADE_STEEL_CHARS,
4251 EL_INTERNAL_CASCADE_CE,
4252 EL_INTERNAL_CASCADE_GE,
4253 EL_INTERNAL_CASCADE_REF,
4254 EL_INTERNAL_CASCADE_USER,
4255 EL_INTERNAL_CASCADE_DYNAMIC,
4260 static int ep_obsolete[] =
4264 EL_EM_KEY_1_FILE_OBSOLETE,
4265 EL_EM_KEY_2_FILE_OBSOLETE,
4266 EL_EM_KEY_3_FILE_OBSOLETE,
4267 EL_EM_KEY_4_FILE_OBSOLETE,
4268 EL_ENVELOPE_OBSOLETE,
4277 } element_properties[] =
4279 { ep_diggable, EP_DIGGABLE },
4280 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4281 { ep_dont_run_into, EP_DONT_RUN_INTO },
4282 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4283 { ep_dont_touch, EP_DONT_TOUCH },
4284 { ep_indestructible, EP_INDESTRUCTIBLE },
4285 { ep_slippery, EP_SLIPPERY },
4286 { ep_can_change, EP_CAN_CHANGE },
4287 { ep_can_move, EP_CAN_MOVE },
4288 { ep_can_fall, EP_CAN_FALL },
4289 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4290 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4291 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4292 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4293 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4294 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4295 { ep_walkable_over, EP_WALKABLE_OVER },
4296 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4297 { ep_walkable_under, EP_WALKABLE_UNDER },
4298 { ep_passable_over, EP_PASSABLE_OVER },
4299 { ep_passable_inside, EP_PASSABLE_INSIDE },
4300 { ep_passable_under, EP_PASSABLE_UNDER },
4301 { ep_droppable, EP_DROPPABLE },
4302 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4303 { ep_pushable, EP_PUSHABLE },
4304 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4305 { ep_protected, EP_PROTECTED },
4306 { ep_throwable, EP_THROWABLE },
4307 { ep_can_explode, EP_CAN_EXPLODE },
4308 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4310 { ep_player, EP_PLAYER },
4311 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4312 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4313 { ep_switchable, EP_SWITCHABLE },
4314 { ep_bd_element, EP_BD_ELEMENT },
4315 { ep_sp_element, EP_SP_ELEMENT },
4316 { ep_sb_element, EP_SB_ELEMENT },
4318 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4319 { ep_food_penguin, EP_FOOD_PENGUIN },
4320 { ep_food_pig, EP_FOOD_PIG },
4321 { ep_historic_wall, EP_HISTORIC_WALL },
4322 { ep_historic_solid, EP_HISTORIC_SOLID },
4323 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4324 { ep_belt, EP_BELT },
4325 { ep_belt_active, EP_BELT_ACTIVE },
4326 { ep_belt_switch, EP_BELT_SWITCH },
4327 { ep_tube, EP_TUBE },
4328 { ep_acid_pool, EP_ACID_POOL },
4329 { ep_keygate, EP_KEYGATE },
4330 { ep_amoeboid, EP_AMOEBOID },
4331 { ep_amoebalive, EP_AMOEBALIVE },
4332 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4333 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4334 { ep_can_grow, EP_CAN_GROW },
4335 { ep_active_bomb, EP_ACTIVE_BOMB },
4336 { ep_inactive, EP_INACTIVE },
4338 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4340 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4342 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4343 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4345 { ep_obsolete, EP_OBSOLETE },
4352 /* always start with reliable default values (element has no properties) */
4353 /* (but never initialize clipboard elements after the very first time) */
4354 /* (to be able to use clipboard elements between several levels) */
4355 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4356 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4357 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4358 SET_PROPERTY(i, j, FALSE);
4360 /* set all base element properties from above array definitions */
4361 for (i = 0; element_properties[i].elements != NULL; i++)
4362 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4363 SET_PROPERTY((element_properties[i].elements)[j],
4364 element_properties[i].property, TRUE);
4366 /* copy properties to some elements that are only stored in level file */
4367 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4368 for (j = 0; copy_properties[j][0] != -1; j++)
4369 if (HAS_PROPERTY(copy_properties[j][0], i))
4370 for (k = 1; k <= 4; k++)
4371 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4373 /* set static element properties that are not listed in array definitions */
4374 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4375 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4377 clipboard_elements_initialized = TRUE;
4380 void InitElementPropertiesEngine(int engine_version)
4382 static int no_wall_properties[] =
4385 EP_COLLECTIBLE_ONLY,
4387 EP_DONT_COLLIDE_WITH,
4390 EP_CAN_SMASH_PLAYER,
4391 EP_CAN_SMASH_ENEMIES,
4392 EP_CAN_SMASH_EVERYTHING,
4397 EP_FOOD_DARK_YAMYAM,
4413 /* important: after initialization in InitElementPropertiesStatic(), the
4414 elements are not again initialized to a default value; therefore all
4415 changes have to make sure that they leave the element with a defined
4416 property (which means that conditional property changes must be set to
4417 a reliable default value before) */
4419 /* resolve group elements */
4420 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4421 ResolveGroupElement(EL_GROUP_START + i);
4423 /* set all special, combined or engine dependent element properties */
4424 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4426 /* do not change (already initialized) clipboard elements here */
4427 if (IS_CLIPBOARD_ELEMENT(i))
4430 /* ---------- INACTIVE ------------------------------------------------- */
4431 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4432 i <= EL_CHAR_END) ||
4433 (i >= EL_STEEL_CHAR_START &&
4434 i <= EL_STEEL_CHAR_END)));
4436 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4437 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4438 IS_WALKABLE_INSIDE(i) ||
4439 IS_WALKABLE_UNDER(i)));
4441 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4442 IS_PASSABLE_INSIDE(i) ||
4443 IS_PASSABLE_UNDER(i)));
4445 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4446 IS_PASSABLE_OVER(i)));
4448 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4449 IS_PASSABLE_INSIDE(i)));
4451 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4452 IS_PASSABLE_UNDER(i)));
4454 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4457 /* ---------- COLLECTIBLE ---------------------------------------------- */
4458 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4462 /* ---------- SNAPPABLE ------------------------------------------------ */
4463 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4464 IS_COLLECTIBLE(i) ||
4468 /* ---------- WALL ----------------------------------------------------- */
4469 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4471 for (j = 0; no_wall_properties[j] != -1; j++)
4472 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4473 i >= EL_FIRST_RUNTIME_UNREAL)
4474 SET_PROPERTY(i, EP_WALL, FALSE);
4476 if (IS_HISTORIC_WALL(i))
4477 SET_PROPERTY(i, EP_WALL, TRUE);
4479 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4480 if (engine_version < VERSION_IDENT(2,2,0,0))
4481 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4483 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4485 !IS_COLLECTIBLE(i)));
4487 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4488 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4489 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4491 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4492 IS_INDESTRUCTIBLE(i)));
4494 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4496 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4497 else if (engine_version < VERSION_IDENT(2,2,0,0))
4498 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4500 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4504 if (IS_CUSTOM_ELEMENT(i))
4506 /* these are additional properties which are initially false when set */
4508 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4510 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4511 if (DONT_COLLIDE_WITH(i))
4512 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4514 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4515 if (CAN_SMASH_EVERYTHING(i))
4516 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4517 if (CAN_SMASH_ENEMIES(i))
4518 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4521 /* ---------- CAN_SMASH ------------------------------------------------ */
4522 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4523 CAN_SMASH_ENEMIES(i) ||
4524 CAN_SMASH_EVERYTHING(i)));
4526 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4527 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4528 EXPLODES_BY_FIRE(i)));
4530 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4531 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4532 EXPLODES_SMASHED(i)));
4534 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4535 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4536 EXPLODES_IMPACT(i)));
4538 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4539 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4541 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4542 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4543 i == EL_BLACK_ORB));
4545 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4546 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4548 IS_CUSTOM_ELEMENT(i)));
4550 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4551 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4552 i == EL_SP_ELECTRON));
4554 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4555 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4556 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4557 getMoveIntoAcidProperty(&level, i));
4559 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4560 if (MAYBE_DONT_COLLIDE_WITH(i))
4561 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4562 getDontCollideWithProperty(&level, i));
4564 /* ---------- SP_PORT -------------------------------------------------- */
4565 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4566 IS_PASSABLE_INSIDE(i)));
4568 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4569 for (j = 0; j < level.num_android_clone_elements; j++)
4570 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4572 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4574 /* ---------- CAN_CHANGE ----------------------------------------------- */
4575 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4576 for (j = 0; j < element_info[i].num_change_pages; j++)
4577 if (element_info[i].change_page[j].can_change)
4578 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4580 /* ---------- HAS_ACTION ----------------------------------------------- */
4581 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4582 for (j = 0; j < element_info[i].num_change_pages; j++)
4583 if (element_info[i].change_page[j].has_action)
4584 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4586 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4587 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4590 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4591 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4592 element_info[i].crumbled[ACTION_DEFAULT] !=
4593 element_info[i].graphic[ACTION_DEFAULT]);
4595 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4596 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4597 IS_EDITOR_CASCADE_INACTIVE(i)));
4600 /* dynamically adjust element properties according to game engine version */
4602 static int ep_em_slippery_wall[] =
4607 EL_EXPANDABLE_WALL_HORIZONTAL,
4608 EL_EXPANDABLE_WALL_VERTICAL,
4609 EL_EXPANDABLE_WALL_ANY,
4610 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4611 EL_EXPANDABLE_STEELWALL_VERTICAL,
4612 EL_EXPANDABLE_STEELWALL_ANY,
4613 EL_EXPANDABLE_STEELWALL_GROWING,
4617 static int ep_em_explodes_by_fire[] =
4620 EL_EM_DYNAMITE_ACTIVE,
4625 /* special EM style gems behaviour */
4626 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4627 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4628 level.em_slippery_gems);
4630 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4631 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4632 (level.em_slippery_gems &&
4633 engine_version > VERSION_IDENT(2,0,1,0)));
4635 /* special EM style explosion behaviour regarding chain reactions */
4636 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4637 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4638 level.em_explodes_by_fire);
4641 /* this is needed because some graphics depend on element properties */
4642 if (game_status == GAME_MODE_PLAYING)
4643 InitElementGraphicInfo();
4646 void InitElementPropertiesAfterLoading(int engine_version)
4650 /* set some other uninitialized values of custom elements in older levels */
4651 if (engine_version < VERSION_IDENT(3,1,0,0))
4653 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4655 int element = EL_CUSTOM_START + i;
4657 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4659 element_info[element].explosion_delay = 17;
4660 element_info[element].ignition_delay = 8;
4665 void InitElementPropertiesGfxElement()
4669 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4671 struct ElementInfo *ei = &element_info[i];
4673 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4677 static void InitGlobal()
4682 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4684 /* check if element_name_info entry defined for each element in "main.h" */
4685 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4686 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4688 element_info[i].token_name = element_name_info[i].token_name;
4689 element_info[i].class_name = element_name_info[i].class_name;
4690 element_info[i].editor_description= element_name_info[i].editor_description;
4693 /* create hash from image config list */
4694 image_config_hash = newSetupFileHash();
4695 for (i = 0; image_config[i].token != NULL; i++)
4696 setHashEntry(image_config_hash,
4697 image_config[i].token,
4698 image_config[i].value);
4700 /* create hash from element token list */
4701 element_token_hash = newSetupFileHash();
4702 for (i = 0; element_name_info[i].token_name != NULL; i++)
4703 setHashEntry(element_token_hash,
4704 element_name_info[i].token_name,
4707 /* create hash from graphic token list */
4708 graphic_token_hash = newSetupFileHash();
4709 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4710 if (strSuffix(image_config[i].value, ".png") ||
4711 strSuffix(image_config[i].value, ".pcx") ||
4712 strSuffix(image_config[i].value, ".wav") ||
4713 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4714 setHashEntry(graphic_token_hash,
4715 image_config[i].token,
4716 int2str(graphic++, 0));
4718 /* create hash from font token list */
4719 font_token_hash = newSetupFileHash();
4720 for (i = 0; font_info[i].token_name != NULL; i++)
4721 setHashEntry(font_token_hash,
4722 font_info[i].token_name,
4725 /* set default filenames for all cloned graphics in static configuration */
4726 for (i = 0; image_config[i].token != NULL; i++)
4728 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4730 char *token = image_config[i].token;
4731 char *token_clone_from = getStringCat2(token, ".clone_from");
4732 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4734 if (token_cloned != NULL)
4736 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4738 if (value_cloned != NULL)
4740 /* set default filename in static configuration */
4741 image_config[i].value = value_cloned;
4743 /* set default filename in image config hash */
4744 setHashEntry(image_config_hash, token, value_cloned);
4748 free(token_clone_from);
4752 /* always start with reliable default values (all elements) */
4753 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4754 ActiveElement[i] = i;
4756 /* now add all entries that have an active state (active elements) */
4757 for (i = 0; element_with_active_state[i].element != -1; i++)
4759 int element = element_with_active_state[i].element;
4760 int element_active = element_with_active_state[i].element_active;
4762 ActiveElement[element] = element_active;
4765 /* always start with reliable default values (all buttons) */
4766 for (i = 0; i < NUM_IMAGE_FILES; i++)
4767 ActiveButton[i] = i;
4769 /* now add all entries that have an active state (active buttons) */
4770 for (i = 0; button_with_active_state[i].button != -1; i++)
4772 int button = button_with_active_state[i].button;
4773 int button_active = button_with_active_state[i].button_active;
4775 ActiveButton[button] = button_active;
4778 /* always start with reliable default values (all fonts) */
4779 for (i = 0; i < NUM_FONTS; i++)
4782 /* now add all entries that have an active state (active fonts) */
4783 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4785 int font = font_with_active_state[i].font_nr;
4786 int font_active = font_with_active_state[i].font_nr_active;
4788 ActiveFont[font] = font_active;
4791 global.autoplay_leveldir = NULL;
4792 global.convert_leveldir = NULL;
4793 global.create_images_dir = NULL;
4795 global.frames_per_second = 0;
4797 global.border_status = GAME_MODE_LOADING;
4798 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4800 global.use_envelope_request = FALSE;
4803 void Execute_Command(char *command)
4807 if (strEqual(command, "print graphicsinfo.conf"))
4809 Print("# You can configure additional/alternative image files here.\n");
4810 Print("# (The entries below are default and therefore commented out.)\n");
4812 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4814 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4817 for (i = 0; image_config[i].token != NULL; i++)
4818 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4819 image_config[i].value));
4823 else if (strEqual(command, "print soundsinfo.conf"))
4825 Print("# You can configure additional/alternative sound files here.\n");
4826 Print("# (The entries below are default and therefore commented out.)\n");
4828 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4830 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4833 for (i = 0; sound_config[i].token != NULL; i++)
4834 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4835 sound_config[i].value));
4839 else if (strEqual(command, "print musicinfo.conf"))
4841 Print("# You can configure additional/alternative music files here.\n");
4842 Print("# (The entries below are default and therefore commented out.)\n");
4844 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4846 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4849 for (i = 0; music_config[i].token != NULL; i++)
4850 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4851 music_config[i].value));
4855 else if (strEqual(command, "print editorsetup.conf"))
4857 Print("# You can configure your personal editor element list here.\n");
4858 Print("# (The entries below are default and therefore commented out.)\n");
4861 /* this is needed to be able to check element list for cascade elements */
4862 InitElementPropertiesStatic();
4863 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4865 PrintEditorElementList();
4869 else if (strEqual(command, "print helpanim.conf"))
4871 Print("# You can configure different element help animations here.\n");
4872 Print("# (The entries below are default and therefore commented out.)\n");
4875 for (i = 0; helpanim_config[i].token != NULL; i++)
4877 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4878 helpanim_config[i].value));
4880 if (strEqual(helpanim_config[i].token, "end"))
4886 else if (strEqual(command, "print helptext.conf"))
4888 Print("# You can configure different element help text here.\n");
4889 Print("# (The entries below are default and therefore commented out.)\n");
4892 for (i = 0; helptext_config[i].token != NULL; i++)
4893 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4894 helptext_config[i].value));
4898 else if (strPrefix(command, "dump level "))
4900 char *filename = &command[11];
4902 if (!fileExists(filename))
4903 Error(ERR_EXIT, "cannot open file '%s'", filename);
4905 LoadLevelFromFilename(&level, filename);
4910 else if (strPrefix(command, "dump tape "))
4912 char *filename = &command[10];
4914 if (!fileExists(filename))
4915 Error(ERR_EXIT, "cannot open file '%s'", filename);
4917 LoadTapeFromFilename(filename);
4922 else if (strPrefix(command, "autotest ") ||
4923 strPrefix(command, "autoplay ") ||
4924 strPrefix(command, "autoffwd ") ||
4925 strPrefix(command, "autowarp "))
4927 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4929 global.autoplay_mode =
4930 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
4931 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
4932 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
4933 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
4934 AUTOPLAY_MODE_NONE);
4936 while (*str_ptr != '\0') /* continue parsing string */
4938 /* cut leading whitespace from string, replace it by string terminator */
4939 while (*str_ptr == ' ' || *str_ptr == '\t')
4942 if (*str_ptr == '\0') /* end of string reached */
4945 if (global.autoplay_leveldir == NULL) /* read level set string */
4947 global.autoplay_leveldir = str_ptr;
4948 global.autoplay_all = TRUE; /* default: play all tapes */
4950 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4951 global.autoplay_level[i] = FALSE;
4953 else /* read level number string */
4955 int level_nr = atoi(str_ptr); /* get level_nr value */
4957 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4958 global.autoplay_level[level_nr] = TRUE;
4960 global.autoplay_all = FALSE;
4963 /* advance string pointer to the next whitespace (or end of string) */
4964 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4968 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
4969 program.headless = TRUE;
4971 else if (strPrefix(command, "convert "))
4973 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4974 char *str_ptr = strchr(str_copy, ' ');
4976 global.convert_leveldir = str_copy;
4977 global.convert_level_nr = -1;
4979 if (str_ptr != NULL) /* level number follows */
4981 *str_ptr++ = '\0'; /* terminate leveldir string */
4982 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4985 else if (strPrefix(command, "create images "))
4987 global.create_images_dir = getStringCopy(&command[14]);
4989 if (access(global.create_images_dir, W_OK) != 0)
4990 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4991 global.create_images_dir);
4993 else if (strPrefix(command, "create CE image "))
4995 CreateCustomElementImages(&command[16]);
5001 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5005 static void InitSetup()
5007 LoadSetup(); /* global setup info */
5009 /* set some options from setup file */
5011 if (setup.options.verbose)
5012 options.verbose = TRUE;
5015 static void InitGameInfo()
5017 game.restart_level = FALSE;
5020 static void InitPlayerInfo()
5024 /* choose default local player */
5025 local_player = &stored_player[0];
5027 for (i = 0; i < MAX_PLAYERS; i++)
5028 stored_player[i].connected = FALSE;
5030 local_player->connected = TRUE;
5033 static void InitArtworkInfo()
5038 static char *get_string_in_brackets(char *string)
5040 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5042 sprintf(string_in_brackets, "[%s]", string);
5044 return string_in_brackets;
5047 static char *get_level_id_suffix(int id_nr)
5049 char *id_suffix = checked_malloc(1 + 3 + 1);
5051 if (id_nr < 0 || id_nr > 999)
5054 sprintf(id_suffix, ".%03d", id_nr);
5059 static void InitArtworkConfig()
5061 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5063 NUM_GLOBAL_ANIM_TOKENS + 1];
5064 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5065 NUM_GLOBAL_ANIM_TOKENS + 1];
5066 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5067 NUM_GLOBAL_ANIM_TOKENS + 1];
5068 static char *action_id_suffix[NUM_ACTIONS + 1];
5069 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5070 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5071 static char *level_id_suffix[MAX_LEVELS + 1];
5072 static char *dummy[1] = { NULL };
5073 static char *ignore_generic_tokens[] =
5079 static char **ignore_image_tokens;
5080 static char **ignore_sound_tokens;
5081 static char **ignore_music_tokens;
5082 int num_ignore_generic_tokens;
5083 int num_ignore_image_tokens;
5084 int num_ignore_sound_tokens;
5085 int num_ignore_music_tokens;
5088 /* dynamically determine list of generic tokens to be ignored */
5089 num_ignore_generic_tokens = 0;
5090 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5091 num_ignore_generic_tokens++;
5093 /* dynamically determine list of image tokens to be ignored */
5094 num_ignore_image_tokens = num_ignore_generic_tokens;
5095 for (i = 0; image_config_vars[i].token != NULL; i++)
5096 num_ignore_image_tokens++;
5097 ignore_image_tokens =
5098 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5099 for (i = 0; i < num_ignore_generic_tokens; i++)
5100 ignore_image_tokens[i] = ignore_generic_tokens[i];
5101 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5102 ignore_image_tokens[num_ignore_generic_tokens + i] =
5103 image_config_vars[i].token;
5104 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5106 /* dynamically determine list of sound tokens to be ignored */
5107 num_ignore_sound_tokens = num_ignore_generic_tokens;
5108 ignore_sound_tokens =
5109 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5110 for (i = 0; i < num_ignore_generic_tokens; i++)
5111 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5112 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5114 /* dynamically determine list of music tokens to be ignored */
5115 num_ignore_music_tokens = num_ignore_generic_tokens;
5116 ignore_music_tokens =
5117 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5118 for (i = 0; i < num_ignore_generic_tokens; i++)
5119 ignore_music_tokens[i] = ignore_generic_tokens[i];
5120 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5122 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5123 image_id_prefix[i] = element_info[i].token_name;
5124 for (i = 0; i < NUM_FONTS; i++)
5125 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5126 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5127 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5128 global_anim_info[i].token_name;
5129 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5131 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5132 sound_id_prefix[i] = element_info[i].token_name;
5133 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5134 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5135 get_string_in_brackets(element_info[i].class_name);
5136 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5137 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5138 global_anim_info[i].token_name;
5139 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5141 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5142 music_id_prefix[i] = music_prefix_info[i].prefix;
5143 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5144 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5145 global_anim_info[i].token_name;
5146 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5148 for (i = 0; i < NUM_ACTIONS; i++)
5149 action_id_suffix[i] = element_action_info[i].suffix;
5150 action_id_suffix[NUM_ACTIONS] = NULL;
5152 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5153 direction_id_suffix[i] = element_direction_info[i].suffix;
5154 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5156 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5157 special_id_suffix[i] = special_suffix_info[i].suffix;
5158 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5160 for (i = 0; i < MAX_LEVELS; i++)
5161 level_id_suffix[i] = get_level_id_suffix(i);
5162 level_id_suffix[MAX_LEVELS] = NULL;
5164 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5165 image_id_prefix, action_id_suffix, direction_id_suffix,
5166 special_id_suffix, ignore_image_tokens);
5167 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5168 sound_id_prefix, action_id_suffix, dummy,
5169 special_id_suffix, ignore_sound_tokens);
5170 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5171 music_id_prefix, action_id_suffix, special_id_suffix,
5172 level_id_suffix, ignore_music_tokens);
5175 static void InitMixer()
5182 void InitGfxBuffers()
5184 static int win_xsize_last = -1;
5185 static int win_ysize_last = -1;
5187 /* create additional image buffers for double-buffering and cross-fading */
5189 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5191 /* used to temporarily store the backbuffer -- only re-create if changed */
5192 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5193 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5195 win_xsize_last = WIN_XSIZE;
5196 win_ysize_last = WIN_YSIZE;
5199 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5200 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5201 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5202 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5204 /* initialize screen properties */
5205 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5206 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5208 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5209 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5210 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5211 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5212 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5213 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5215 /* required if door size definitions have changed */
5216 InitGraphicCompatibilityInfo_Doors();
5218 InitGfxBuffers_EM();
5219 InitGfxBuffers_SP();
5224 struct GraphicInfo *graphic_info_last = graphic_info;
5225 char *filename_font_initial = NULL;
5226 char *filename_anim_initial = NULL;
5227 Bitmap *bitmap_font_initial = NULL;
5231 /* determine settings for initial font (for displaying startup messages) */
5232 for (i = 0; image_config[i].token != NULL; i++)
5234 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5236 char font_token[128];
5239 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5240 len_font_token = strlen(font_token);
5242 if (strEqual(image_config[i].token, font_token))
5243 filename_font_initial = image_config[i].value;
5244 else if (strlen(image_config[i].token) > len_font_token &&
5245 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5247 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5248 font_initial[j].src_x = atoi(image_config[i].value);
5249 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5250 font_initial[j].src_y = atoi(image_config[i].value);
5251 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5252 font_initial[j].width = atoi(image_config[i].value);
5253 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5254 font_initial[j].height = atoi(image_config[i].value);
5259 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5261 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5262 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5265 if (filename_font_initial == NULL) /* should not happen */
5266 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5269 InitGfxCustomArtworkInfo();
5270 InitGfxOtherSettings();
5272 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5274 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5275 font_initial[j].bitmap = bitmap_font_initial;
5277 InitFontGraphicInfo();
5279 font_height = getFontHeight(FC_RED);
5281 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5282 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5283 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5286 DrawInitText("Loading graphics", 120, FC_GREEN);
5288 /* initialize settings for busy animation with default values */
5289 int parameter[NUM_GFX_ARGS];
5290 for (i = 0; i < NUM_GFX_ARGS; i++)
5291 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5292 image_config_suffix[i].token,
5293 image_config_suffix[i].type);
5295 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5296 int len_anim_token = strlen(anim_token);
5298 /* read settings for busy animation from default custom artwork config */
5299 char *gfx_config_filename = getPath3(options.graphics_directory,
5301 GRAPHICSINFO_FILENAME);
5303 if (fileExists(gfx_config_filename))
5305 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5307 if (setup_file_hash)
5309 char *filename = getHashEntry(setup_file_hash, anim_token);
5313 filename_anim_initial = getStringCopy(filename);
5315 for (j = 0; image_config_suffix[j].token != NULL; j++)
5317 int type = image_config_suffix[j].type;
5318 char *suffix = image_config_suffix[j].token;
5319 char *token = getStringCat2(anim_token, suffix);
5320 char *value = getHashEntry(setup_file_hash, token);
5322 checked_free(token);
5325 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5329 freeSetupFileHash(setup_file_hash);
5333 if (filename_anim_initial == NULL)
5335 /* read settings for busy animation from static default artwork config */
5336 for (i = 0; image_config[i].token != NULL; i++)
5338 if (strEqual(image_config[i].token, anim_token))
5339 filename_anim_initial = getStringCopy(image_config[i].value);
5340 else if (strlen(image_config[i].token) > len_anim_token &&
5341 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5343 for (j = 0; image_config_suffix[j].token != NULL; j++)
5345 if (strEqual(&image_config[i].token[len_anim_token],
5346 image_config_suffix[j].token))
5348 get_graphic_parameter_value(image_config[i].value,
5349 image_config_suffix[j].token,
5350 image_config_suffix[j].type);
5356 if (filename_anim_initial == NULL) /* should not happen */
5357 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5359 anim_initial.bitmaps =
5360 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5362 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5363 LoadCustomImage(filename_anim_initial);
5365 checked_free(filename_anim_initial);
5367 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5369 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5371 graphic_info = graphic_info_last;
5373 init.busy.width = anim_initial.width;
5374 init.busy.height = anim_initial.height;
5376 InitMenuDesignSettings_Static();
5378 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5379 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5380 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5382 gfx.fade_border_source_status = global.border_status;
5383 gfx.fade_border_target_status = global.border_status;
5384 gfx.masked_border_bitmap_ptr = backbuffer;
5386 /* use copy of busy animation to prevent change while reloading artwork */
5390 void InitGfxBackground()
5392 fieldbuffer = bitmap_db_field;
5393 SetDrawtoField(DRAW_TO_BACKBUFFER);
5395 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5397 redraw_mask = REDRAW_ALL;
5400 static void InitLevelInfo()
5402 LoadLevelInfo(); /* global level info */
5403 LoadLevelSetup_LastSeries(); /* last played series info */
5404 LoadLevelSetup_SeriesInfo(); /* last played level info */
5406 if (global.autoplay_leveldir &&
5407 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5409 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5410 global.autoplay_leveldir);
5411 if (leveldir_current == NULL)
5412 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5416 static void InitLevelArtworkInfo()
5418 LoadLevelArtworkInfo();
5421 static void InitImages()
5423 print_timestamp_init("InitImages");
5426 printf("::: leveldir_current->identifier == '%s'\n",
5427 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5428 printf("::: leveldir_current->graphics_path == '%s'\n",
5429 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5430 printf("::: leveldir_current->graphics_set == '%s'\n",
5431 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5432 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5433 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5436 setLevelArtworkDir(artwork.gfx_first);
5439 printf("::: leveldir_current->identifier == '%s'\n",
5440 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5441 printf("::: leveldir_current->graphics_path == '%s'\n",
5442 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5443 printf("::: leveldir_current->graphics_set == '%s'\n",
5444 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5445 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5446 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5450 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5451 leveldir_current->identifier,
5452 artwork.gfx_current_identifier,
5453 artwork.gfx_current->identifier,
5454 leveldir_current->graphics_set,
5455 leveldir_current->graphics_path);
5458 UPDATE_BUSY_STATE();
5460 ReloadCustomImages();
5461 print_timestamp_time("ReloadCustomImages");
5463 UPDATE_BUSY_STATE();
5465 LoadCustomElementDescriptions();
5466 print_timestamp_time("LoadCustomElementDescriptions");
5468 UPDATE_BUSY_STATE();
5470 LoadMenuDesignSettings();
5471 print_timestamp_time("LoadMenuDesignSettings");
5473 UPDATE_BUSY_STATE();
5475 ReinitializeGraphics();
5476 print_timestamp_time("ReinitializeGraphics");
5478 LoadMenuDesignSettings_AfterGraphics();
5479 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5481 UPDATE_BUSY_STATE();
5483 print_timestamp_done("InitImages");
5486 static void InitSound(char *identifier)
5488 print_timestamp_init("InitSound");
5490 if (identifier == NULL)
5491 identifier = artwork.snd_current->identifier;
5493 /* set artwork path to send it to the sound server process */
5494 setLevelArtworkDir(artwork.snd_first);
5496 InitReloadCustomSounds(identifier);
5497 print_timestamp_time("InitReloadCustomSounds");
5499 ReinitializeSounds();
5500 print_timestamp_time("ReinitializeSounds");
5502 print_timestamp_done("InitSound");
5505 static void InitMusic(char *identifier)
5507 print_timestamp_init("InitMusic");
5509 if (identifier == NULL)
5510 identifier = artwork.mus_current->identifier;
5512 /* set artwork path to send it to the sound server process */
5513 setLevelArtworkDir(artwork.mus_first);
5515 InitReloadCustomMusic(identifier);
5516 print_timestamp_time("InitReloadCustomMusic");
5518 ReinitializeMusic();
5519 print_timestamp_time("ReinitializeMusic");
5521 print_timestamp_done("InitMusic");
5524 static void InitArtworkDone()
5526 if (program.headless)
5529 InitGlobalAnimations();
5532 void InitNetworkServer()
5534 #if defined(NETWORK_AVALIABLE)
5538 if (!options.network)
5541 #if defined(NETWORK_AVALIABLE)
5542 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5544 if (!ConnectToServer(options.server_host, options.server_port))
5545 Error(ERR_EXIT, "cannot connect to network game server");
5547 SendToServer_PlayerName(setup.player_name);
5548 SendToServer_ProtocolVersion();
5551 SendToServer_NrWanted(nr_wanted);
5555 static boolean CheckArtworkConfigForCustomElements(char *filename)
5557 SetupFileHash *setup_file_hash;
5558 boolean redefined_ce_found = FALSE;
5560 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5562 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5564 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5566 char *token = HASH_ITERATION_TOKEN(itr);
5568 if (strPrefix(token, "custom_"))
5570 redefined_ce_found = TRUE;
5575 END_HASH_ITERATION(setup_file_hash, itr)
5577 freeSetupFileHash(setup_file_hash);
5580 return redefined_ce_found;
5583 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5585 char *filename_base, *filename_local;
5586 boolean redefined_ce_found = FALSE;
5588 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5591 printf("::: leveldir_current->identifier == '%s'\n",
5592 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5593 printf("::: leveldir_current->graphics_path == '%s'\n",
5594 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5595 printf("::: leveldir_current->graphics_set == '%s'\n",
5596 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5597 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5598 leveldir_current == NULL ? "[NULL]" :
5599 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5602 /* first look for special artwork configured in level series config */
5603 filename_base = getCustomArtworkLevelConfigFilename(type);
5606 printf("::: filename_base == '%s'\n", filename_base);
5609 if (fileExists(filename_base))
5610 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5612 filename_local = getCustomArtworkConfigFilename(type);
5615 printf("::: filename_local == '%s'\n", filename_local);
5618 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5619 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5622 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5625 return redefined_ce_found;
5628 static void InitOverrideArtwork()
5630 boolean redefined_ce_found = FALSE;
5632 /* to check if this level set redefines any CEs, do not use overriding */
5633 gfx.override_level_graphics = FALSE;
5634 gfx.override_level_sounds = FALSE;
5635 gfx.override_level_music = FALSE;
5637 /* now check if this level set has definitions for custom elements */
5638 if (setup.override_level_graphics == AUTO ||
5639 setup.override_level_sounds == AUTO ||
5640 setup.override_level_music == AUTO)
5641 redefined_ce_found =
5642 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5643 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5644 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5647 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5650 if (redefined_ce_found)
5652 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5653 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5654 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5655 gfx.override_level_music = (setup.override_level_music == TRUE);
5659 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5660 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5661 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5662 gfx.override_level_music = (setup.override_level_music != FALSE);
5666 printf("::: => %d, %d, %d\n",
5667 gfx.override_level_graphics,
5668 gfx.override_level_sounds,
5669 gfx.override_level_music);
5673 static char *getNewArtworkIdentifier(int type)
5675 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5676 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5677 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5678 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5679 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5680 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5681 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5682 char *leveldir_identifier = leveldir_current->identifier;
5683 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5684 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5685 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5686 char *artwork_current_identifier;
5687 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5689 /* leveldir_current may be invalid (level group, parent link) */
5690 if (!validLevelSeries(leveldir_current))
5693 /* 1st step: determine artwork set to be activated in descending order:
5694 --------------------------------------------------------------------
5695 1. setup artwork (when configured to override everything else)
5696 2. artwork set configured in "levelinfo.conf" of current level set
5697 (artwork in level directory will have priority when loading later)
5698 3. artwork in level directory (stored in artwork sub-directory)
5699 4. setup artwork (currently configured in setup menu) */
5701 if (setup_override_artwork)
5702 artwork_current_identifier = setup_artwork_set;
5703 else if (leveldir_artwork_set != NULL)
5704 artwork_current_identifier = leveldir_artwork_set;
5705 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5706 artwork_current_identifier = leveldir_identifier;
5708 artwork_current_identifier = setup_artwork_set;
5711 /* 2nd step: check if it is really needed to reload artwork set
5712 ------------------------------------------------------------ */
5714 /* ---------- reload if level set and also artwork set has changed ------- */
5715 if (leveldir_current_identifier[type] != leveldir_identifier &&
5716 (last_has_level_artwork_set[type] || has_level_artwork_set))
5717 artwork_new_identifier = artwork_current_identifier;
5719 leveldir_current_identifier[type] = leveldir_identifier;
5720 last_has_level_artwork_set[type] = has_level_artwork_set;
5722 /* ---------- reload if "override artwork" setting has changed ----------- */
5723 if (last_override_level_artwork[type] != setup_override_artwork)
5724 artwork_new_identifier = artwork_current_identifier;
5726 last_override_level_artwork[type] = setup_override_artwork;
5728 /* ---------- reload if current artwork identifier has changed ----------- */
5729 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5730 artwork_current_identifier))
5731 artwork_new_identifier = artwork_current_identifier;
5733 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5735 /* ---------- do not reload directly after starting ---------------------- */
5736 if (!initialized[type])
5737 artwork_new_identifier = NULL;
5739 initialized[type] = TRUE;
5741 return artwork_new_identifier;
5744 void ReloadCustomArtwork(int force_reload)
5746 int last_game_status = game_status; /* save current game status */
5747 char *gfx_new_identifier;
5748 char *snd_new_identifier;
5749 char *mus_new_identifier;
5750 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5751 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5752 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5753 boolean reload_needed;
5755 InitOverrideArtwork();
5757 force_reload_gfx |= AdjustGraphicsForEMC();
5759 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5760 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5761 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5763 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5764 snd_new_identifier != NULL || force_reload_snd ||
5765 mus_new_identifier != NULL || force_reload_mus);
5770 print_timestamp_init("ReloadCustomArtwork");
5772 SetGameStatus(GAME_MODE_LOADING);
5774 FadeOut(REDRAW_ALL);
5776 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5777 print_timestamp_time("ClearRectangle");
5781 if (gfx_new_identifier != NULL || force_reload_gfx)
5784 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5785 artwork.gfx_current_identifier,
5787 artwork.gfx_current->identifier,
5788 leveldir_current->graphics_set);
5792 print_timestamp_time("InitImages");
5795 if (snd_new_identifier != NULL || force_reload_snd)
5797 InitSound(snd_new_identifier);
5798 print_timestamp_time("InitSound");
5801 if (mus_new_identifier != NULL || force_reload_mus)
5803 InitMusic(mus_new_identifier);
5804 print_timestamp_time("InitMusic");
5809 SetGameStatus(last_game_status); /* restore current game status */
5811 init_last = init; /* switch to new busy animation */
5813 FadeOut(REDRAW_ALL);
5815 RedrawGlobalBorder();
5817 /* force redraw of (open or closed) door graphics */
5818 SetDoorState(DOOR_OPEN_ALL);
5819 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5821 FadeSetEnterScreen();
5822 FadeSkipNextFadeOut();
5824 print_timestamp_done("ReloadCustomArtwork");
5826 LimitScreenUpdates(FALSE);
5829 void KeyboardAutoRepeatOffUnlessAutoplay()
5831 if (global.autoplay_leveldir == NULL)
5832 KeyboardAutoRepeatOff();
5835 void DisplayExitMessage(char *format, va_list ap)
5837 // check if draw buffer and fonts for exit message are already available
5838 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5841 int font_1 = FC_RED;
5842 int font_2 = FC_YELLOW;
5843 int font_3 = FC_BLUE;
5844 int font_width = getFontWidth(font_2);
5845 int font_height = getFontHeight(font_2);
5848 int sxsize = WIN_XSIZE - 2 * sx;
5849 int sysize = WIN_YSIZE - 2 * sy;
5850 int line_length = sxsize / font_width;
5851 int max_lines = sysize / font_height;
5852 int num_lines_printed;
5856 gfx.sxsize = sxsize;
5857 gfx.sysize = sysize;
5861 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5863 DrawTextSCentered(sy, font_1, "Fatal error:");
5864 sy += 3 * font_height;;
5867 DrawTextBufferVA(sx, sy, format, ap, font_2,
5868 line_length, line_length, max_lines,
5869 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5870 sy += (num_lines_printed + 3) * font_height;
5872 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5873 sy += 3 * font_height;
5876 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5877 line_length, line_length, max_lines,
5878 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5880 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5882 redraw_mask = REDRAW_ALL;
5884 /* force drawing exit message even if screen updates are currently limited */
5885 LimitScreenUpdates(FALSE);
5889 /* deactivate toons on error message screen */
5890 setup.toons = FALSE;
5892 WaitForEventToContinue();
5896 /* ========================================================================= */
5898 /* ========================================================================= */
5902 print_timestamp_init("OpenAll");
5904 SetGameStatus(GAME_MODE_LOADING);
5908 InitGlobal(); /* initialize some global variables */
5910 print_timestamp_time("[init global stuff]");
5914 print_timestamp_time("[init setup/config stuff (1)]");
5918 if (options.execute_command)
5919 Execute_Command(options.execute_command);
5921 if (options.serveronly)
5923 #if defined(PLATFORM_UNIX)
5924 NetworkServer(options.server_port, options.serveronly);
5926 Error(ERR_WARN, "networking only supported in Unix version");
5929 exit(0); /* never reached, server loops forever */
5933 print_timestamp_time("[init setup/config stuff (2)]");
5935 print_timestamp_time("[init setup/config stuff (3)]");
5936 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5937 print_timestamp_time("[init setup/config stuff (4)]");
5938 InitArtworkConfig(); /* needed before forking sound child process */
5939 print_timestamp_time("[init setup/config stuff (5)]");
5941 print_timestamp_time("[init setup/config stuff (6)]");
5943 InitRND(NEW_RANDOMIZE);
5944 InitSimpleRandom(NEW_RANDOMIZE);
5948 print_timestamp_time("[init setup/config stuff]");
5951 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5955 print_timestamp_time("[init video stuff]");
5957 InitElementPropertiesStatic();
5958 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5959 InitElementPropertiesGfxElement();
5961 print_timestamp_time("[init element properties stuff]");
5965 print_timestamp_time("InitGfx");
5968 print_timestamp_time("InitLevelInfo");
5970 InitLevelArtworkInfo();
5971 print_timestamp_time("InitLevelArtworkInfo");
5973 InitOverrideArtwork(); /* needs to know current level directory */
5974 print_timestamp_time("InitOverrideArtwork");
5976 InitImages(); /* needs to know current level directory */
5977 print_timestamp_time("InitImages");
5979 InitSound(NULL); /* needs to know current level directory */
5980 print_timestamp_time("InitSound");
5982 InitMusic(NULL); /* needs to know current level directory */
5983 print_timestamp_time("InitMusic");
5987 InitGfxBackground();
5992 if (global.autoplay_leveldir)
5997 else if (global.convert_leveldir)
6002 else if (global.create_images_dir)
6004 CreateLevelSketchImages();
6008 SetGameStatus(GAME_MODE_MAIN);
6010 FadeSetEnterScreen();
6011 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6012 FadeSkipNextFadeOut();
6014 print_timestamp_time("[post-artwork]");
6016 print_timestamp_done("OpenAll");
6020 InitNetworkServer();
6023 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6025 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6026 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6027 #if defined(PLATFORM_ANDROID)
6028 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6029 SDL_AndroidGetInternalStoragePath());
6030 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6031 SDL_AndroidGetExternalStoragePath());
6032 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6033 (SDL_AndroidGetExternalStorageState() ==
6034 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
6035 SDL_AndroidGetExternalStorageState() ==
6036 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
6041 void CloseAllAndExit(int exit_value)
6046 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6053 #if defined(TARGET_SDL)
6054 #if defined(TARGET_SDL2)
6056 // set a flag to tell the network server thread to quit and wait for it
6057 // using SDL_WaitThread()
6059 if (network_server) /* terminate network server */
6060 SDL_KillThread(server_thread);
6064 CloseVideoDisplay();
6065 ClosePlatformDependentStuff();
6067 if (exit_value != 0)
6069 /* fall back to default level set (current set may have caused an error) */
6070 SaveLevelSetup_LastSeries_Deactivate();
6072 /* tell user where to find error log file which may contain more details */
6073 // (error notification now directly displayed on screen inside R'n'D
6074 // NotifyUserAboutErrorFile(); /* currently only works for Windows */