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 program.headless = TRUE;
4987 else if (strPrefix(command, "create images "))
4989 global.create_images_dir = getStringCopy(&command[14]);
4991 if (access(global.create_images_dir, W_OK) != 0)
4992 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4993 global.create_images_dir);
4995 else if (strPrefix(command, "create CE image "))
4997 CreateCustomElementImages(&command[16]);
5003 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5007 static void InitSetup()
5009 LoadSetup(); /* global setup info */
5011 /* set some options from setup file */
5013 if (setup.options.verbose)
5014 options.verbose = TRUE;
5017 static void InitGameInfo()
5019 game.restart_level = FALSE;
5022 static void InitPlayerInfo()
5026 /* choose default local player */
5027 local_player = &stored_player[0];
5029 for (i = 0; i < MAX_PLAYERS; i++)
5030 stored_player[i].connected = FALSE;
5032 local_player->connected = TRUE;
5035 static void InitArtworkInfo()
5040 static char *get_string_in_brackets(char *string)
5042 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5044 sprintf(string_in_brackets, "[%s]", string);
5046 return string_in_brackets;
5049 static char *get_level_id_suffix(int id_nr)
5051 char *id_suffix = checked_malloc(1 + 3 + 1);
5053 if (id_nr < 0 || id_nr > 999)
5056 sprintf(id_suffix, ".%03d", id_nr);
5061 static void InitArtworkConfig()
5063 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5065 NUM_GLOBAL_ANIM_TOKENS + 1];
5066 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5067 NUM_GLOBAL_ANIM_TOKENS + 1];
5068 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5069 NUM_GLOBAL_ANIM_TOKENS + 1];
5070 static char *action_id_suffix[NUM_ACTIONS + 1];
5071 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5072 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5073 static char *level_id_suffix[MAX_LEVELS + 1];
5074 static char *dummy[1] = { NULL };
5075 static char *ignore_generic_tokens[] =
5081 static char **ignore_image_tokens;
5082 static char **ignore_sound_tokens;
5083 static char **ignore_music_tokens;
5084 int num_ignore_generic_tokens;
5085 int num_ignore_image_tokens;
5086 int num_ignore_sound_tokens;
5087 int num_ignore_music_tokens;
5090 /* dynamically determine list of generic tokens to be ignored */
5091 num_ignore_generic_tokens = 0;
5092 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5093 num_ignore_generic_tokens++;
5095 /* dynamically determine list of image tokens to be ignored */
5096 num_ignore_image_tokens = num_ignore_generic_tokens;
5097 for (i = 0; image_config_vars[i].token != NULL; i++)
5098 num_ignore_image_tokens++;
5099 ignore_image_tokens =
5100 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5101 for (i = 0; i < num_ignore_generic_tokens; i++)
5102 ignore_image_tokens[i] = ignore_generic_tokens[i];
5103 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5104 ignore_image_tokens[num_ignore_generic_tokens + i] =
5105 image_config_vars[i].token;
5106 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5108 /* dynamically determine list of sound tokens to be ignored */
5109 num_ignore_sound_tokens = num_ignore_generic_tokens;
5110 ignore_sound_tokens =
5111 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5112 for (i = 0; i < num_ignore_generic_tokens; i++)
5113 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5114 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5116 /* dynamically determine list of music tokens to be ignored */
5117 num_ignore_music_tokens = num_ignore_generic_tokens;
5118 ignore_music_tokens =
5119 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5120 for (i = 0; i < num_ignore_generic_tokens; i++)
5121 ignore_music_tokens[i] = ignore_generic_tokens[i];
5122 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5124 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5125 image_id_prefix[i] = element_info[i].token_name;
5126 for (i = 0; i < NUM_FONTS; i++)
5127 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5128 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5129 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5130 global_anim_info[i].token_name;
5131 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5133 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5134 sound_id_prefix[i] = element_info[i].token_name;
5135 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5136 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5137 get_string_in_brackets(element_info[i].class_name);
5138 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5139 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5140 global_anim_info[i].token_name;
5141 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5143 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5144 music_id_prefix[i] = music_prefix_info[i].prefix;
5145 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5146 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5147 global_anim_info[i].token_name;
5148 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5150 for (i = 0; i < NUM_ACTIONS; i++)
5151 action_id_suffix[i] = element_action_info[i].suffix;
5152 action_id_suffix[NUM_ACTIONS] = NULL;
5154 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5155 direction_id_suffix[i] = element_direction_info[i].suffix;
5156 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5158 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5159 special_id_suffix[i] = special_suffix_info[i].suffix;
5160 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5162 for (i = 0; i < MAX_LEVELS; i++)
5163 level_id_suffix[i] = get_level_id_suffix(i);
5164 level_id_suffix[MAX_LEVELS] = NULL;
5166 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5167 image_id_prefix, action_id_suffix, direction_id_suffix,
5168 special_id_suffix, ignore_image_tokens);
5169 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5170 sound_id_prefix, action_id_suffix, dummy,
5171 special_id_suffix, ignore_sound_tokens);
5172 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5173 music_id_prefix, action_id_suffix, special_id_suffix,
5174 level_id_suffix, ignore_music_tokens);
5177 static void InitMixer()
5184 void InitGfxBuffers()
5186 static int win_xsize_last = -1;
5187 static int win_ysize_last = -1;
5189 /* create additional image buffers for double-buffering and cross-fading */
5191 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5193 /* used to temporarily store the backbuffer -- only re-create if changed */
5194 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5195 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5197 win_xsize_last = WIN_XSIZE;
5198 win_ysize_last = WIN_YSIZE;
5201 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5202 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5203 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5204 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5206 /* initialize screen properties */
5207 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5208 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5210 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5211 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5212 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5213 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5214 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5215 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5217 /* required if door size definitions have changed */
5218 InitGraphicCompatibilityInfo_Doors();
5220 InitGfxBuffers_EM();
5221 InitGfxBuffers_SP();
5226 struct GraphicInfo *graphic_info_last = graphic_info;
5227 char *filename_font_initial = NULL;
5228 char *filename_anim_initial = NULL;
5229 Bitmap *bitmap_font_initial = NULL;
5233 /* determine settings for initial font (for displaying startup messages) */
5234 for (i = 0; image_config[i].token != NULL; i++)
5236 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5238 char font_token[128];
5241 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5242 len_font_token = strlen(font_token);
5244 if (strEqual(image_config[i].token, font_token))
5245 filename_font_initial = image_config[i].value;
5246 else if (strlen(image_config[i].token) > len_font_token &&
5247 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5249 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5250 font_initial[j].src_x = atoi(image_config[i].value);
5251 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5252 font_initial[j].src_y = atoi(image_config[i].value);
5253 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5254 font_initial[j].width = atoi(image_config[i].value);
5255 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5256 font_initial[j].height = atoi(image_config[i].value);
5261 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5263 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5264 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5267 if (filename_font_initial == NULL) /* should not happen */
5268 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5271 InitGfxCustomArtworkInfo();
5272 InitGfxOtherSettings();
5274 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5276 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5277 font_initial[j].bitmap = bitmap_font_initial;
5279 InitFontGraphicInfo();
5281 font_height = getFontHeight(FC_RED);
5283 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5284 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5285 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5288 DrawInitText("Loading graphics", 120, FC_GREEN);
5290 /* initialize settings for busy animation with default values */
5291 int parameter[NUM_GFX_ARGS];
5292 for (i = 0; i < NUM_GFX_ARGS; i++)
5293 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5294 image_config_suffix[i].token,
5295 image_config_suffix[i].type);
5297 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5298 int len_anim_token = strlen(anim_token);
5300 /* read settings for busy animation from default custom artwork config */
5301 char *gfx_config_filename = getPath3(options.graphics_directory,
5303 GRAPHICSINFO_FILENAME);
5305 if (fileExists(gfx_config_filename))
5307 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5309 if (setup_file_hash)
5311 char *filename = getHashEntry(setup_file_hash, anim_token);
5315 filename_anim_initial = getStringCopy(filename);
5317 for (j = 0; image_config_suffix[j].token != NULL; j++)
5319 int type = image_config_suffix[j].type;
5320 char *suffix = image_config_suffix[j].token;
5321 char *token = getStringCat2(anim_token, suffix);
5322 char *value = getHashEntry(setup_file_hash, token);
5324 checked_free(token);
5327 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5331 freeSetupFileHash(setup_file_hash);
5335 if (filename_anim_initial == NULL)
5337 /* read settings for busy animation from static default artwork config */
5338 for (i = 0; image_config[i].token != NULL; i++)
5340 if (strEqual(image_config[i].token, anim_token))
5341 filename_anim_initial = getStringCopy(image_config[i].value);
5342 else if (strlen(image_config[i].token) > len_anim_token &&
5343 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5345 for (j = 0; image_config_suffix[j].token != NULL; j++)
5347 if (strEqual(&image_config[i].token[len_anim_token],
5348 image_config_suffix[j].token))
5350 get_graphic_parameter_value(image_config[i].value,
5351 image_config_suffix[j].token,
5352 image_config_suffix[j].type);
5358 if (filename_anim_initial == NULL) /* should not happen */
5359 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5361 anim_initial.bitmaps =
5362 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5364 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5365 LoadCustomImage(filename_anim_initial);
5367 checked_free(filename_anim_initial);
5369 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5371 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5373 graphic_info = graphic_info_last;
5375 init.busy.width = anim_initial.width;
5376 init.busy.height = anim_initial.height;
5378 InitMenuDesignSettings_Static();
5380 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5381 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5382 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5384 gfx.fade_border_source_status = global.border_status;
5385 gfx.fade_border_target_status = global.border_status;
5386 gfx.masked_border_bitmap_ptr = backbuffer;
5388 /* use copy of busy animation to prevent change while reloading artwork */
5392 void InitGfxBackground()
5394 fieldbuffer = bitmap_db_field;
5395 SetDrawtoField(DRAW_TO_BACKBUFFER);
5397 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5399 redraw_mask = REDRAW_ALL;
5402 static void InitLevelInfo()
5404 LoadLevelInfo(); /* global level info */
5405 LoadLevelSetup_LastSeries(); /* last played series info */
5406 LoadLevelSetup_SeriesInfo(); /* last played level info */
5408 if (global.autoplay_leveldir &&
5409 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5411 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5412 global.autoplay_leveldir);
5413 if (leveldir_current == NULL)
5414 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5418 static void InitLevelArtworkInfo()
5420 LoadLevelArtworkInfo();
5423 static void InitImages()
5425 print_timestamp_init("InitImages");
5428 printf("::: leveldir_current->identifier == '%s'\n",
5429 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5430 printf("::: leveldir_current->graphics_path == '%s'\n",
5431 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5432 printf("::: leveldir_current->graphics_set == '%s'\n",
5433 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5434 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5435 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5438 setLevelArtworkDir(artwork.gfx_first);
5441 printf("::: leveldir_current->identifier == '%s'\n",
5442 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5443 printf("::: leveldir_current->graphics_path == '%s'\n",
5444 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5445 printf("::: leveldir_current->graphics_set == '%s'\n",
5446 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5447 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5448 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5452 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5453 leveldir_current->identifier,
5454 artwork.gfx_current_identifier,
5455 artwork.gfx_current->identifier,
5456 leveldir_current->graphics_set,
5457 leveldir_current->graphics_path);
5460 UPDATE_BUSY_STATE();
5462 ReloadCustomImages();
5463 print_timestamp_time("ReloadCustomImages");
5465 UPDATE_BUSY_STATE();
5467 LoadCustomElementDescriptions();
5468 print_timestamp_time("LoadCustomElementDescriptions");
5470 UPDATE_BUSY_STATE();
5472 LoadMenuDesignSettings();
5473 print_timestamp_time("LoadMenuDesignSettings");
5475 UPDATE_BUSY_STATE();
5477 ReinitializeGraphics();
5478 print_timestamp_time("ReinitializeGraphics");
5480 LoadMenuDesignSettings_AfterGraphics();
5481 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5483 UPDATE_BUSY_STATE();
5485 print_timestamp_done("InitImages");
5488 static void InitSound(char *identifier)
5490 print_timestamp_init("InitSound");
5492 if (identifier == NULL)
5493 identifier = artwork.snd_current->identifier;
5495 /* set artwork path to send it to the sound server process */
5496 setLevelArtworkDir(artwork.snd_first);
5498 InitReloadCustomSounds(identifier);
5499 print_timestamp_time("InitReloadCustomSounds");
5501 ReinitializeSounds();
5502 print_timestamp_time("ReinitializeSounds");
5504 print_timestamp_done("InitSound");
5507 static void InitMusic(char *identifier)
5509 print_timestamp_init("InitMusic");
5511 if (identifier == NULL)
5512 identifier = artwork.mus_current->identifier;
5514 /* set artwork path to send it to the sound server process */
5515 setLevelArtworkDir(artwork.mus_first);
5517 InitReloadCustomMusic(identifier);
5518 print_timestamp_time("InitReloadCustomMusic");
5520 ReinitializeMusic();
5521 print_timestamp_time("ReinitializeMusic");
5523 print_timestamp_done("InitMusic");
5526 static void InitArtworkDone()
5528 if (program.headless)
5531 InitGlobalAnimations();
5534 void InitNetworkServer()
5536 #if defined(NETWORK_AVALIABLE)
5540 if (!options.network)
5543 #if defined(NETWORK_AVALIABLE)
5544 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5546 if (!ConnectToServer(options.server_host, options.server_port))
5547 Error(ERR_EXIT, "cannot connect to network game server");
5549 SendToServer_PlayerName(setup.player_name);
5550 SendToServer_ProtocolVersion();
5553 SendToServer_NrWanted(nr_wanted);
5557 static boolean CheckArtworkConfigForCustomElements(char *filename)
5559 SetupFileHash *setup_file_hash;
5560 boolean redefined_ce_found = FALSE;
5562 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5564 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5566 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5568 char *token = HASH_ITERATION_TOKEN(itr);
5570 if (strPrefix(token, "custom_"))
5572 redefined_ce_found = TRUE;
5577 END_HASH_ITERATION(setup_file_hash, itr)
5579 freeSetupFileHash(setup_file_hash);
5582 return redefined_ce_found;
5585 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5587 char *filename_base, *filename_local;
5588 boolean redefined_ce_found = FALSE;
5590 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5593 printf("::: leveldir_current->identifier == '%s'\n",
5594 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5595 printf("::: leveldir_current->graphics_path == '%s'\n",
5596 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5597 printf("::: leveldir_current->graphics_set == '%s'\n",
5598 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5599 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5600 leveldir_current == NULL ? "[NULL]" :
5601 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5604 /* first look for special artwork configured in level series config */
5605 filename_base = getCustomArtworkLevelConfigFilename(type);
5608 printf("::: filename_base == '%s'\n", filename_base);
5611 if (fileExists(filename_base))
5612 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5614 filename_local = getCustomArtworkConfigFilename(type);
5617 printf("::: filename_local == '%s'\n", filename_local);
5620 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5621 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5624 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5627 return redefined_ce_found;
5630 static void InitOverrideArtwork()
5632 boolean redefined_ce_found = FALSE;
5634 /* to check if this level set redefines any CEs, do not use overriding */
5635 gfx.override_level_graphics = FALSE;
5636 gfx.override_level_sounds = FALSE;
5637 gfx.override_level_music = FALSE;
5639 /* now check if this level set has definitions for custom elements */
5640 if (setup.override_level_graphics == AUTO ||
5641 setup.override_level_sounds == AUTO ||
5642 setup.override_level_music == AUTO)
5643 redefined_ce_found =
5644 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5645 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5646 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5649 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5652 if (redefined_ce_found)
5654 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5655 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5656 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5657 gfx.override_level_music = (setup.override_level_music == TRUE);
5661 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5662 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5663 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5664 gfx.override_level_music = (setup.override_level_music != FALSE);
5668 printf("::: => %d, %d, %d\n",
5669 gfx.override_level_graphics,
5670 gfx.override_level_sounds,
5671 gfx.override_level_music);
5675 static char *getNewArtworkIdentifier(int type)
5677 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5678 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5679 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5680 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5681 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5682 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5683 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5684 char *leveldir_identifier = leveldir_current->identifier;
5685 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5686 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5687 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5688 char *artwork_current_identifier;
5689 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5691 /* leveldir_current may be invalid (level group, parent link) */
5692 if (!validLevelSeries(leveldir_current))
5695 /* 1st step: determine artwork set to be activated in descending order:
5696 --------------------------------------------------------------------
5697 1. setup artwork (when configured to override everything else)
5698 2. artwork set configured in "levelinfo.conf" of current level set
5699 (artwork in level directory will have priority when loading later)
5700 3. artwork in level directory (stored in artwork sub-directory)
5701 4. setup artwork (currently configured in setup menu) */
5703 if (setup_override_artwork)
5704 artwork_current_identifier = setup_artwork_set;
5705 else if (leveldir_artwork_set != NULL)
5706 artwork_current_identifier = leveldir_artwork_set;
5707 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5708 artwork_current_identifier = leveldir_identifier;
5710 artwork_current_identifier = setup_artwork_set;
5713 /* 2nd step: check if it is really needed to reload artwork set
5714 ------------------------------------------------------------ */
5716 /* ---------- reload if level set and also artwork set has changed ------- */
5717 if (leveldir_current_identifier[type] != leveldir_identifier &&
5718 (last_has_level_artwork_set[type] || has_level_artwork_set))
5719 artwork_new_identifier = artwork_current_identifier;
5721 leveldir_current_identifier[type] = leveldir_identifier;
5722 last_has_level_artwork_set[type] = has_level_artwork_set;
5724 /* ---------- reload if "override artwork" setting has changed ----------- */
5725 if (last_override_level_artwork[type] != setup_override_artwork)
5726 artwork_new_identifier = artwork_current_identifier;
5728 last_override_level_artwork[type] = setup_override_artwork;
5730 /* ---------- reload if current artwork identifier has changed ----------- */
5731 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5732 artwork_current_identifier))
5733 artwork_new_identifier = artwork_current_identifier;
5735 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5737 /* ---------- do not reload directly after starting ---------------------- */
5738 if (!initialized[type])
5739 artwork_new_identifier = NULL;
5741 initialized[type] = TRUE;
5743 return artwork_new_identifier;
5746 void ReloadCustomArtwork(int force_reload)
5748 int last_game_status = game_status; /* save current game status */
5749 char *gfx_new_identifier;
5750 char *snd_new_identifier;
5751 char *mus_new_identifier;
5752 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5753 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5754 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5755 boolean reload_needed;
5757 InitOverrideArtwork();
5759 force_reload_gfx |= AdjustGraphicsForEMC();
5761 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5762 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5763 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5765 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5766 snd_new_identifier != NULL || force_reload_snd ||
5767 mus_new_identifier != NULL || force_reload_mus);
5772 print_timestamp_init("ReloadCustomArtwork");
5774 SetGameStatus(GAME_MODE_LOADING);
5776 FadeOut(REDRAW_ALL);
5778 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5779 print_timestamp_time("ClearRectangle");
5783 if (gfx_new_identifier != NULL || force_reload_gfx)
5786 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5787 artwork.gfx_current_identifier,
5789 artwork.gfx_current->identifier,
5790 leveldir_current->graphics_set);
5794 print_timestamp_time("InitImages");
5797 if (snd_new_identifier != NULL || force_reload_snd)
5799 InitSound(snd_new_identifier);
5800 print_timestamp_time("InitSound");
5803 if (mus_new_identifier != NULL || force_reload_mus)
5805 InitMusic(mus_new_identifier);
5806 print_timestamp_time("InitMusic");
5811 SetGameStatus(last_game_status); /* restore current game status */
5813 init_last = init; /* switch to new busy animation */
5815 FadeOut(REDRAW_ALL);
5817 RedrawGlobalBorder();
5819 /* force redraw of (open or closed) door graphics */
5820 SetDoorState(DOOR_OPEN_ALL);
5821 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5823 FadeSetEnterScreen();
5824 FadeSkipNextFadeOut();
5826 print_timestamp_done("ReloadCustomArtwork");
5828 LimitScreenUpdates(FALSE);
5831 void KeyboardAutoRepeatOffUnlessAutoplay()
5833 if (global.autoplay_leveldir == NULL)
5834 KeyboardAutoRepeatOff();
5837 void DisplayExitMessage(char *format, va_list ap)
5839 // check if draw buffer and fonts for exit message are already available
5840 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5843 int font_1 = FC_RED;
5844 int font_2 = FC_YELLOW;
5845 int font_3 = FC_BLUE;
5846 int font_width = getFontWidth(font_2);
5847 int font_height = getFontHeight(font_2);
5850 int sxsize = WIN_XSIZE - 2 * sx;
5851 int sysize = WIN_YSIZE - 2 * sy;
5852 int line_length = sxsize / font_width;
5853 int max_lines = sysize / font_height;
5854 int num_lines_printed;
5858 gfx.sxsize = sxsize;
5859 gfx.sysize = sysize;
5863 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5865 DrawTextSCentered(sy, font_1, "Fatal error:");
5866 sy += 3 * font_height;;
5869 DrawTextBufferVA(sx, sy, format, ap, font_2,
5870 line_length, line_length, max_lines,
5871 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5872 sy += (num_lines_printed + 3) * font_height;
5874 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5875 sy += 3 * font_height;
5878 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5879 line_length, line_length, max_lines,
5880 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5882 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5884 redraw_mask = REDRAW_ALL;
5886 /* force drawing exit message even if screen updates are currently limited */
5887 LimitScreenUpdates(FALSE);
5891 /* deactivate toons on error message screen */
5892 setup.toons = FALSE;
5894 WaitForEventToContinue();
5898 /* ========================================================================= */
5900 /* ========================================================================= */
5904 print_timestamp_init("OpenAll");
5906 SetGameStatus(GAME_MODE_LOADING);
5910 InitGlobal(); /* initialize some global variables */
5912 print_timestamp_time("[init global stuff]");
5916 print_timestamp_time("[init setup/config stuff (1)]");
5920 if (options.execute_command)
5921 Execute_Command(options.execute_command);
5923 if (options.serveronly)
5925 #if defined(PLATFORM_UNIX)
5926 NetworkServer(options.server_port, options.serveronly);
5928 Error(ERR_WARN, "networking only supported in Unix version");
5931 exit(0); /* never reached, server loops forever */
5935 print_timestamp_time("[init setup/config stuff (2)]");
5937 print_timestamp_time("[init setup/config stuff (3)]");
5938 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5939 print_timestamp_time("[init setup/config stuff (4)]");
5940 InitArtworkConfig(); /* needed before forking sound child process */
5941 print_timestamp_time("[init setup/config stuff (5)]");
5943 print_timestamp_time("[init setup/config stuff (6)]");
5945 InitRND(NEW_RANDOMIZE);
5946 InitSimpleRandom(NEW_RANDOMIZE);
5950 print_timestamp_time("[init setup/config stuff]");
5953 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5957 print_timestamp_time("[init video stuff]");
5959 InitElementPropertiesStatic();
5960 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5961 InitElementPropertiesGfxElement();
5963 print_timestamp_time("[init element properties stuff]");
5967 print_timestamp_time("InitGfx");
5970 print_timestamp_time("InitLevelInfo");
5972 InitLevelArtworkInfo();
5973 print_timestamp_time("InitLevelArtworkInfo");
5975 InitOverrideArtwork(); /* needs to know current level directory */
5976 print_timestamp_time("InitOverrideArtwork");
5978 InitImages(); /* needs to know current level directory */
5979 print_timestamp_time("InitImages");
5981 InitSound(NULL); /* needs to know current level directory */
5982 print_timestamp_time("InitSound");
5984 InitMusic(NULL); /* needs to know current level directory */
5985 print_timestamp_time("InitMusic");
5989 InitGfxBackground();
5994 if (global.autoplay_leveldir)
5999 else if (global.convert_leveldir)
6004 else if (global.create_images_dir)
6006 CreateLevelSketchImages();
6010 SetGameStatus(GAME_MODE_MAIN);
6012 FadeSetEnterScreen();
6013 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6014 FadeSkipNextFadeOut();
6016 print_timestamp_time("[post-artwork]");
6018 print_timestamp_done("OpenAll");
6022 InitNetworkServer();
6025 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6027 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6028 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6029 #if defined(PLATFORM_ANDROID)
6030 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6031 SDL_AndroidGetInternalStoragePath());
6032 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6033 SDL_AndroidGetExternalStoragePath());
6034 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6035 (SDL_AndroidGetExternalStorageState() ==
6036 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
6037 SDL_AndroidGetExternalStorageState() ==
6038 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
6043 void CloseAllAndExit(int exit_value)
6048 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6055 #if defined(TARGET_SDL)
6056 #if defined(TARGET_SDL2)
6058 // set a flag to tell the network server thread to quit and wait for it
6059 // using SDL_WaitThread()
6061 if (network_server) /* terminate network server */
6062 SDL_KillThread(server_thread);
6066 CloseVideoDisplay();
6067 ClosePlatformDependentStuff();
6069 if (exit_value != 0)
6071 /* fall back to default level set (current set may have caused an error) */
6072 SaveLevelSetup_LastSeries_Deactivate();
6074 /* tell user where to find error log file which may contain more details */
6075 // (error notification now directly displayed on screen inside R'n'D
6076 // NotifyUserAboutErrorFile(); /* currently only works for Windows */