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 (src_x < 0 || src_y < 0 ||
1714 src_x + width > src_bitmap_width ||
1715 src_y + height > src_bitmap_height)
1717 Error(ERR_INFO_LINE, "-");
1718 Error(ERR_INFO, "warning: error found in config file:");
1719 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1720 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1721 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1722 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1724 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1725 src_x, src_y, src_bitmap_width, src_bitmap_height);
1726 Error(ERR_INFO, "custom graphic rejected for this element/action");
1728 if (i == fallback_graphic)
1729 Error(ERR_EXIT, "no fallback graphic available");
1731 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1732 Error(ERR_INFO_LINE, "-");
1734 graphic_info[i] = graphic_info[fallback_graphic];
1737 /* check if last animation frame is inside specified bitmap */
1739 last_frame = graphic_info[i].anim_frames - 1;
1740 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1742 if (src_x < 0 || src_y < 0 ||
1743 src_x + width > src_bitmap_width ||
1744 src_y + height > src_bitmap_height)
1746 Error(ERR_INFO_LINE, "-");
1747 Error(ERR_INFO, "warning: error found in config file:");
1748 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1749 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1750 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1751 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1753 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1754 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1755 Error(ERR_INFO, "custom graphic rejected for this element/action");
1757 if (i == fallback_graphic)
1758 Error(ERR_EXIT, "no fallback graphic available");
1760 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1761 Error(ERR_INFO_LINE, "-");
1763 graphic_info[i] = graphic_info[fallback_graphic];
1768 static void InitGraphicCompatibilityInfo()
1770 struct FileInfo *fi_global_door =
1771 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1772 int num_images = getImageListSize();
1775 /* the following compatibility handling is needed for the following case:
1776 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1777 graphics mainly used for door and panel graphics, like editor, tape and
1778 in-game buttons with hard-coded bitmap positions and button sizes; as
1779 these graphics now have individual definitions, redefining "global.door"
1780 to change all these graphics at once like before does not work anymore
1781 (because all those individual definitions still have their default values);
1782 to solve this, remap all those individual definitions that are not
1783 redefined to the new bitmap of "global.door" if it was redefined */
1785 /* special compatibility handling if image "global.door" was redefined */
1786 if (fi_global_door->redefined)
1788 for (i = 0; i < num_images; i++)
1790 struct FileInfo *fi = getImageListEntryFromImageID(i);
1792 /* process only those images that still use the default settings */
1795 /* process all images which default to same image as "global.door" */
1796 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1798 // printf("::: special treatment needed for token '%s'\n", fi->token);
1800 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1801 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1807 InitGraphicCompatibilityInfo_Doors();
1810 static void InitElementSoundInfo()
1812 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1813 int num_property_mappings = getSoundListPropertyMappingSize();
1816 /* set values to -1 to identify later as "uninitialized" values */
1817 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1818 for (act = 0; act < NUM_ACTIONS; act++)
1819 element_info[i].sound[act] = -1;
1821 /* initialize element/sound mapping from static configuration */
1822 for (i = 0; element_to_sound[i].element > -1; i++)
1824 int element = element_to_sound[i].element;
1825 int action = element_to_sound[i].action;
1826 int sound = element_to_sound[i].sound;
1827 boolean is_class = element_to_sound[i].is_class;
1830 action = ACTION_DEFAULT;
1833 element_info[element].sound[action] = sound;
1835 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1836 if (strEqual(element_info[j].class_name,
1837 element_info[element].class_name))
1838 element_info[j].sound[action] = sound;
1841 /* initialize element class/sound mapping from dynamic configuration */
1842 for (i = 0; i < num_property_mappings; i++)
1844 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1845 int action = property_mapping[i].ext1_index;
1846 int sound = property_mapping[i].artwork_index;
1848 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1852 action = ACTION_DEFAULT;
1854 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1855 if (strEqual(element_info[j].class_name,
1856 element_info[element_class].class_name))
1857 element_info[j].sound[action] = sound;
1860 /* initialize element/sound mapping from dynamic configuration */
1861 for (i = 0; i < num_property_mappings; i++)
1863 int element = property_mapping[i].base_index;
1864 int action = property_mapping[i].ext1_index;
1865 int sound = property_mapping[i].artwork_index;
1867 if (element >= MAX_NUM_ELEMENTS)
1871 action = ACTION_DEFAULT;
1873 element_info[element].sound[action] = sound;
1876 /* now set all '-1' values to element specific default values */
1877 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1879 for (act = 0; act < NUM_ACTIONS; act++)
1881 /* generic default action sound (defined by "[default]" directive) */
1882 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1884 /* look for special default action sound (classic game specific) */
1885 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1886 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1887 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1888 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1889 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1890 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1892 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1893 /* !!! make this better !!! */
1894 if (i == EL_EMPTY_SPACE)
1895 default_action_sound = element_info[EL_DEFAULT].sound[act];
1897 /* no sound for this specific action -- use default action sound */
1898 if (element_info[i].sound[act] == -1)
1899 element_info[i].sound[act] = default_action_sound;
1903 /* copy sound settings to some elements that are only stored in level file
1904 in native R'n'D levels, but are used by game engine in native EM levels */
1905 for (i = 0; copy_properties[i][0] != -1; i++)
1906 for (j = 1; j <= 4; j++)
1907 for (act = 0; act < NUM_ACTIONS; act++)
1908 element_info[copy_properties[i][j]].sound[act] =
1909 element_info[copy_properties[i][0]].sound[act];
1912 static void InitGameModeSoundInfo()
1916 /* set values to -1 to identify later as "uninitialized" values */
1917 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1920 /* initialize gamemode/sound mapping from static configuration */
1921 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1923 int gamemode = gamemode_to_sound[i].gamemode;
1924 int sound = gamemode_to_sound[i].sound;
1927 gamemode = GAME_MODE_DEFAULT;
1929 menu.sound[gamemode] = sound;
1932 /* now set all '-1' values to levelset specific default values */
1933 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1934 if (menu.sound[i] == -1)
1935 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1938 static void set_sound_parameters(int sound, char **parameter_raw)
1940 int parameter[NUM_SND_ARGS];
1943 /* get integer values from string parameters */
1944 for (i = 0; i < NUM_SND_ARGS; i++)
1946 get_parameter_value(parameter_raw[i],
1947 sound_config_suffix[i].token,
1948 sound_config_suffix[i].type);
1950 /* explicit loop mode setting in configuration overrides default value */
1951 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1952 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1954 /* sound volume to change the original volume when loading the sound file */
1955 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1957 /* sound priority to give certain sounds a higher or lower priority */
1958 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1961 static void InitSoundInfo()
1963 int *sound_effect_properties;
1964 int num_sounds = getSoundListSize();
1967 checked_free(sound_info);
1969 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1970 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1972 /* initialize sound effect for all elements to "no sound" */
1973 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1974 for (j = 0; j < NUM_ACTIONS; j++)
1975 element_info[i].sound[j] = SND_UNDEFINED;
1977 for (i = 0; i < num_sounds; i++)
1979 struct FileInfo *sound = getSoundListEntry(i);
1980 int len_effect_text = strlen(sound->token);
1982 sound_effect_properties[i] = ACTION_OTHER;
1983 sound_info[i].loop = FALSE; /* default: play sound only once */
1985 /* determine all loop sounds and identify certain sound classes */
1987 for (j = 0; element_action_info[j].suffix; j++)
1989 int len_action_text = strlen(element_action_info[j].suffix);
1991 if (len_action_text < len_effect_text &&
1992 strEqual(&sound->token[len_effect_text - len_action_text],
1993 element_action_info[j].suffix))
1995 sound_effect_properties[i] = element_action_info[j].value;
1996 sound_info[i].loop = element_action_info[j].is_loop_sound;
2002 /* associate elements and some selected sound actions */
2004 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2006 if (element_info[j].class_name)
2008 int len_class_text = strlen(element_info[j].class_name);
2010 if (len_class_text + 1 < len_effect_text &&
2011 strncmp(sound->token,
2012 element_info[j].class_name, len_class_text) == 0 &&
2013 sound->token[len_class_text] == '.')
2015 int sound_action_value = sound_effect_properties[i];
2017 element_info[j].sound[sound_action_value] = i;
2022 set_sound_parameters(i, sound->parameter);
2025 free(sound_effect_properties);
2028 static void InitGameModeMusicInfo()
2030 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2031 int num_property_mappings = getMusicListPropertyMappingSize();
2032 int default_levelset_music = -1;
2035 /* set values to -1 to identify later as "uninitialized" values */
2036 for (i = 0; i < MAX_LEVELS; i++)
2037 levelset.music[i] = -1;
2038 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2041 /* initialize gamemode/music mapping from static configuration */
2042 for (i = 0; gamemode_to_music[i].music > -1; i++)
2044 int gamemode = gamemode_to_music[i].gamemode;
2045 int music = gamemode_to_music[i].music;
2048 gamemode = GAME_MODE_DEFAULT;
2050 menu.music[gamemode] = music;
2053 /* initialize gamemode/music mapping from dynamic configuration */
2054 for (i = 0; i < num_property_mappings; i++)
2056 int prefix = property_mapping[i].base_index;
2057 int gamemode = property_mapping[i].ext2_index;
2058 int level = property_mapping[i].ext3_index;
2059 int music = property_mapping[i].artwork_index;
2061 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2065 gamemode = GAME_MODE_DEFAULT;
2067 /* level specific music only allowed for in-game music */
2068 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2069 gamemode = GAME_MODE_PLAYING;
2074 default_levelset_music = music;
2077 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2078 levelset.music[level] = music;
2079 if (gamemode != GAME_MODE_PLAYING)
2080 menu.music[gamemode] = music;
2083 /* now set all '-1' values to menu specific default values */
2084 /* (undefined values of "levelset.music[]" might stay at "-1" to
2085 allow dynamic selection of music files from music directory!) */
2086 for (i = 0; i < MAX_LEVELS; i++)
2087 if (levelset.music[i] == -1)
2088 levelset.music[i] = default_levelset_music;
2089 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2090 if (menu.music[i] == -1)
2091 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2094 static void set_music_parameters(int music, char **parameter_raw)
2096 int parameter[NUM_MUS_ARGS];
2099 /* get integer values from string parameters */
2100 for (i = 0; i < NUM_MUS_ARGS; i++)
2102 get_parameter_value(parameter_raw[i],
2103 music_config_suffix[i].token,
2104 music_config_suffix[i].type);
2106 /* explicit loop mode setting in configuration overrides default value */
2107 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2108 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2111 static void InitMusicInfo()
2113 int num_music = getMusicListSize();
2116 checked_free(music_info);
2118 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2120 for (i = 0; i < num_music; i++)
2122 struct FileInfo *music = getMusicListEntry(i);
2123 int len_music_text = strlen(music->token);
2125 music_info[i].loop = TRUE; /* default: play music in loop mode */
2127 /* determine all loop music */
2129 for (j = 0; music_prefix_info[j].prefix; j++)
2131 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2133 if (len_prefix_text < len_music_text &&
2134 strncmp(music->token,
2135 music_prefix_info[j].prefix, len_prefix_text) == 0)
2137 music_info[i].loop = music_prefix_info[j].is_loop_music;
2143 set_music_parameters(i, music->parameter);
2147 static void ReinitializeGraphics()
2149 print_timestamp_init("ReinitializeGraphics");
2151 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2153 InitGraphicInfo(); /* graphic properties mapping */
2154 print_timestamp_time("InitGraphicInfo");
2155 InitElementGraphicInfo(); /* element game graphic mapping */
2156 print_timestamp_time("InitElementGraphicInfo");
2157 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2158 print_timestamp_time("InitElementSpecialGraphicInfo");
2160 InitElementSmallImages(); /* scale elements to all needed sizes */
2161 print_timestamp_time("InitElementSmallImages");
2162 InitScaledImages(); /* scale all other images, if needed */
2163 print_timestamp_time("InitScaledImages");
2164 InitBitmapPointers(); /* set standard size bitmap pointers */
2165 print_timestamp_time("InitBitmapPointers");
2166 InitFontGraphicInfo(); /* initialize text drawing functions */
2167 print_timestamp_time("InitFontGraphicInfo");
2168 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2169 print_timestamp_time("InitGlobalAnimGraphicInfo");
2171 InitImageTextures(); /* create textures for certain images */
2172 print_timestamp_time("InitImageTextures");
2174 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2175 print_timestamp_time("InitGraphicInfo_EM");
2177 InitGraphicCompatibilityInfo();
2178 print_timestamp_time("InitGraphicCompatibilityInfo");
2180 SetMainBackgroundImage(IMG_BACKGROUND);
2181 print_timestamp_time("SetMainBackgroundImage");
2182 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2183 print_timestamp_time("SetDoorBackgroundImage");
2186 print_timestamp_time("InitGadgets");
2188 print_timestamp_time("InitDoors");
2190 print_timestamp_done("ReinitializeGraphics");
2193 static void ReinitializeSounds()
2195 InitSoundInfo(); /* sound properties mapping */
2196 InitElementSoundInfo(); /* element game sound mapping */
2197 InitGameModeSoundInfo(); /* game mode sound mapping */
2198 InitGlobalAnimSoundInfo(); /* global animation sound settings */
2200 InitPlayLevelSound(); /* internal game sound settings */
2203 static void ReinitializeMusic()
2205 InitMusicInfo(); /* music properties mapping */
2206 InitGameModeMusicInfo(); /* game mode music mapping */
2207 InitGlobalAnimMusicInfo(); /* global animation music settings */
2210 static int get_special_property_bit(int element, int property_bit_nr)
2212 struct PropertyBitInfo
2218 static struct PropertyBitInfo pb_can_move_into_acid[] =
2220 /* the player may be able fall into acid when gravity is activated */
2225 { EL_SP_MURPHY, 0 },
2226 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2228 /* all elements that can move may be able to also move into acid */
2231 { EL_BUG_RIGHT, 1 },
2234 { EL_SPACESHIP, 2 },
2235 { EL_SPACESHIP_LEFT, 2 },
2236 { EL_SPACESHIP_RIGHT, 2 },
2237 { EL_SPACESHIP_UP, 2 },
2238 { EL_SPACESHIP_DOWN, 2 },
2239 { EL_BD_BUTTERFLY, 3 },
2240 { EL_BD_BUTTERFLY_LEFT, 3 },
2241 { EL_BD_BUTTERFLY_RIGHT, 3 },
2242 { EL_BD_BUTTERFLY_UP, 3 },
2243 { EL_BD_BUTTERFLY_DOWN, 3 },
2244 { EL_BD_FIREFLY, 4 },
2245 { EL_BD_FIREFLY_LEFT, 4 },
2246 { EL_BD_FIREFLY_RIGHT, 4 },
2247 { EL_BD_FIREFLY_UP, 4 },
2248 { EL_BD_FIREFLY_DOWN, 4 },
2250 { EL_YAMYAM_LEFT, 5 },
2251 { EL_YAMYAM_RIGHT, 5 },
2252 { EL_YAMYAM_UP, 5 },
2253 { EL_YAMYAM_DOWN, 5 },
2254 { EL_DARK_YAMYAM, 6 },
2257 { EL_PACMAN_LEFT, 8 },
2258 { EL_PACMAN_RIGHT, 8 },
2259 { EL_PACMAN_UP, 8 },
2260 { EL_PACMAN_DOWN, 8 },
2262 { EL_MOLE_LEFT, 9 },
2263 { EL_MOLE_RIGHT, 9 },
2265 { EL_MOLE_DOWN, 9 },
2269 { EL_SATELLITE, 13 },
2270 { EL_SP_SNIKSNAK, 14 },
2271 { EL_SP_ELECTRON, 15 },
2274 { EL_EMC_ANDROID, 18 },
2279 static struct PropertyBitInfo pb_dont_collide_with[] =
2281 { EL_SP_SNIKSNAK, 0 },
2282 { EL_SP_ELECTRON, 1 },
2290 struct PropertyBitInfo *pb_info;
2293 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2294 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2299 struct PropertyBitInfo *pb_info = NULL;
2302 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2303 if (pb_definition[i].bit_nr == property_bit_nr)
2304 pb_info = pb_definition[i].pb_info;
2306 if (pb_info == NULL)
2309 for (i = 0; pb_info[i].element != -1; i++)
2310 if (pb_info[i].element == element)
2311 return pb_info[i].bit_nr;
2316 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2317 boolean property_value)
2319 int bit_nr = get_special_property_bit(element, property_bit_nr);
2324 *bitfield |= (1 << bit_nr);
2326 *bitfield &= ~(1 << bit_nr);
2330 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2332 int bit_nr = get_special_property_bit(element, property_bit_nr);
2335 return ((*bitfield & (1 << bit_nr)) != 0);
2340 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2342 static int group_nr;
2343 static struct ElementGroupInfo *group;
2344 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2347 if (actual_group == NULL) /* not yet initialized */
2350 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2352 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2353 group_element - EL_GROUP_START + 1);
2355 /* replace element which caused too deep recursion by question mark */
2356 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2361 if (recursion_depth == 0) /* initialization */
2363 group = actual_group;
2364 group_nr = GROUP_NR(group_element);
2366 group->num_elements_resolved = 0;
2367 group->choice_pos = 0;
2369 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2370 element_info[i].in_group[group_nr] = FALSE;
2373 for (i = 0; i < actual_group->num_elements; i++)
2375 int element = actual_group->element[i];
2377 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2380 if (IS_GROUP_ELEMENT(element))
2381 ResolveGroupElementExt(element, recursion_depth + 1);
2384 group->element_resolved[group->num_elements_resolved++] = element;
2385 element_info[element].in_group[group_nr] = TRUE;
2390 void ResolveGroupElement(int group_element)
2392 ResolveGroupElementExt(group_element, 0);
2395 void InitElementPropertiesStatic()
2397 static boolean clipboard_elements_initialized = FALSE;
2399 static int ep_diggable[] =
2404 EL_SP_BUGGY_BASE_ACTIVATING,
2407 EL_INVISIBLE_SAND_ACTIVE,
2410 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2411 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2416 EL_SP_BUGGY_BASE_ACTIVE,
2423 static int ep_collectible_only[] =
2445 EL_DYNABOMB_INCREASE_NUMBER,
2446 EL_DYNABOMB_INCREASE_SIZE,
2447 EL_DYNABOMB_INCREASE_POWER,
2465 /* !!! handle separately !!! */
2466 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2472 static int ep_dont_run_into[] =
2474 /* same elements as in 'ep_dont_touch' */
2480 /* same elements as in 'ep_dont_collide_with' */
2492 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2497 EL_SP_BUGGY_BASE_ACTIVE,
2504 static int ep_dont_collide_with[] =
2506 /* same elements as in 'ep_dont_touch' */
2523 static int ep_dont_touch[] =
2533 static int ep_indestructible[] =
2537 EL_ACID_POOL_TOPLEFT,
2538 EL_ACID_POOL_TOPRIGHT,
2539 EL_ACID_POOL_BOTTOMLEFT,
2540 EL_ACID_POOL_BOTTOM,
2541 EL_ACID_POOL_BOTTOMRIGHT,
2542 EL_SP_HARDWARE_GRAY,
2543 EL_SP_HARDWARE_GREEN,
2544 EL_SP_HARDWARE_BLUE,
2546 EL_SP_HARDWARE_YELLOW,
2547 EL_SP_HARDWARE_BASE_1,
2548 EL_SP_HARDWARE_BASE_2,
2549 EL_SP_HARDWARE_BASE_3,
2550 EL_SP_HARDWARE_BASE_4,
2551 EL_SP_HARDWARE_BASE_5,
2552 EL_SP_HARDWARE_BASE_6,
2553 EL_INVISIBLE_STEELWALL,
2554 EL_INVISIBLE_STEELWALL_ACTIVE,
2555 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2556 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2557 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2558 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2559 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2560 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2561 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2562 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2563 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2564 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2565 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2566 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2568 EL_LIGHT_SWITCH_ACTIVE,
2569 EL_SIGN_EXCLAMATION,
2570 EL_SIGN_RADIOACTIVITY,
2577 EL_SIGN_ENTRY_FORBIDDEN,
2578 EL_SIGN_EMERGENCY_EXIT,
2586 EL_STEEL_EXIT_CLOSED,
2588 EL_STEEL_EXIT_OPENING,
2589 EL_STEEL_EXIT_CLOSING,
2590 EL_EM_STEEL_EXIT_CLOSED,
2591 EL_EM_STEEL_EXIT_OPEN,
2592 EL_EM_STEEL_EXIT_OPENING,
2593 EL_EM_STEEL_EXIT_CLOSING,
2594 EL_DC_STEELWALL_1_LEFT,
2595 EL_DC_STEELWALL_1_RIGHT,
2596 EL_DC_STEELWALL_1_TOP,
2597 EL_DC_STEELWALL_1_BOTTOM,
2598 EL_DC_STEELWALL_1_HORIZONTAL,
2599 EL_DC_STEELWALL_1_VERTICAL,
2600 EL_DC_STEELWALL_1_TOPLEFT,
2601 EL_DC_STEELWALL_1_TOPRIGHT,
2602 EL_DC_STEELWALL_1_BOTTOMLEFT,
2603 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2604 EL_DC_STEELWALL_1_TOPLEFT_2,
2605 EL_DC_STEELWALL_1_TOPRIGHT_2,
2606 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2607 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2608 EL_DC_STEELWALL_2_LEFT,
2609 EL_DC_STEELWALL_2_RIGHT,
2610 EL_DC_STEELWALL_2_TOP,
2611 EL_DC_STEELWALL_2_BOTTOM,
2612 EL_DC_STEELWALL_2_HORIZONTAL,
2613 EL_DC_STEELWALL_2_VERTICAL,
2614 EL_DC_STEELWALL_2_MIDDLE,
2615 EL_DC_STEELWALL_2_SINGLE,
2616 EL_STEELWALL_SLIPPERY,
2630 EL_GATE_1_GRAY_ACTIVE,
2631 EL_GATE_2_GRAY_ACTIVE,
2632 EL_GATE_3_GRAY_ACTIVE,
2633 EL_GATE_4_GRAY_ACTIVE,
2642 EL_EM_GATE_1_GRAY_ACTIVE,
2643 EL_EM_GATE_2_GRAY_ACTIVE,
2644 EL_EM_GATE_3_GRAY_ACTIVE,
2645 EL_EM_GATE_4_GRAY_ACTIVE,
2654 EL_EMC_GATE_5_GRAY_ACTIVE,
2655 EL_EMC_GATE_6_GRAY_ACTIVE,
2656 EL_EMC_GATE_7_GRAY_ACTIVE,
2657 EL_EMC_GATE_8_GRAY_ACTIVE,
2659 EL_DC_GATE_WHITE_GRAY,
2660 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2661 EL_DC_GATE_FAKE_GRAY,
2663 EL_SWITCHGATE_OPENING,
2664 EL_SWITCHGATE_CLOSED,
2665 EL_SWITCHGATE_CLOSING,
2666 EL_DC_SWITCHGATE_SWITCH_UP,
2667 EL_DC_SWITCHGATE_SWITCH_DOWN,
2669 EL_TIMEGATE_OPENING,
2671 EL_TIMEGATE_CLOSING,
2672 EL_DC_TIMEGATE_SWITCH,
2673 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2677 EL_TUBE_VERTICAL_LEFT,
2678 EL_TUBE_VERTICAL_RIGHT,
2679 EL_TUBE_HORIZONTAL_UP,
2680 EL_TUBE_HORIZONTAL_DOWN,
2685 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2686 EL_EXPANDABLE_STEELWALL_VERTICAL,
2687 EL_EXPANDABLE_STEELWALL_ANY,
2692 static int ep_slippery[] =
2706 EL_ROBOT_WHEEL_ACTIVE,
2712 EL_ACID_POOL_TOPLEFT,
2713 EL_ACID_POOL_TOPRIGHT,
2723 EL_STEELWALL_SLIPPERY,
2726 EL_EMC_WALL_SLIPPERY_1,
2727 EL_EMC_WALL_SLIPPERY_2,
2728 EL_EMC_WALL_SLIPPERY_3,
2729 EL_EMC_WALL_SLIPPERY_4,
2731 EL_EMC_MAGIC_BALL_ACTIVE,
2736 static int ep_can_change[] =
2741 static int ep_can_move[] =
2743 /* same elements as in 'pb_can_move_into_acid' */
2766 static int ep_can_fall[] =
2780 EL_QUICKSAND_FAST_FULL,
2782 EL_BD_MAGIC_WALL_FULL,
2783 EL_DC_MAGIC_WALL_FULL,
2797 static int ep_can_smash_player[] =
2823 static int ep_can_smash_enemies[] =
2832 static int ep_can_smash_everything[] =
2841 static int ep_explodes_by_fire[] =
2843 /* same elements as in 'ep_explodes_impact' */
2848 /* same elements as in 'ep_explodes_smashed' */
2858 EL_EM_DYNAMITE_ACTIVE,
2859 EL_DYNABOMB_PLAYER_1_ACTIVE,
2860 EL_DYNABOMB_PLAYER_2_ACTIVE,
2861 EL_DYNABOMB_PLAYER_3_ACTIVE,
2862 EL_DYNABOMB_PLAYER_4_ACTIVE,
2863 EL_DYNABOMB_INCREASE_NUMBER,
2864 EL_DYNABOMB_INCREASE_SIZE,
2865 EL_DYNABOMB_INCREASE_POWER,
2866 EL_SP_DISK_RED_ACTIVE,
2880 static int ep_explodes_smashed[] =
2882 /* same elements as in 'ep_explodes_impact' */
2896 static int ep_explodes_impact[] =
2905 static int ep_walkable_over[] =
2909 EL_SOKOBAN_FIELD_EMPTY,
2916 EL_EM_STEEL_EXIT_OPEN,
2917 EL_EM_STEEL_EXIT_OPENING,
2926 EL_GATE_1_GRAY_ACTIVE,
2927 EL_GATE_2_GRAY_ACTIVE,
2928 EL_GATE_3_GRAY_ACTIVE,
2929 EL_GATE_4_GRAY_ACTIVE,
2937 static int ep_walkable_inside[] =
2942 EL_TUBE_VERTICAL_LEFT,
2943 EL_TUBE_VERTICAL_RIGHT,
2944 EL_TUBE_HORIZONTAL_UP,
2945 EL_TUBE_HORIZONTAL_DOWN,
2954 static int ep_walkable_under[] =
2959 static int ep_passable_over[] =
2969 EL_EM_GATE_1_GRAY_ACTIVE,
2970 EL_EM_GATE_2_GRAY_ACTIVE,
2971 EL_EM_GATE_3_GRAY_ACTIVE,
2972 EL_EM_GATE_4_GRAY_ACTIVE,
2981 EL_EMC_GATE_5_GRAY_ACTIVE,
2982 EL_EMC_GATE_6_GRAY_ACTIVE,
2983 EL_EMC_GATE_7_GRAY_ACTIVE,
2984 EL_EMC_GATE_8_GRAY_ACTIVE,
2986 EL_DC_GATE_WHITE_GRAY,
2987 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2994 static int ep_passable_inside[] =
3000 EL_SP_PORT_HORIZONTAL,
3001 EL_SP_PORT_VERTICAL,
3003 EL_SP_GRAVITY_PORT_LEFT,
3004 EL_SP_GRAVITY_PORT_RIGHT,
3005 EL_SP_GRAVITY_PORT_UP,
3006 EL_SP_GRAVITY_PORT_DOWN,
3007 EL_SP_GRAVITY_ON_PORT_LEFT,
3008 EL_SP_GRAVITY_ON_PORT_RIGHT,
3009 EL_SP_GRAVITY_ON_PORT_UP,
3010 EL_SP_GRAVITY_ON_PORT_DOWN,
3011 EL_SP_GRAVITY_OFF_PORT_LEFT,
3012 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3013 EL_SP_GRAVITY_OFF_PORT_UP,
3014 EL_SP_GRAVITY_OFF_PORT_DOWN,
3019 static int ep_passable_under[] =
3024 static int ep_droppable[] =
3029 static int ep_explodes_1x1_old[] =
3034 static int ep_pushable[] =
3046 EL_SOKOBAN_FIELD_FULL,
3055 static int ep_explodes_cross_old[] =
3060 static int ep_protected[] =
3062 /* same elements as in 'ep_walkable_inside' */
3066 EL_TUBE_VERTICAL_LEFT,
3067 EL_TUBE_VERTICAL_RIGHT,
3068 EL_TUBE_HORIZONTAL_UP,
3069 EL_TUBE_HORIZONTAL_DOWN,
3075 /* same elements as in 'ep_passable_over' */
3084 EL_EM_GATE_1_GRAY_ACTIVE,
3085 EL_EM_GATE_2_GRAY_ACTIVE,
3086 EL_EM_GATE_3_GRAY_ACTIVE,
3087 EL_EM_GATE_4_GRAY_ACTIVE,
3096 EL_EMC_GATE_5_GRAY_ACTIVE,
3097 EL_EMC_GATE_6_GRAY_ACTIVE,
3098 EL_EMC_GATE_7_GRAY_ACTIVE,
3099 EL_EMC_GATE_8_GRAY_ACTIVE,
3101 EL_DC_GATE_WHITE_GRAY,
3102 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3106 /* same elements as in 'ep_passable_inside' */
3111 EL_SP_PORT_HORIZONTAL,
3112 EL_SP_PORT_VERTICAL,
3114 EL_SP_GRAVITY_PORT_LEFT,
3115 EL_SP_GRAVITY_PORT_RIGHT,
3116 EL_SP_GRAVITY_PORT_UP,
3117 EL_SP_GRAVITY_PORT_DOWN,
3118 EL_SP_GRAVITY_ON_PORT_LEFT,
3119 EL_SP_GRAVITY_ON_PORT_RIGHT,
3120 EL_SP_GRAVITY_ON_PORT_UP,
3121 EL_SP_GRAVITY_ON_PORT_DOWN,
3122 EL_SP_GRAVITY_OFF_PORT_LEFT,
3123 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3124 EL_SP_GRAVITY_OFF_PORT_UP,
3125 EL_SP_GRAVITY_OFF_PORT_DOWN,
3130 static int ep_throwable[] =
3135 static int ep_can_explode[] =
3137 /* same elements as in 'ep_explodes_impact' */
3142 /* same elements as in 'ep_explodes_smashed' */
3148 /* elements that can explode by explosion or by dragonfire */
3152 EL_EM_DYNAMITE_ACTIVE,
3153 EL_DYNABOMB_PLAYER_1_ACTIVE,
3154 EL_DYNABOMB_PLAYER_2_ACTIVE,
3155 EL_DYNABOMB_PLAYER_3_ACTIVE,
3156 EL_DYNABOMB_PLAYER_4_ACTIVE,
3157 EL_DYNABOMB_INCREASE_NUMBER,
3158 EL_DYNABOMB_INCREASE_SIZE,
3159 EL_DYNABOMB_INCREASE_POWER,
3160 EL_SP_DISK_RED_ACTIVE,
3168 /* elements that can explode only by explosion */
3174 static int ep_gravity_reachable[] =
3180 EL_INVISIBLE_SAND_ACTIVE,
3185 EL_SP_PORT_HORIZONTAL,
3186 EL_SP_PORT_VERTICAL,
3188 EL_SP_GRAVITY_PORT_LEFT,
3189 EL_SP_GRAVITY_PORT_RIGHT,
3190 EL_SP_GRAVITY_PORT_UP,
3191 EL_SP_GRAVITY_PORT_DOWN,
3192 EL_SP_GRAVITY_ON_PORT_LEFT,
3193 EL_SP_GRAVITY_ON_PORT_RIGHT,
3194 EL_SP_GRAVITY_ON_PORT_UP,
3195 EL_SP_GRAVITY_ON_PORT_DOWN,
3196 EL_SP_GRAVITY_OFF_PORT_LEFT,
3197 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3198 EL_SP_GRAVITY_OFF_PORT_UP,
3199 EL_SP_GRAVITY_OFF_PORT_DOWN,
3205 static int ep_player[] =
3212 EL_SOKOBAN_FIELD_PLAYER,
3218 static int ep_can_pass_magic_wall[] =
3232 static int ep_can_pass_dc_magic_wall[] =
3248 static int ep_switchable[] =
3252 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3253 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3254 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3255 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3256 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3257 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3258 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3259 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3260 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3261 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3262 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3263 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3264 EL_SWITCHGATE_SWITCH_UP,
3265 EL_SWITCHGATE_SWITCH_DOWN,
3266 EL_DC_SWITCHGATE_SWITCH_UP,
3267 EL_DC_SWITCHGATE_SWITCH_DOWN,
3269 EL_LIGHT_SWITCH_ACTIVE,
3271 EL_DC_TIMEGATE_SWITCH,
3272 EL_BALLOON_SWITCH_LEFT,
3273 EL_BALLOON_SWITCH_RIGHT,
3274 EL_BALLOON_SWITCH_UP,
3275 EL_BALLOON_SWITCH_DOWN,
3276 EL_BALLOON_SWITCH_ANY,
3277 EL_BALLOON_SWITCH_NONE,
3280 EL_EMC_MAGIC_BALL_SWITCH,
3281 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3286 static int ep_bd_element[] =
3320 static int ep_sp_element[] =
3322 /* should always be valid */
3325 /* standard classic Supaplex elements */
3332 EL_SP_HARDWARE_GRAY,
3340 EL_SP_GRAVITY_PORT_RIGHT,
3341 EL_SP_GRAVITY_PORT_DOWN,
3342 EL_SP_GRAVITY_PORT_LEFT,
3343 EL_SP_GRAVITY_PORT_UP,
3348 EL_SP_PORT_VERTICAL,
3349 EL_SP_PORT_HORIZONTAL,
3355 EL_SP_HARDWARE_BASE_1,
3356 EL_SP_HARDWARE_GREEN,
3357 EL_SP_HARDWARE_BLUE,
3359 EL_SP_HARDWARE_YELLOW,
3360 EL_SP_HARDWARE_BASE_2,
3361 EL_SP_HARDWARE_BASE_3,
3362 EL_SP_HARDWARE_BASE_4,
3363 EL_SP_HARDWARE_BASE_5,
3364 EL_SP_HARDWARE_BASE_6,
3368 /* additional elements that appeared in newer Supaplex levels */
3371 /* additional gravity port elements (not switching, but setting gravity) */
3372 EL_SP_GRAVITY_ON_PORT_LEFT,
3373 EL_SP_GRAVITY_ON_PORT_RIGHT,
3374 EL_SP_GRAVITY_ON_PORT_UP,
3375 EL_SP_GRAVITY_ON_PORT_DOWN,
3376 EL_SP_GRAVITY_OFF_PORT_LEFT,
3377 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3378 EL_SP_GRAVITY_OFF_PORT_UP,
3379 EL_SP_GRAVITY_OFF_PORT_DOWN,
3381 /* more than one Murphy in a level results in an inactive clone */
3384 /* runtime Supaplex elements */
3385 EL_SP_DISK_RED_ACTIVE,
3386 EL_SP_TERMINAL_ACTIVE,
3387 EL_SP_BUGGY_BASE_ACTIVATING,
3388 EL_SP_BUGGY_BASE_ACTIVE,
3395 static int ep_sb_element[] =
3400 EL_SOKOBAN_FIELD_EMPTY,
3401 EL_SOKOBAN_FIELD_FULL,
3402 EL_SOKOBAN_FIELD_PLAYER,
3407 EL_INVISIBLE_STEELWALL,
3412 static int ep_gem[] =
3424 static int ep_food_dark_yamyam[] =
3452 static int ep_food_penguin[] =
3466 static int ep_food_pig[] =
3478 static int ep_historic_wall[] =
3489 EL_GATE_1_GRAY_ACTIVE,
3490 EL_GATE_2_GRAY_ACTIVE,
3491 EL_GATE_3_GRAY_ACTIVE,
3492 EL_GATE_4_GRAY_ACTIVE,
3501 EL_EM_GATE_1_GRAY_ACTIVE,
3502 EL_EM_GATE_2_GRAY_ACTIVE,
3503 EL_EM_GATE_3_GRAY_ACTIVE,
3504 EL_EM_GATE_4_GRAY_ACTIVE,
3511 EL_EXPANDABLE_WALL_HORIZONTAL,
3512 EL_EXPANDABLE_WALL_VERTICAL,
3513 EL_EXPANDABLE_WALL_ANY,
3514 EL_EXPANDABLE_WALL_GROWING,
3515 EL_BD_EXPANDABLE_WALL,
3522 EL_SP_HARDWARE_GRAY,
3523 EL_SP_HARDWARE_GREEN,
3524 EL_SP_HARDWARE_BLUE,
3526 EL_SP_HARDWARE_YELLOW,
3527 EL_SP_HARDWARE_BASE_1,
3528 EL_SP_HARDWARE_BASE_2,
3529 EL_SP_HARDWARE_BASE_3,
3530 EL_SP_HARDWARE_BASE_4,
3531 EL_SP_HARDWARE_BASE_5,
3532 EL_SP_HARDWARE_BASE_6,
3534 EL_SP_TERMINAL_ACTIVE,
3537 EL_INVISIBLE_STEELWALL,
3538 EL_INVISIBLE_STEELWALL_ACTIVE,
3540 EL_INVISIBLE_WALL_ACTIVE,
3541 EL_STEELWALL_SLIPPERY,
3558 static int ep_historic_solid[] =
3562 EL_EXPANDABLE_WALL_HORIZONTAL,
3563 EL_EXPANDABLE_WALL_VERTICAL,
3564 EL_EXPANDABLE_WALL_ANY,
3565 EL_BD_EXPANDABLE_WALL,
3578 EL_QUICKSAND_FILLING,
3579 EL_QUICKSAND_EMPTYING,
3581 EL_MAGIC_WALL_ACTIVE,
3582 EL_MAGIC_WALL_EMPTYING,
3583 EL_MAGIC_WALL_FILLING,
3587 EL_BD_MAGIC_WALL_ACTIVE,
3588 EL_BD_MAGIC_WALL_EMPTYING,
3589 EL_BD_MAGIC_WALL_FULL,
3590 EL_BD_MAGIC_WALL_FILLING,
3591 EL_BD_MAGIC_WALL_DEAD,
3600 EL_SP_TERMINAL_ACTIVE,
3604 EL_INVISIBLE_WALL_ACTIVE,
3605 EL_SWITCHGATE_SWITCH_UP,
3606 EL_SWITCHGATE_SWITCH_DOWN,
3607 EL_DC_SWITCHGATE_SWITCH_UP,
3608 EL_DC_SWITCHGATE_SWITCH_DOWN,
3610 EL_TIMEGATE_SWITCH_ACTIVE,
3611 EL_DC_TIMEGATE_SWITCH,
3612 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3624 /* the following elements are a direct copy of "indestructible" elements,
3625 except "EL_ACID", which is "indestructible", but not "solid"! */
3630 EL_ACID_POOL_TOPLEFT,
3631 EL_ACID_POOL_TOPRIGHT,
3632 EL_ACID_POOL_BOTTOMLEFT,
3633 EL_ACID_POOL_BOTTOM,
3634 EL_ACID_POOL_BOTTOMRIGHT,
3635 EL_SP_HARDWARE_GRAY,
3636 EL_SP_HARDWARE_GREEN,
3637 EL_SP_HARDWARE_BLUE,
3639 EL_SP_HARDWARE_YELLOW,
3640 EL_SP_HARDWARE_BASE_1,
3641 EL_SP_HARDWARE_BASE_2,
3642 EL_SP_HARDWARE_BASE_3,
3643 EL_SP_HARDWARE_BASE_4,
3644 EL_SP_HARDWARE_BASE_5,
3645 EL_SP_HARDWARE_BASE_6,
3646 EL_INVISIBLE_STEELWALL,
3647 EL_INVISIBLE_STEELWALL_ACTIVE,
3648 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3649 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3650 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3651 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3652 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3653 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3654 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3655 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3656 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3657 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3658 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3659 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3661 EL_LIGHT_SWITCH_ACTIVE,
3662 EL_SIGN_EXCLAMATION,
3663 EL_SIGN_RADIOACTIVITY,
3670 EL_SIGN_ENTRY_FORBIDDEN,
3671 EL_SIGN_EMERGENCY_EXIT,
3679 EL_STEEL_EXIT_CLOSED,
3681 EL_DC_STEELWALL_1_LEFT,
3682 EL_DC_STEELWALL_1_RIGHT,
3683 EL_DC_STEELWALL_1_TOP,
3684 EL_DC_STEELWALL_1_BOTTOM,
3685 EL_DC_STEELWALL_1_HORIZONTAL,
3686 EL_DC_STEELWALL_1_VERTICAL,
3687 EL_DC_STEELWALL_1_TOPLEFT,
3688 EL_DC_STEELWALL_1_TOPRIGHT,
3689 EL_DC_STEELWALL_1_BOTTOMLEFT,
3690 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3691 EL_DC_STEELWALL_1_TOPLEFT_2,
3692 EL_DC_STEELWALL_1_TOPRIGHT_2,
3693 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3694 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3695 EL_DC_STEELWALL_2_LEFT,
3696 EL_DC_STEELWALL_2_RIGHT,
3697 EL_DC_STEELWALL_2_TOP,
3698 EL_DC_STEELWALL_2_BOTTOM,
3699 EL_DC_STEELWALL_2_HORIZONTAL,
3700 EL_DC_STEELWALL_2_VERTICAL,
3701 EL_DC_STEELWALL_2_MIDDLE,
3702 EL_DC_STEELWALL_2_SINGLE,
3703 EL_STEELWALL_SLIPPERY,
3717 EL_GATE_1_GRAY_ACTIVE,
3718 EL_GATE_2_GRAY_ACTIVE,
3719 EL_GATE_3_GRAY_ACTIVE,
3720 EL_GATE_4_GRAY_ACTIVE,
3729 EL_EM_GATE_1_GRAY_ACTIVE,
3730 EL_EM_GATE_2_GRAY_ACTIVE,
3731 EL_EM_GATE_3_GRAY_ACTIVE,
3732 EL_EM_GATE_4_GRAY_ACTIVE,
3734 EL_SWITCHGATE_OPENING,
3735 EL_SWITCHGATE_CLOSED,
3736 EL_SWITCHGATE_CLOSING,
3738 EL_TIMEGATE_OPENING,
3740 EL_TIMEGATE_CLOSING,
3744 EL_TUBE_VERTICAL_LEFT,
3745 EL_TUBE_VERTICAL_RIGHT,
3746 EL_TUBE_HORIZONTAL_UP,
3747 EL_TUBE_HORIZONTAL_DOWN,
3756 static int ep_classic_enemy[] =
3773 static int ep_belt[] =
3775 EL_CONVEYOR_BELT_1_LEFT,
3776 EL_CONVEYOR_BELT_1_MIDDLE,
3777 EL_CONVEYOR_BELT_1_RIGHT,
3778 EL_CONVEYOR_BELT_2_LEFT,
3779 EL_CONVEYOR_BELT_2_MIDDLE,
3780 EL_CONVEYOR_BELT_2_RIGHT,
3781 EL_CONVEYOR_BELT_3_LEFT,
3782 EL_CONVEYOR_BELT_3_MIDDLE,
3783 EL_CONVEYOR_BELT_3_RIGHT,
3784 EL_CONVEYOR_BELT_4_LEFT,
3785 EL_CONVEYOR_BELT_4_MIDDLE,
3786 EL_CONVEYOR_BELT_4_RIGHT,
3791 static int ep_belt_active[] =
3793 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3794 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3795 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3796 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3797 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3798 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3799 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3800 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3801 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3802 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3803 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3804 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3809 static int ep_belt_switch[] =
3811 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3812 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3813 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3814 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3815 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3816 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3817 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3818 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3819 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3820 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3821 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3822 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3827 static int ep_tube[] =
3834 EL_TUBE_HORIZONTAL_UP,
3835 EL_TUBE_HORIZONTAL_DOWN,
3837 EL_TUBE_VERTICAL_LEFT,
3838 EL_TUBE_VERTICAL_RIGHT,
3844 static int ep_acid_pool[] =
3846 EL_ACID_POOL_TOPLEFT,
3847 EL_ACID_POOL_TOPRIGHT,
3848 EL_ACID_POOL_BOTTOMLEFT,
3849 EL_ACID_POOL_BOTTOM,
3850 EL_ACID_POOL_BOTTOMRIGHT,
3855 static int ep_keygate[] =
3865 EL_GATE_1_GRAY_ACTIVE,
3866 EL_GATE_2_GRAY_ACTIVE,
3867 EL_GATE_3_GRAY_ACTIVE,
3868 EL_GATE_4_GRAY_ACTIVE,
3877 EL_EM_GATE_1_GRAY_ACTIVE,
3878 EL_EM_GATE_2_GRAY_ACTIVE,
3879 EL_EM_GATE_3_GRAY_ACTIVE,
3880 EL_EM_GATE_4_GRAY_ACTIVE,
3889 EL_EMC_GATE_5_GRAY_ACTIVE,
3890 EL_EMC_GATE_6_GRAY_ACTIVE,
3891 EL_EMC_GATE_7_GRAY_ACTIVE,
3892 EL_EMC_GATE_8_GRAY_ACTIVE,
3894 EL_DC_GATE_WHITE_GRAY,
3895 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3900 static int ep_amoeboid[] =
3912 static int ep_amoebalive[] =
3923 static int ep_has_editor_content[] =
3929 EL_SOKOBAN_FIELD_PLAYER,
3946 static int ep_can_turn_each_move[] =
3948 /* !!! do something with this one !!! */
3952 static int ep_can_grow[] =
3966 static int ep_active_bomb[] =
3969 EL_EM_DYNAMITE_ACTIVE,
3970 EL_DYNABOMB_PLAYER_1_ACTIVE,
3971 EL_DYNABOMB_PLAYER_2_ACTIVE,
3972 EL_DYNABOMB_PLAYER_3_ACTIVE,
3973 EL_DYNABOMB_PLAYER_4_ACTIVE,
3974 EL_SP_DISK_RED_ACTIVE,
3979 static int ep_inactive[] =
3989 EL_QUICKSAND_FAST_EMPTY,
4012 EL_GATE_1_GRAY_ACTIVE,
4013 EL_GATE_2_GRAY_ACTIVE,
4014 EL_GATE_3_GRAY_ACTIVE,
4015 EL_GATE_4_GRAY_ACTIVE,
4024 EL_EM_GATE_1_GRAY_ACTIVE,
4025 EL_EM_GATE_2_GRAY_ACTIVE,
4026 EL_EM_GATE_3_GRAY_ACTIVE,
4027 EL_EM_GATE_4_GRAY_ACTIVE,
4036 EL_EMC_GATE_5_GRAY_ACTIVE,
4037 EL_EMC_GATE_6_GRAY_ACTIVE,
4038 EL_EMC_GATE_7_GRAY_ACTIVE,
4039 EL_EMC_GATE_8_GRAY_ACTIVE,
4041 EL_DC_GATE_WHITE_GRAY,
4042 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4043 EL_DC_GATE_FAKE_GRAY,
4046 EL_INVISIBLE_STEELWALL,
4054 EL_WALL_EMERALD_YELLOW,
4055 EL_DYNABOMB_INCREASE_NUMBER,
4056 EL_DYNABOMB_INCREASE_SIZE,
4057 EL_DYNABOMB_INCREASE_POWER,
4061 EL_SOKOBAN_FIELD_EMPTY,
4062 EL_SOKOBAN_FIELD_FULL,
4063 EL_WALL_EMERALD_RED,
4064 EL_WALL_EMERALD_PURPLE,
4065 EL_ACID_POOL_TOPLEFT,
4066 EL_ACID_POOL_TOPRIGHT,
4067 EL_ACID_POOL_BOTTOMLEFT,
4068 EL_ACID_POOL_BOTTOM,
4069 EL_ACID_POOL_BOTTOMRIGHT,
4073 EL_BD_MAGIC_WALL_DEAD,
4075 EL_DC_MAGIC_WALL_DEAD,
4076 EL_AMOEBA_TO_DIAMOND,
4084 EL_SP_GRAVITY_PORT_RIGHT,
4085 EL_SP_GRAVITY_PORT_DOWN,
4086 EL_SP_GRAVITY_PORT_LEFT,
4087 EL_SP_GRAVITY_PORT_UP,
4088 EL_SP_PORT_HORIZONTAL,
4089 EL_SP_PORT_VERTICAL,
4100 EL_SP_HARDWARE_GRAY,
4101 EL_SP_HARDWARE_GREEN,
4102 EL_SP_HARDWARE_BLUE,
4104 EL_SP_HARDWARE_YELLOW,
4105 EL_SP_HARDWARE_BASE_1,
4106 EL_SP_HARDWARE_BASE_2,
4107 EL_SP_HARDWARE_BASE_3,
4108 EL_SP_HARDWARE_BASE_4,
4109 EL_SP_HARDWARE_BASE_5,
4110 EL_SP_HARDWARE_BASE_6,
4111 EL_SP_GRAVITY_ON_PORT_LEFT,
4112 EL_SP_GRAVITY_ON_PORT_RIGHT,
4113 EL_SP_GRAVITY_ON_PORT_UP,
4114 EL_SP_GRAVITY_ON_PORT_DOWN,
4115 EL_SP_GRAVITY_OFF_PORT_LEFT,
4116 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4117 EL_SP_GRAVITY_OFF_PORT_UP,
4118 EL_SP_GRAVITY_OFF_PORT_DOWN,
4119 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4120 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4121 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4122 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4123 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4124 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4125 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4126 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4127 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4128 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4129 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4130 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4131 EL_SIGN_EXCLAMATION,
4132 EL_SIGN_RADIOACTIVITY,
4139 EL_SIGN_ENTRY_FORBIDDEN,
4140 EL_SIGN_EMERGENCY_EXIT,
4148 EL_DC_STEELWALL_1_LEFT,
4149 EL_DC_STEELWALL_1_RIGHT,
4150 EL_DC_STEELWALL_1_TOP,
4151 EL_DC_STEELWALL_1_BOTTOM,
4152 EL_DC_STEELWALL_1_HORIZONTAL,
4153 EL_DC_STEELWALL_1_VERTICAL,
4154 EL_DC_STEELWALL_1_TOPLEFT,
4155 EL_DC_STEELWALL_1_TOPRIGHT,
4156 EL_DC_STEELWALL_1_BOTTOMLEFT,
4157 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4158 EL_DC_STEELWALL_1_TOPLEFT_2,
4159 EL_DC_STEELWALL_1_TOPRIGHT_2,
4160 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4161 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4162 EL_DC_STEELWALL_2_LEFT,
4163 EL_DC_STEELWALL_2_RIGHT,
4164 EL_DC_STEELWALL_2_TOP,
4165 EL_DC_STEELWALL_2_BOTTOM,
4166 EL_DC_STEELWALL_2_HORIZONTAL,
4167 EL_DC_STEELWALL_2_VERTICAL,
4168 EL_DC_STEELWALL_2_MIDDLE,
4169 EL_DC_STEELWALL_2_SINGLE,
4170 EL_STEELWALL_SLIPPERY,
4175 EL_EMC_WALL_SLIPPERY_1,
4176 EL_EMC_WALL_SLIPPERY_2,
4177 EL_EMC_WALL_SLIPPERY_3,
4178 EL_EMC_WALL_SLIPPERY_4,
4199 static int ep_em_slippery_wall[] =
4204 static int ep_gfx_crumbled[] =
4215 static int ep_editor_cascade_active[] =
4217 EL_INTERNAL_CASCADE_BD_ACTIVE,
4218 EL_INTERNAL_CASCADE_EM_ACTIVE,
4219 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4220 EL_INTERNAL_CASCADE_RND_ACTIVE,
4221 EL_INTERNAL_CASCADE_SB_ACTIVE,
4222 EL_INTERNAL_CASCADE_SP_ACTIVE,
4223 EL_INTERNAL_CASCADE_DC_ACTIVE,
4224 EL_INTERNAL_CASCADE_DX_ACTIVE,
4225 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4226 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4227 EL_INTERNAL_CASCADE_CE_ACTIVE,
4228 EL_INTERNAL_CASCADE_GE_ACTIVE,
4229 EL_INTERNAL_CASCADE_REF_ACTIVE,
4230 EL_INTERNAL_CASCADE_USER_ACTIVE,
4231 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4236 static int ep_editor_cascade_inactive[] =
4238 EL_INTERNAL_CASCADE_BD,
4239 EL_INTERNAL_CASCADE_EM,
4240 EL_INTERNAL_CASCADE_EMC,
4241 EL_INTERNAL_CASCADE_RND,
4242 EL_INTERNAL_CASCADE_SB,
4243 EL_INTERNAL_CASCADE_SP,
4244 EL_INTERNAL_CASCADE_DC,
4245 EL_INTERNAL_CASCADE_DX,
4246 EL_INTERNAL_CASCADE_CHARS,
4247 EL_INTERNAL_CASCADE_STEEL_CHARS,
4248 EL_INTERNAL_CASCADE_CE,
4249 EL_INTERNAL_CASCADE_GE,
4250 EL_INTERNAL_CASCADE_REF,
4251 EL_INTERNAL_CASCADE_USER,
4252 EL_INTERNAL_CASCADE_DYNAMIC,
4257 static int ep_obsolete[] =
4261 EL_EM_KEY_1_FILE_OBSOLETE,
4262 EL_EM_KEY_2_FILE_OBSOLETE,
4263 EL_EM_KEY_3_FILE_OBSOLETE,
4264 EL_EM_KEY_4_FILE_OBSOLETE,
4265 EL_ENVELOPE_OBSOLETE,
4274 } element_properties[] =
4276 { ep_diggable, EP_DIGGABLE },
4277 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4278 { ep_dont_run_into, EP_DONT_RUN_INTO },
4279 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4280 { ep_dont_touch, EP_DONT_TOUCH },
4281 { ep_indestructible, EP_INDESTRUCTIBLE },
4282 { ep_slippery, EP_SLIPPERY },
4283 { ep_can_change, EP_CAN_CHANGE },
4284 { ep_can_move, EP_CAN_MOVE },
4285 { ep_can_fall, EP_CAN_FALL },
4286 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4287 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4288 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4289 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4290 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4291 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4292 { ep_walkable_over, EP_WALKABLE_OVER },
4293 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4294 { ep_walkable_under, EP_WALKABLE_UNDER },
4295 { ep_passable_over, EP_PASSABLE_OVER },
4296 { ep_passable_inside, EP_PASSABLE_INSIDE },
4297 { ep_passable_under, EP_PASSABLE_UNDER },
4298 { ep_droppable, EP_DROPPABLE },
4299 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4300 { ep_pushable, EP_PUSHABLE },
4301 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4302 { ep_protected, EP_PROTECTED },
4303 { ep_throwable, EP_THROWABLE },
4304 { ep_can_explode, EP_CAN_EXPLODE },
4305 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4307 { ep_player, EP_PLAYER },
4308 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4309 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4310 { ep_switchable, EP_SWITCHABLE },
4311 { ep_bd_element, EP_BD_ELEMENT },
4312 { ep_sp_element, EP_SP_ELEMENT },
4313 { ep_sb_element, EP_SB_ELEMENT },
4315 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4316 { ep_food_penguin, EP_FOOD_PENGUIN },
4317 { ep_food_pig, EP_FOOD_PIG },
4318 { ep_historic_wall, EP_HISTORIC_WALL },
4319 { ep_historic_solid, EP_HISTORIC_SOLID },
4320 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4321 { ep_belt, EP_BELT },
4322 { ep_belt_active, EP_BELT_ACTIVE },
4323 { ep_belt_switch, EP_BELT_SWITCH },
4324 { ep_tube, EP_TUBE },
4325 { ep_acid_pool, EP_ACID_POOL },
4326 { ep_keygate, EP_KEYGATE },
4327 { ep_amoeboid, EP_AMOEBOID },
4328 { ep_amoebalive, EP_AMOEBALIVE },
4329 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4330 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4331 { ep_can_grow, EP_CAN_GROW },
4332 { ep_active_bomb, EP_ACTIVE_BOMB },
4333 { ep_inactive, EP_INACTIVE },
4335 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4337 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4339 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4340 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4342 { ep_obsolete, EP_OBSOLETE },
4349 /* always start with reliable default values (element has no properties) */
4350 /* (but never initialize clipboard elements after the very first time) */
4351 /* (to be able to use clipboard elements between several levels) */
4352 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4353 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4354 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4355 SET_PROPERTY(i, j, FALSE);
4357 /* set all base element properties from above array definitions */
4358 for (i = 0; element_properties[i].elements != NULL; i++)
4359 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4360 SET_PROPERTY((element_properties[i].elements)[j],
4361 element_properties[i].property, TRUE);
4363 /* copy properties to some elements that are only stored in level file */
4364 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4365 for (j = 0; copy_properties[j][0] != -1; j++)
4366 if (HAS_PROPERTY(copy_properties[j][0], i))
4367 for (k = 1; k <= 4; k++)
4368 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4370 /* set static element properties that are not listed in array definitions */
4371 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4372 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4374 clipboard_elements_initialized = TRUE;
4377 void InitElementPropertiesEngine(int engine_version)
4379 static int no_wall_properties[] =
4382 EP_COLLECTIBLE_ONLY,
4384 EP_DONT_COLLIDE_WITH,
4387 EP_CAN_SMASH_PLAYER,
4388 EP_CAN_SMASH_ENEMIES,
4389 EP_CAN_SMASH_EVERYTHING,
4394 EP_FOOD_DARK_YAMYAM,
4410 /* important: after initialization in InitElementPropertiesStatic(), the
4411 elements are not again initialized to a default value; therefore all
4412 changes have to make sure that they leave the element with a defined
4413 property (which means that conditional property changes must be set to
4414 a reliable default value before) */
4416 /* resolve group elements */
4417 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4418 ResolveGroupElement(EL_GROUP_START + i);
4420 /* set all special, combined or engine dependent element properties */
4421 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4423 /* do not change (already initialized) clipboard elements here */
4424 if (IS_CLIPBOARD_ELEMENT(i))
4427 /* ---------- INACTIVE ------------------------------------------------- */
4428 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4429 i <= EL_CHAR_END) ||
4430 (i >= EL_STEEL_CHAR_START &&
4431 i <= EL_STEEL_CHAR_END)));
4433 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4434 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4435 IS_WALKABLE_INSIDE(i) ||
4436 IS_WALKABLE_UNDER(i)));
4438 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4439 IS_PASSABLE_INSIDE(i) ||
4440 IS_PASSABLE_UNDER(i)));
4442 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4443 IS_PASSABLE_OVER(i)));
4445 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4446 IS_PASSABLE_INSIDE(i)));
4448 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4449 IS_PASSABLE_UNDER(i)));
4451 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4454 /* ---------- COLLECTIBLE ---------------------------------------------- */
4455 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4459 /* ---------- SNAPPABLE ------------------------------------------------ */
4460 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4461 IS_COLLECTIBLE(i) ||
4465 /* ---------- WALL ----------------------------------------------------- */
4466 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4468 for (j = 0; no_wall_properties[j] != -1; j++)
4469 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4470 i >= EL_FIRST_RUNTIME_UNREAL)
4471 SET_PROPERTY(i, EP_WALL, FALSE);
4473 if (IS_HISTORIC_WALL(i))
4474 SET_PROPERTY(i, EP_WALL, TRUE);
4476 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4477 if (engine_version < VERSION_IDENT(2,2,0,0))
4478 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4480 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4482 !IS_COLLECTIBLE(i)));
4484 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4485 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4486 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4488 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4489 IS_INDESTRUCTIBLE(i)));
4491 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4493 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4494 else if (engine_version < VERSION_IDENT(2,2,0,0))
4495 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4497 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4501 if (IS_CUSTOM_ELEMENT(i))
4503 /* these are additional properties which are initially false when set */
4505 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4507 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4508 if (DONT_COLLIDE_WITH(i))
4509 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4511 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4512 if (CAN_SMASH_EVERYTHING(i))
4513 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4514 if (CAN_SMASH_ENEMIES(i))
4515 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4518 /* ---------- CAN_SMASH ------------------------------------------------ */
4519 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4520 CAN_SMASH_ENEMIES(i) ||
4521 CAN_SMASH_EVERYTHING(i)));
4523 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4524 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4525 EXPLODES_BY_FIRE(i)));
4527 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4528 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4529 EXPLODES_SMASHED(i)));
4531 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4532 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4533 EXPLODES_IMPACT(i)));
4535 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4536 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4538 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4539 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4540 i == EL_BLACK_ORB));
4542 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4543 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4545 IS_CUSTOM_ELEMENT(i)));
4547 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4548 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4549 i == EL_SP_ELECTRON));
4551 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4552 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4553 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4554 getMoveIntoAcidProperty(&level, i));
4556 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4557 if (MAYBE_DONT_COLLIDE_WITH(i))
4558 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4559 getDontCollideWithProperty(&level, i));
4561 /* ---------- SP_PORT -------------------------------------------------- */
4562 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4563 IS_PASSABLE_INSIDE(i)));
4565 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4566 for (j = 0; j < level.num_android_clone_elements; j++)
4567 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4569 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4571 /* ---------- CAN_CHANGE ----------------------------------------------- */
4572 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4573 for (j = 0; j < element_info[i].num_change_pages; j++)
4574 if (element_info[i].change_page[j].can_change)
4575 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4577 /* ---------- HAS_ACTION ----------------------------------------------- */
4578 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4579 for (j = 0; j < element_info[i].num_change_pages; j++)
4580 if (element_info[i].change_page[j].has_action)
4581 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4583 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4584 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4587 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4588 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4589 element_info[i].crumbled[ACTION_DEFAULT] !=
4590 element_info[i].graphic[ACTION_DEFAULT]);
4592 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4593 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4594 IS_EDITOR_CASCADE_INACTIVE(i)));
4597 /* dynamically adjust element properties according to game engine version */
4599 static int ep_em_slippery_wall[] =
4604 EL_EXPANDABLE_WALL_HORIZONTAL,
4605 EL_EXPANDABLE_WALL_VERTICAL,
4606 EL_EXPANDABLE_WALL_ANY,
4607 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4608 EL_EXPANDABLE_STEELWALL_VERTICAL,
4609 EL_EXPANDABLE_STEELWALL_ANY,
4610 EL_EXPANDABLE_STEELWALL_GROWING,
4614 static int ep_em_explodes_by_fire[] =
4617 EL_EM_DYNAMITE_ACTIVE,
4622 /* special EM style gems behaviour */
4623 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4624 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4625 level.em_slippery_gems);
4627 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4628 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4629 (level.em_slippery_gems &&
4630 engine_version > VERSION_IDENT(2,0,1,0)));
4632 /* special EM style explosion behaviour regarding chain reactions */
4633 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4634 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4635 level.em_explodes_by_fire);
4638 /* this is needed because some graphics depend on element properties */
4639 if (game_status == GAME_MODE_PLAYING)
4640 InitElementGraphicInfo();
4643 void InitElementPropertiesAfterLoading(int engine_version)
4647 /* set some other uninitialized values of custom elements in older levels */
4648 if (engine_version < VERSION_IDENT(3,1,0,0))
4650 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4652 int element = EL_CUSTOM_START + i;
4654 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4656 element_info[element].explosion_delay = 17;
4657 element_info[element].ignition_delay = 8;
4662 void InitElementPropertiesGfxElement()
4666 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4668 struct ElementInfo *ei = &element_info[i];
4670 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4674 static void InitGlobal()
4679 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4681 /* check if element_name_info entry defined for each element in "main.h" */
4682 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4683 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4685 element_info[i].token_name = element_name_info[i].token_name;
4686 element_info[i].class_name = element_name_info[i].class_name;
4687 element_info[i].editor_description= element_name_info[i].editor_description;
4690 /* create hash from image config list */
4691 image_config_hash = newSetupFileHash();
4692 for (i = 0; image_config[i].token != NULL; i++)
4693 setHashEntry(image_config_hash,
4694 image_config[i].token,
4695 image_config[i].value);
4697 /* create hash from element token list */
4698 element_token_hash = newSetupFileHash();
4699 for (i = 0; element_name_info[i].token_name != NULL; i++)
4700 setHashEntry(element_token_hash,
4701 element_name_info[i].token_name,
4704 /* create hash from graphic token list */
4705 graphic_token_hash = newSetupFileHash();
4706 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4707 if (strSuffix(image_config[i].value, ".png") ||
4708 strSuffix(image_config[i].value, ".pcx") ||
4709 strSuffix(image_config[i].value, ".wav") ||
4710 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4711 setHashEntry(graphic_token_hash,
4712 image_config[i].token,
4713 int2str(graphic++, 0));
4715 /* create hash from font token list */
4716 font_token_hash = newSetupFileHash();
4717 for (i = 0; font_info[i].token_name != NULL; i++)
4718 setHashEntry(font_token_hash,
4719 font_info[i].token_name,
4722 /* set default filenames for all cloned graphics in static configuration */
4723 for (i = 0; image_config[i].token != NULL; i++)
4725 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4727 char *token = image_config[i].token;
4728 char *token_clone_from = getStringCat2(token, ".clone_from");
4729 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4731 if (token_cloned != NULL)
4733 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4735 if (value_cloned != NULL)
4737 /* set default filename in static configuration */
4738 image_config[i].value = value_cloned;
4740 /* set default filename in image config hash */
4741 setHashEntry(image_config_hash, token, value_cloned);
4745 free(token_clone_from);
4749 /* always start with reliable default values (all elements) */
4750 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4751 ActiveElement[i] = i;
4753 /* now add all entries that have an active state (active elements) */
4754 for (i = 0; element_with_active_state[i].element != -1; i++)
4756 int element = element_with_active_state[i].element;
4757 int element_active = element_with_active_state[i].element_active;
4759 ActiveElement[element] = element_active;
4762 /* always start with reliable default values (all buttons) */
4763 for (i = 0; i < NUM_IMAGE_FILES; i++)
4764 ActiveButton[i] = i;
4766 /* now add all entries that have an active state (active buttons) */
4767 for (i = 0; button_with_active_state[i].button != -1; i++)
4769 int button = button_with_active_state[i].button;
4770 int button_active = button_with_active_state[i].button_active;
4772 ActiveButton[button] = button_active;
4775 /* always start with reliable default values (all fonts) */
4776 for (i = 0; i < NUM_FONTS; i++)
4779 /* now add all entries that have an active state (active fonts) */
4780 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4782 int font = font_with_active_state[i].font_nr;
4783 int font_active = font_with_active_state[i].font_nr_active;
4785 ActiveFont[font] = font_active;
4788 global.autoplay_leveldir = NULL;
4789 global.convert_leveldir = NULL;
4790 global.create_images_dir = NULL;
4792 global.frames_per_second = 0;
4794 global.border_status = GAME_MODE_LOADING;
4795 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4797 global.use_envelope_request = FALSE;
4800 void Execute_Command(char *command)
4804 if (strEqual(command, "print graphicsinfo.conf"))
4806 Print("# You can configure additional/alternative image files here.\n");
4807 Print("# (The entries below are default and therefore commented out.)\n");
4809 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4811 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4814 for (i = 0; image_config[i].token != NULL; i++)
4815 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4816 image_config[i].value));
4820 else if (strEqual(command, "print soundsinfo.conf"))
4822 Print("# You can configure additional/alternative sound files here.\n");
4823 Print("# (The entries below are default and therefore commented out.)\n");
4825 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4827 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4830 for (i = 0; sound_config[i].token != NULL; i++)
4831 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4832 sound_config[i].value));
4836 else if (strEqual(command, "print musicinfo.conf"))
4838 Print("# You can configure additional/alternative music files here.\n");
4839 Print("# (The entries below are default and therefore commented out.)\n");
4841 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4843 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4846 for (i = 0; music_config[i].token != NULL; i++)
4847 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4848 music_config[i].value));
4852 else if (strEqual(command, "print editorsetup.conf"))
4854 Print("# You can configure your personal editor element list here.\n");
4855 Print("# (The entries below are default and therefore commented out.)\n");
4858 /* this is needed to be able to check element list for cascade elements */
4859 InitElementPropertiesStatic();
4860 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4862 PrintEditorElementList();
4866 else if (strEqual(command, "print helpanim.conf"))
4868 Print("# You can configure different element help animations here.\n");
4869 Print("# (The entries below are default and therefore commented out.)\n");
4872 for (i = 0; helpanim_config[i].token != NULL; i++)
4874 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4875 helpanim_config[i].value));
4877 if (strEqual(helpanim_config[i].token, "end"))
4883 else if (strEqual(command, "print helptext.conf"))
4885 Print("# You can configure different element help text here.\n");
4886 Print("# (The entries below are default and therefore commented out.)\n");
4889 for (i = 0; helptext_config[i].token != NULL; i++)
4890 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4891 helptext_config[i].value));
4895 else if (strPrefix(command, "dump level "))
4897 char *filename = &command[11];
4899 if (!fileExists(filename))
4900 Error(ERR_EXIT, "cannot open file '%s'", filename);
4902 LoadLevelFromFilename(&level, filename);
4907 else if (strPrefix(command, "dump tape "))
4909 char *filename = &command[10];
4911 if (!fileExists(filename))
4912 Error(ERR_EXIT, "cannot open file '%s'", filename);
4914 LoadTapeFromFilename(filename);
4919 else if (strPrefix(command, "autotest ") ||
4920 strPrefix(command, "autoplay ") ||
4921 strPrefix(command, "autoffwd ") ||
4922 strPrefix(command, "autowarp "))
4924 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4926 global.autoplay_mode =
4927 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
4928 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
4929 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
4930 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
4931 AUTOPLAY_MODE_NONE);
4933 while (*str_ptr != '\0') /* continue parsing string */
4935 /* cut leading whitespace from string, replace it by string terminator */
4936 while (*str_ptr == ' ' || *str_ptr == '\t')
4939 if (*str_ptr == '\0') /* end of string reached */
4942 if (global.autoplay_leveldir == NULL) /* read level set string */
4944 global.autoplay_leveldir = str_ptr;
4945 global.autoplay_all = TRUE; /* default: play all tapes */
4947 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4948 global.autoplay_level[i] = FALSE;
4950 else /* read level number string */
4952 int level_nr = atoi(str_ptr); /* get level_nr value */
4954 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4955 global.autoplay_level[level_nr] = TRUE;
4957 global.autoplay_all = FALSE;
4960 /* advance string pointer to the next whitespace (or end of string) */
4961 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4965 else if (strPrefix(command, "convert "))
4967 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4968 char *str_ptr = strchr(str_copy, ' ');
4970 global.convert_leveldir = str_copy;
4971 global.convert_level_nr = -1;
4973 if (str_ptr != NULL) /* level number follows */
4975 *str_ptr++ = '\0'; /* terminate leveldir string */
4976 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4979 else if (strPrefix(command, "create images "))
4981 global.create_images_dir = getStringCopy(&command[14]);
4983 if (access(global.create_images_dir, W_OK) != 0)
4984 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4985 global.create_images_dir);
4987 else if (strPrefix(command, "create CE image "))
4989 CreateCustomElementImages(&command[16]);
4995 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4999 static void InitSetup()
5001 LoadSetup(); /* global setup info */
5003 /* set some options from setup file */
5005 if (setup.options.verbose)
5006 options.verbose = TRUE;
5009 static void InitGameInfo()
5011 game.restart_level = FALSE;
5014 static void InitPlayerInfo()
5018 /* choose default local player */
5019 local_player = &stored_player[0];
5021 for (i = 0; i < MAX_PLAYERS; i++)
5022 stored_player[i].connected = FALSE;
5024 local_player->connected = TRUE;
5027 static void InitArtworkInfo()
5032 static char *get_string_in_brackets(char *string)
5034 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5036 sprintf(string_in_brackets, "[%s]", string);
5038 return string_in_brackets;
5041 static char *get_level_id_suffix(int id_nr)
5043 char *id_suffix = checked_malloc(1 + 3 + 1);
5045 if (id_nr < 0 || id_nr > 999)
5048 sprintf(id_suffix, ".%03d", id_nr);
5053 static void InitArtworkConfig()
5055 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5057 NUM_GLOBAL_ANIM_TOKENS + 1];
5058 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5059 NUM_GLOBAL_ANIM_TOKENS + 1];
5060 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5061 NUM_GLOBAL_ANIM_TOKENS + 1];
5062 static char *action_id_suffix[NUM_ACTIONS + 1];
5063 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5064 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5065 static char *level_id_suffix[MAX_LEVELS + 1];
5066 static char *dummy[1] = { NULL };
5067 static char *ignore_generic_tokens[] =
5073 static char **ignore_image_tokens;
5074 static char **ignore_sound_tokens;
5075 static char **ignore_music_tokens;
5076 int num_ignore_generic_tokens;
5077 int num_ignore_image_tokens;
5078 int num_ignore_sound_tokens;
5079 int num_ignore_music_tokens;
5082 /* dynamically determine list of generic tokens to be ignored */
5083 num_ignore_generic_tokens = 0;
5084 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5085 num_ignore_generic_tokens++;
5087 /* dynamically determine list of image tokens to be ignored */
5088 num_ignore_image_tokens = num_ignore_generic_tokens;
5089 for (i = 0; image_config_vars[i].token != NULL; i++)
5090 num_ignore_image_tokens++;
5091 ignore_image_tokens =
5092 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5093 for (i = 0; i < num_ignore_generic_tokens; i++)
5094 ignore_image_tokens[i] = ignore_generic_tokens[i];
5095 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5096 ignore_image_tokens[num_ignore_generic_tokens + i] =
5097 image_config_vars[i].token;
5098 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5100 /* dynamically determine list of sound tokens to be ignored */
5101 num_ignore_sound_tokens = num_ignore_generic_tokens;
5102 ignore_sound_tokens =
5103 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5104 for (i = 0; i < num_ignore_generic_tokens; i++)
5105 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5106 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5108 /* dynamically determine list of music tokens to be ignored */
5109 num_ignore_music_tokens = num_ignore_generic_tokens;
5110 ignore_music_tokens =
5111 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5112 for (i = 0; i < num_ignore_generic_tokens; i++)
5113 ignore_music_tokens[i] = ignore_generic_tokens[i];
5114 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5116 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5117 image_id_prefix[i] = element_info[i].token_name;
5118 for (i = 0; i < NUM_FONTS; i++)
5119 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5120 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5121 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5122 global_anim_info[i].token_name;
5123 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5125 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5126 sound_id_prefix[i] = element_info[i].token_name;
5127 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5128 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5129 get_string_in_brackets(element_info[i].class_name);
5130 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5131 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5132 global_anim_info[i].token_name;
5133 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5135 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5136 music_id_prefix[i] = music_prefix_info[i].prefix;
5137 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5138 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5139 global_anim_info[i].token_name;
5140 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5142 for (i = 0; i < NUM_ACTIONS; i++)
5143 action_id_suffix[i] = element_action_info[i].suffix;
5144 action_id_suffix[NUM_ACTIONS] = NULL;
5146 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5147 direction_id_suffix[i] = element_direction_info[i].suffix;
5148 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5150 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5151 special_id_suffix[i] = special_suffix_info[i].suffix;
5152 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5154 for (i = 0; i < MAX_LEVELS; i++)
5155 level_id_suffix[i] = get_level_id_suffix(i);
5156 level_id_suffix[MAX_LEVELS] = NULL;
5158 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5159 image_id_prefix, action_id_suffix, direction_id_suffix,
5160 special_id_suffix, ignore_image_tokens);
5161 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5162 sound_id_prefix, action_id_suffix, dummy,
5163 special_id_suffix, ignore_sound_tokens);
5164 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5165 music_id_prefix, action_id_suffix, special_id_suffix,
5166 level_id_suffix, ignore_music_tokens);
5169 static void InitMixer()
5176 void InitGfxBuffers()
5178 static int win_xsize_last = -1;
5179 static int win_ysize_last = -1;
5181 /* create additional image buffers for double-buffering and cross-fading */
5183 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5185 /* used to temporarily store the backbuffer -- only re-create if changed */
5186 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5187 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5189 win_xsize_last = WIN_XSIZE;
5190 win_ysize_last = WIN_YSIZE;
5193 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5194 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5195 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5196 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5198 /* initialize screen properties */
5199 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5200 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5202 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5203 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5204 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5205 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5206 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5207 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5209 /* required if door size definitions have changed */
5210 InitGraphicCompatibilityInfo_Doors();
5212 InitGfxBuffers_EM();
5213 InitGfxBuffers_SP();
5218 struct GraphicInfo *graphic_info_last = graphic_info;
5219 char *filename_font_initial = NULL;
5220 char *filename_anim_initial = NULL;
5221 Bitmap *bitmap_font_initial = NULL;
5225 /* determine settings for initial font (for displaying startup messages) */
5226 for (i = 0; image_config[i].token != NULL; i++)
5228 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5230 char font_token[128];
5233 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5234 len_font_token = strlen(font_token);
5236 if (strEqual(image_config[i].token, font_token))
5237 filename_font_initial = image_config[i].value;
5238 else if (strlen(image_config[i].token) > len_font_token &&
5239 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5241 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5242 font_initial[j].src_x = atoi(image_config[i].value);
5243 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5244 font_initial[j].src_y = atoi(image_config[i].value);
5245 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5246 font_initial[j].width = atoi(image_config[i].value);
5247 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5248 font_initial[j].height = atoi(image_config[i].value);
5253 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5255 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5256 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5259 if (filename_font_initial == NULL) /* should not happen */
5260 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5263 InitGfxCustomArtworkInfo();
5264 InitGfxOtherSettings();
5266 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5268 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5269 font_initial[j].bitmap = bitmap_font_initial;
5271 InitFontGraphicInfo();
5273 font_height = getFontHeight(FC_RED);
5275 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5276 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5277 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5280 DrawInitText("Loading graphics", 120, FC_GREEN);
5282 /* initialize settings for busy animation with default values */
5283 int parameter[NUM_GFX_ARGS];
5284 for (i = 0; i < NUM_GFX_ARGS; i++)
5285 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5286 image_config_suffix[i].token,
5287 image_config_suffix[i].type);
5289 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5290 int len_anim_token = strlen(anim_token);
5292 /* read settings for busy animation from default custom artwork config */
5293 char *gfx_config_filename = getPath3(options.graphics_directory,
5295 GRAPHICSINFO_FILENAME);
5297 if (fileExists(gfx_config_filename))
5299 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5301 if (setup_file_hash)
5303 char *filename = getHashEntry(setup_file_hash, anim_token);
5307 filename_anim_initial = getStringCopy(filename);
5309 for (j = 0; image_config_suffix[j].token != NULL; j++)
5311 int type = image_config_suffix[j].type;
5312 char *suffix = image_config_suffix[j].token;
5313 char *token = getStringCat2(anim_token, suffix);
5314 char *value = getHashEntry(setup_file_hash, token);
5316 checked_free(token);
5319 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5323 freeSetupFileHash(setup_file_hash);
5327 if (filename_anim_initial == NULL)
5329 /* read settings for busy animation from static default artwork config */
5330 for (i = 0; image_config[i].token != NULL; i++)
5332 if (strEqual(image_config[i].token, anim_token))
5333 filename_anim_initial = getStringCopy(image_config[i].value);
5334 else if (strlen(image_config[i].token) > len_anim_token &&
5335 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5337 for (j = 0; image_config_suffix[j].token != NULL; j++)
5339 if (strEqual(&image_config[i].token[len_anim_token],
5340 image_config_suffix[j].token))
5342 get_graphic_parameter_value(image_config[i].value,
5343 image_config_suffix[j].token,
5344 image_config_suffix[j].type);
5350 if (filename_anim_initial == NULL) /* should not happen */
5351 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5353 anim_initial.bitmaps =
5354 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5356 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5357 LoadCustomImage(filename_anim_initial);
5359 checked_free(filename_anim_initial);
5361 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5363 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5365 graphic_info = graphic_info_last;
5367 init.busy.width = anim_initial.width;
5368 init.busy.height = anim_initial.height;
5370 InitMenuDesignSettings_Static();
5372 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5373 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5374 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5376 gfx.fade_border_source_status = global.border_status;
5377 gfx.fade_border_target_status = global.border_status;
5378 gfx.masked_border_bitmap_ptr = backbuffer;
5380 /* use copy of busy animation to prevent change while reloading artwork */
5384 void InitGfxBackground()
5386 fieldbuffer = bitmap_db_field;
5387 SetDrawtoField(DRAW_TO_BACKBUFFER);
5389 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5391 redraw_mask = REDRAW_ALL;
5394 static void InitLevelInfo()
5396 LoadLevelInfo(); /* global level info */
5397 LoadLevelSetup_LastSeries(); /* last played series info */
5398 LoadLevelSetup_SeriesInfo(); /* last played level info */
5400 if (global.autoplay_leveldir &&
5401 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5403 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5404 global.autoplay_leveldir);
5405 if (leveldir_current == NULL)
5406 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5410 static void InitLevelArtworkInfo()
5412 LoadLevelArtworkInfo();
5415 static void InitImages()
5417 print_timestamp_init("InitImages");
5420 printf("::: leveldir_current->identifier == '%s'\n",
5421 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5422 printf("::: leveldir_current->graphics_path == '%s'\n",
5423 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5424 printf("::: leveldir_current->graphics_set == '%s'\n",
5425 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5426 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5427 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5430 setLevelArtworkDir(artwork.gfx_first);
5433 printf("::: leveldir_current->identifier == '%s'\n",
5434 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5435 printf("::: leveldir_current->graphics_path == '%s'\n",
5436 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5437 printf("::: leveldir_current->graphics_set == '%s'\n",
5438 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5439 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5440 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5444 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5445 leveldir_current->identifier,
5446 artwork.gfx_current_identifier,
5447 artwork.gfx_current->identifier,
5448 leveldir_current->graphics_set,
5449 leveldir_current->graphics_path);
5452 UPDATE_BUSY_STATE();
5454 ReloadCustomImages();
5455 print_timestamp_time("ReloadCustomImages");
5457 UPDATE_BUSY_STATE();
5459 LoadCustomElementDescriptions();
5460 print_timestamp_time("LoadCustomElementDescriptions");
5462 UPDATE_BUSY_STATE();
5464 LoadMenuDesignSettings();
5465 print_timestamp_time("LoadMenuDesignSettings");
5467 UPDATE_BUSY_STATE();
5469 ReinitializeGraphics();
5470 print_timestamp_time("ReinitializeGraphics");
5472 LoadMenuDesignSettings_AfterGraphics();
5473 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5475 UPDATE_BUSY_STATE();
5477 print_timestamp_done("InitImages");
5480 static void InitSound(char *identifier)
5482 print_timestamp_init("InitSound");
5484 if (identifier == NULL)
5485 identifier = artwork.snd_current->identifier;
5487 /* set artwork path to send it to the sound server process */
5488 setLevelArtworkDir(artwork.snd_first);
5490 InitReloadCustomSounds(identifier);
5491 print_timestamp_time("InitReloadCustomSounds");
5493 ReinitializeSounds();
5494 print_timestamp_time("ReinitializeSounds");
5496 print_timestamp_done("InitSound");
5499 static void InitMusic(char *identifier)
5501 print_timestamp_init("InitMusic");
5503 if (identifier == NULL)
5504 identifier = artwork.mus_current->identifier;
5506 /* set artwork path to send it to the sound server process */
5507 setLevelArtworkDir(artwork.mus_first);
5509 InitReloadCustomMusic(identifier);
5510 print_timestamp_time("InitReloadCustomMusic");
5512 ReinitializeMusic();
5513 print_timestamp_time("ReinitializeMusic");
5515 print_timestamp_done("InitMusic");
5518 static void InitArtworkDone()
5520 InitGlobalAnimations();
5523 void InitNetworkServer()
5525 #if defined(NETWORK_AVALIABLE)
5529 if (!options.network)
5532 #if defined(NETWORK_AVALIABLE)
5533 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5535 if (!ConnectToServer(options.server_host, options.server_port))
5536 Error(ERR_EXIT, "cannot connect to network game server");
5538 SendToServer_PlayerName(setup.player_name);
5539 SendToServer_ProtocolVersion();
5542 SendToServer_NrWanted(nr_wanted);
5546 static boolean CheckArtworkConfigForCustomElements(char *filename)
5548 SetupFileHash *setup_file_hash;
5549 boolean redefined_ce_found = FALSE;
5551 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5553 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5555 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5557 char *token = HASH_ITERATION_TOKEN(itr);
5559 if (strPrefix(token, "custom_"))
5561 redefined_ce_found = TRUE;
5566 END_HASH_ITERATION(setup_file_hash, itr)
5568 freeSetupFileHash(setup_file_hash);
5571 return redefined_ce_found;
5574 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5576 char *filename_base, *filename_local;
5577 boolean redefined_ce_found = FALSE;
5579 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5582 printf("::: leveldir_current->identifier == '%s'\n",
5583 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5584 printf("::: leveldir_current->graphics_path == '%s'\n",
5585 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5586 printf("::: leveldir_current->graphics_set == '%s'\n",
5587 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5588 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5589 leveldir_current == NULL ? "[NULL]" :
5590 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5593 /* first look for special artwork configured in level series config */
5594 filename_base = getCustomArtworkLevelConfigFilename(type);
5597 printf("::: filename_base == '%s'\n", filename_base);
5600 if (fileExists(filename_base))
5601 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5603 filename_local = getCustomArtworkConfigFilename(type);
5606 printf("::: filename_local == '%s'\n", filename_local);
5609 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5610 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5613 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5616 return redefined_ce_found;
5619 static void InitOverrideArtwork()
5621 boolean redefined_ce_found = FALSE;
5623 /* to check if this level set redefines any CEs, do not use overriding */
5624 gfx.override_level_graphics = FALSE;
5625 gfx.override_level_sounds = FALSE;
5626 gfx.override_level_music = FALSE;
5628 /* now check if this level set has definitions for custom elements */
5629 if (setup.override_level_graphics == AUTO ||
5630 setup.override_level_sounds == AUTO ||
5631 setup.override_level_music == AUTO)
5632 redefined_ce_found =
5633 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5634 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5635 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5638 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5641 if (redefined_ce_found)
5643 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5644 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5645 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5646 gfx.override_level_music = (setup.override_level_music == TRUE);
5650 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5651 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5652 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5653 gfx.override_level_music = (setup.override_level_music != FALSE);
5657 printf("::: => %d, %d, %d\n",
5658 gfx.override_level_graphics,
5659 gfx.override_level_sounds,
5660 gfx.override_level_music);
5664 static char *getNewArtworkIdentifier(int type)
5666 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5667 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5668 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5669 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5670 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5671 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5672 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5673 char *leveldir_identifier = leveldir_current->identifier;
5674 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5675 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5676 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5677 char *artwork_current_identifier;
5678 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5680 /* leveldir_current may be invalid (level group, parent link) */
5681 if (!validLevelSeries(leveldir_current))
5684 /* 1st step: determine artwork set to be activated in descending order:
5685 --------------------------------------------------------------------
5686 1. setup artwork (when configured to override everything else)
5687 2. artwork set configured in "levelinfo.conf" of current level set
5688 (artwork in level directory will have priority when loading later)
5689 3. artwork in level directory (stored in artwork sub-directory)
5690 4. setup artwork (currently configured in setup menu) */
5692 if (setup_override_artwork)
5693 artwork_current_identifier = setup_artwork_set;
5694 else if (leveldir_artwork_set != NULL)
5695 artwork_current_identifier = leveldir_artwork_set;
5696 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5697 artwork_current_identifier = leveldir_identifier;
5699 artwork_current_identifier = setup_artwork_set;
5702 /* 2nd step: check if it is really needed to reload artwork set
5703 ------------------------------------------------------------ */
5705 /* ---------- reload if level set and also artwork set has changed ------- */
5706 if (leveldir_current_identifier[type] != leveldir_identifier &&
5707 (last_has_level_artwork_set[type] || has_level_artwork_set))
5708 artwork_new_identifier = artwork_current_identifier;
5710 leveldir_current_identifier[type] = leveldir_identifier;
5711 last_has_level_artwork_set[type] = has_level_artwork_set;
5713 /* ---------- reload if "override artwork" setting has changed ----------- */
5714 if (last_override_level_artwork[type] != setup_override_artwork)
5715 artwork_new_identifier = artwork_current_identifier;
5717 last_override_level_artwork[type] = setup_override_artwork;
5719 /* ---------- reload if current artwork identifier has changed ----------- */
5720 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5721 artwork_current_identifier))
5722 artwork_new_identifier = artwork_current_identifier;
5724 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5726 /* ---------- do not reload directly after starting ---------------------- */
5727 if (!initialized[type])
5728 artwork_new_identifier = NULL;
5730 initialized[type] = TRUE;
5732 return artwork_new_identifier;
5735 void ReloadCustomArtwork(int force_reload)
5737 int last_game_status = game_status; /* save current game status */
5738 char *gfx_new_identifier;
5739 char *snd_new_identifier;
5740 char *mus_new_identifier;
5741 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5742 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5743 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5744 boolean reload_needed;
5746 InitOverrideArtwork();
5748 force_reload_gfx |= AdjustGraphicsForEMC();
5750 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5751 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5752 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5754 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5755 snd_new_identifier != NULL || force_reload_snd ||
5756 mus_new_identifier != NULL || force_reload_mus);
5761 print_timestamp_init("ReloadCustomArtwork");
5763 SetGameStatus(GAME_MODE_LOADING);
5765 FadeOut(REDRAW_ALL);
5767 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5768 print_timestamp_time("ClearRectangle");
5772 if (gfx_new_identifier != NULL || force_reload_gfx)
5775 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5776 artwork.gfx_current_identifier,
5778 artwork.gfx_current->identifier,
5779 leveldir_current->graphics_set);
5783 print_timestamp_time("InitImages");
5786 if (snd_new_identifier != NULL || force_reload_snd)
5788 InitSound(snd_new_identifier);
5789 print_timestamp_time("InitSound");
5792 if (mus_new_identifier != NULL || force_reload_mus)
5794 InitMusic(mus_new_identifier);
5795 print_timestamp_time("InitMusic");
5800 SetGameStatus(last_game_status); /* restore current game status */
5802 init_last = init; /* switch to new busy animation */
5804 FadeOut(REDRAW_ALL);
5806 RedrawGlobalBorder();
5808 /* force redraw of (open or closed) door graphics */
5809 SetDoorState(DOOR_OPEN_ALL);
5810 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5812 FadeSetEnterScreen();
5813 FadeSkipNextFadeOut();
5815 print_timestamp_done("ReloadCustomArtwork");
5817 LimitScreenUpdates(FALSE);
5820 void KeyboardAutoRepeatOffUnlessAutoplay()
5822 if (global.autoplay_leveldir == NULL)
5823 KeyboardAutoRepeatOff();
5826 void DisplayExitMessage(char *format, va_list ap)
5828 // check if draw buffer and fonts for exit message are already available
5829 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5832 int font_1 = FC_RED;
5833 int font_2 = FC_YELLOW;
5834 int font_3 = FC_BLUE;
5835 int font_width = getFontWidth(font_2);
5836 int font_height = getFontHeight(font_2);
5839 int sxsize = WIN_XSIZE - 2 * sx;
5840 int sysize = WIN_YSIZE - 2 * sy;
5841 int line_length = sxsize / font_width;
5842 int max_lines = sysize / font_height;
5843 int num_lines_printed;
5847 gfx.sxsize = sxsize;
5848 gfx.sysize = sysize;
5852 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5854 DrawTextSCentered(sy, font_1, "Fatal error:");
5855 sy += 3 * font_height;;
5858 DrawTextBufferVA(sx, sy, format, ap, font_2,
5859 line_length, line_length, max_lines,
5860 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5861 sy += (num_lines_printed + 3) * font_height;
5863 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5864 sy += 3 * font_height;
5867 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5868 line_length, line_length, max_lines,
5869 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5871 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5873 redraw_mask = REDRAW_ALL;
5875 /* force drawing exit message even if screen updates are currently limited */
5876 LimitScreenUpdates(FALSE);
5880 /* deactivate toons on error message screen */
5881 setup.toons = FALSE;
5883 WaitForEventToContinue();
5887 /* ========================================================================= */
5889 /* ========================================================================= */
5893 print_timestamp_init("OpenAll");
5895 SetGameStatus(GAME_MODE_LOADING);
5899 InitGlobal(); /* initialize some global variables */
5901 print_timestamp_time("[init global stuff]");
5905 print_timestamp_time("[init setup/config stuff (1)]");
5909 if (options.execute_command)
5910 Execute_Command(options.execute_command);
5912 if (options.serveronly)
5914 #if defined(PLATFORM_UNIX)
5915 NetworkServer(options.server_port, options.serveronly);
5917 Error(ERR_WARN, "networking only supported in Unix version");
5920 exit(0); /* never reached, server loops forever */
5924 print_timestamp_time("[init setup/config stuff (2)]");
5926 print_timestamp_time("[init setup/config stuff (3)]");
5927 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5928 print_timestamp_time("[init setup/config stuff (4)]");
5929 InitArtworkConfig(); /* needed before forking sound child process */
5930 print_timestamp_time("[init setup/config stuff (5)]");
5932 print_timestamp_time("[init setup/config stuff (6)]");
5934 InitRND(NEW_RANDOMIZE);
5935 InitSimpleRandom(NEW_RANDOMIZE);
5939 print_timestamp_time("[init setup/config stuff]");
5942 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5946 print_timestamp_time("[init video stuff]");
5948 InitElementPropertiesStatic();
5949 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5950 InitElementPropertiesGfxElement();
5952 print_timestamp_time("[init element properties stuff]");
5956 print_timestamp_time("InitGfx");
5959 print_timestamp_time("InitLevelInfo");
5961 InitLevelArtworkInfo();
5962 print_timestamp_time("InitLevelArtworkInfo");
5964 InitOverrideArtwork(); /* needs to know current level directory */
5965 print_timestamp_time("InitOverrideArtwork");
5967 InitImages(); /* needs to know current level directory */
5968 print_timestamp_time("InitImages");
5970 InitSound(NULL); /* needs to know current level directory */
5971 print_timestamp_time("InitSound");
5973 InitMusic(NULL); /* needs to know current level directory */
5974 print_timestamp_time("InitMusic");
5978 InitGfxBackground();
5983 if (global.autoplay_leveldir)
5988 else if (global.convert_leveldir)
5993 else if (global.create_images_dir)
5995 CreateLevelSketchImages();
5999 SetGameStatus(GAME_MODE_MAIN);
6001 FadeSetEnterScreen();
6002 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6003 FadeSkipNextFadeOut();
6005 print_timestamp_time("[post-artwork]");
6007 print_timestamp_done("OpenAll");
6011 InitNetworkServer();
6014 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6016 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6017 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6018 #if defined(PLATFORM_ANDROID)
6019 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6020 SDL_AndroidGetInternalStoragePath());
6021 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6022 SDL_AndroidGetExternalStoragePath());
6023 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6024 (SDL_AndroidGetExternalStorageState() ==
6025 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
6026 SDL_AndroidGetExternalStorageState() ==
6027 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
6032 void CloseAllAndExit(int exit_value)
6037 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6044 #if defined(TARGET_SDL)
6045 #if defined(TARGET_SDL2)
6047 // set a flag to tell the network server thread to quit and wait for it
6048 // using SDL_WaitThread()
6050 if (network_server) /* terminate network server */
6051 SDL_KillThread(server_thread);
6055 CloseVideoDisplay();
6056 ClosePlatformDependentStuff();
6058 if (exit_value != 0)
6060 /* fall back to default level set (current set may have caused an error) */
6061 SaveLevelSetup_LastSeries_Deactivate();
6063 /* tell user where to find error log file which may contain more details */
6064 // (error notification now directly displayed on screen inside R'n'D
6065 // NotifyUserAboutErrorFile(); /* currently only works for Windows */