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;
1261 g->init_event = ANIM_EVENT_DEFAULT;
1262 g->anim_event = ANIM_EVENT_DEFAULT;
1264 g->fade_mode = FADE_MODE_DEFAULT;
1268 g->align = ALIGN_CENTER; /* default for title screens */
1269 g->valign = VALIGN_MIDDLE; /* default for title screens */
1270 g->sort_priority = 0; /* default for title screens */
1272 g->style = STYLE_DEFAULT;
1274 g->bitmaps = src_bitmaps;
1275 g->bitmap = src_bitmap;
1277 /* optional zoom factor for scaling up the image to a larger size */
1278 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1279 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1280 if (g->scale_up_factor < 1)
1281 g->scale_up_factor = 1; /* no scaling */
1283 /* optional tile size for using non-standard image size */
1284 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1286 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1289 // CHECK: should tile sizes less than standard tile size be allowed?
1290 if (g->tile_size < TILESIZE)
1291 g->tile_size = TILESIZE; /* standard tile size */
1294 // when setting tile size, also set width and height accordingly
1295 g->width = g->tile_size;
1296 g->height = g->tile_size;
1299 if (g->use_image_size)
1301 /* set new default bitmap size (with scaling, but without small images) */
1302 g->width = get_scaled_graphic_width(graphic);
1303 g->height = get_scaled_graphic_height(graphic);
1306 /* optional width and height of each animation frame */
1307 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1308 g->width = parameter[GFX_ARG_WIDTH];
1309 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1310 g->height = parameter[GFX_ARG_HEIGHT];
1312 /* optional x and y tile position of animation frame sequence */
1313 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1314 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1315 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1316 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1318 /* optional x and y pixel position of animation frame sequence */
1319 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1320 g->src_x = parameter[GFX_ARG_X];
1321 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1322 g->src_y = parameter[GFX_ARG_Y];
1328 Error(ERR_INFO_LINE, "-");
1329 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1330 g->width, getTokenFromImageID(graphic), TILEX);
1331 Error(ERR_INFO_LINE, "-");
1333 g->width = TILEX; /* will be checked to be inside bitmap later */
1338 Error(ERR_INFO_LINE, "-");
1339 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1340 g->height, getTokenFromImageID(graphic), TILEY);
1341 Error(ERR_INFO_LINE, "-");
1343 g->height = TILEY; /* will be checked to be inside bitmap later */
1349 /* get final bitmap size (with scaling, but without small images) */
1350 int src_image_width = get_scaled_graphic_width(graphic);
1351 int src_image_height = get_scaled_graphic_height(graphic);
1353 if (src_image_width == 0 || src_image_height == 0)
1355 /* only happens when loaded outside artwork system (like "global.busy") */
1356 src_image_width = src_bitmap->width;
1357 src_image_height = src_bitmap->height;
1360 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1362 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1363 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1367 anim_frames_per_row = MAX(1, src_image_width / g->width);
1368 anim_frames_per_col = MAX(1, src_image_height / g->height);
1371 g->src_image_width = src_image_width;
1372 g->src_image_height = src_image_height;
1375 /* correct x or y offset dependent of vertical or horizontal frame order */
1376 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1378 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1379 parameter[GFX_ARG_OFFSET] : g->height);
1380 anim_frames_per_line = anim_frames_per_col;
1382 else /* frames are ordered horizontally */
1384 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1385 parameter[GFX_ARG_OFFSET] : g->width);
1386 anim_frames_per_line = anim_frames_per_row;
1389 /* optionally, the x and y offset of frames can be specified directly */
1390 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1391 g->offset_x = parameter[GFX_ARG_XOFFSET];
1392 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1393 g->offset_y = parameter[GFX_ARG_YOFFSET];
1395 /* optionally, moving animations may have separate start and end graphics */
1396 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1398 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1399 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1401 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1402 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1403 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1404 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1405 else /* frames are ordered horizontally */
1406 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1407 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1409 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1410 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1411 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1412 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1413 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1415 /* optionally, the second movement tile can be specified as start tile */
1416 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1417 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1419 /* automatically determine correct number of frames, if not defined */
1420 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1421 g->anim_frames = parameter[GFX_ARG_FRAMES];
1422 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1423 g->anim_frames = anim_frames_per_row;
1424 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1425 g->anim_frames = anim_frames_per_col;
1429 if (g->anim_frames == 0) /* frames must be at least 1 */
1432 g->anim_frames_per_line =
1433 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1434 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1436 g->anim_delay = parameter[GFX_ARG_DELAY];
1437 if (g->anim_delay == 0) /* delay must be at least 1 */
1440 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1442 /* automatically determine correct start frame, if not defined */
1443 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1444 g->anim_start_frame = 0;
1445 else if (g->anim_mode & ANIM_REVERSE)
1446 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1448 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1450 /* animation synchronized with global frame counter, not move position */
1451 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1453 /* optional element for cloning crumble graphics */
1454 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1455 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1457 /* optional element for cloning digging graphics */
1458 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1459 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1461 /* optional border size for "crumbling" diggable graphics */
1462 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1463 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1465 /* used for global animations and player "boring" and "sleeping" actions */
1466 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1467 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1468 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1469 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1470 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1471 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1472 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1473 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1474 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1475 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1476 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1477 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1479 /* used for global animations */
1480 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1481 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1482 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1483 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1485 /* used for toon animations and global animations */
1486 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1487 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1488 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1489 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1490 g->direction = parameter[GFX_ARG_DIRECTION];
1491 g->position = parameter[GFX_ARG_POSITION];
1492 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1493 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1495 /* this is only used for drawing font characters */
1496 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1497 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1499 /* this is only used for drawing envelope graphics */
1500 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1502 /* used for toon animations and global animations */
1503 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1504 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1506 /* optional graphic for cloning all graphics settings */
1507 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1508 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1510 /* optional settings for drawing title screens and title messages */
1511 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1512 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1513 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1514 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1515 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1516 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1517 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1518 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1519 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1520 g->align = parameter[GFX_ARG_ALIGN];
1521 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1522 g->valign = parameter[GFX_ARG_VALIGN];
1523 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1524 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1526 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1527 g->class = parameter[GFX_ARG_CLASS];
1528 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1529 g->style = parameter[GFX_ARG_STYLE];
1531 /* this is only used for drawing menu buttons and text */
1532 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1533 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1534 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1535 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1538 static void set_graphic_parameters(int graphic)
1540 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1541 char **parameter_raw = image->parameter;
1542 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1543 int parameter[NUM_GFX_ARGS];
1546 /* if fallback to default artwork is done, also use the default parameters */
1547 if (image->fallback_to_default)
1548 parameter_raw = image->default_parameter;
1550 /* get integer values from string parameters */
1551 for (i = 0; i < NUM_GFX_ARGS; i++)
1552 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1553 image_config_suffix[i].token,
1554 image_config_suffix[i].type);
1556 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1558 UPDATE_BUSY_STATE();
1561 static void set_cloned_graphic_parameters(int graphic)
1563 int fallback_graphic = IMG_CHAR_EXCLAM;
1564 int max_num_images = getImageListSize();
1565 int clone_graphic = graphic_info[graphic].clone_from;
1566 int num_references_followed = 1;
1568 while (graphic_info[clone_graphic].clone_from != -1 &&
1569 num_references_followed < max_num_images)
1571 clone_graphic = graphic_info[clone_graphic].clone_from;
1573 num_references_followed++;
1576 if (num_references_followed >= max_num_images)
1578 Error(ERR_INFO_LINE, "-");
1579 Error(ERR_INFO, "warning: error found in config file:");
1580 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1581 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1582 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1583 Error(ERR_INFO, "custom graphic rejected for this element/action");
1585 if (graphic == fallback_graphic)
1586 Error(ERR_EXIT, "no fallback graphic available");
1588 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1589 Error(ERR_INFO_LINE, "-");
1591 graphic_info[graphic] = graphic_info[fallback_graphic];
1595 graphic_info[graphic] = graphic_info[clone_graphic];
1596 graphic_info[graphic].clone_from = clone_graphic;
1600 static void InitGraphicInfo()
1602 int fallback_graphic = IMG_CHAR_EXCLAM;
1603 int num_images = getImageListSize();
1606 /* use image size as default values for width and height for these images */
1607 static int full_size_graphics[] =
1610 IMG_GLOBAL_BORDER_MAIN,
1611 IMG_GLOBAL_BORDER_SCORES,
1612 IMG_GLOBAL_BORDER_EDITOR,
1613 IMG_GLOBAL_BORDER_PLAYING,
1616 IMG_BACKGROUND_ENVELOPE_1,
1617 IMG_BACKGROUND_ENVELOPE_2,
1618 IMG_BACKGROUND_ENVELOPE_3,
1619 IMG_BACKGROUND_ENVELOPE_4,
1620 IMG_BACKGROUND_REQUEST,
1623 IMG_BACKGROUND_TITLE_INITIAL,
1624 IMG_BACKGROUND_TITLE,
1625 IMG_BACKGROUND_MAIN,
1626 IMG_BACKGROUND_LEVELS,
1627 IMG_BACKGROUND_LEVELNR,
1628 IMG_BACKGROUND_SCORES,
1629 IMG_BACKGROUND_EDITOR,
1630 IMG_BACKGROUND_INFO,
1631 IMG_BACKGROUND_INFO_ELEMENTS,
1632 IMG_BACKGROUND_INFO_MUSIC,
1633 IMG_BACKGROUND_INFO_CREDITS,
1634 IMG_BACKGROUND_INFO_PROGRAM,
1635 IMG_BACKGROUND_INFO_VERSION,
1636 IMG_BACKGROUND_INFO_LEVELSET,
1637 IMG_BACKGROUND_SETUP,
1638 IMG_BACKGROUND_PLAYING,
1639 IMG_BACKGROUND_DOOR,
1640 IMG_BACKGROUND_TAPE,
1641 IMG_BACKGROUND_PANEL,
1642 IMG_BACKGROUND_PALETTE,
1643 IMG_BACKGROUND_TOOLBOX,
1645 IMG_TITLESCREEN_INITIAL_1,
1646 IMG_TITLESCREEN_INITIAL_2,
1647 IMG_TITLESCREEN_INITIAL_3,
1648 IMG_TITLESCREEN_INITIAL_4,
1649 IMG_TITLESCREEN_INITIAL_5,
1656 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1657 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1658 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1659 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1660 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1661 IMG_BACKGROUND_TITLEMESSAGE_1,
1662 IMG_BACKGROUND_TITLEMESSAGE_2,
1663 IMG_BACKGROUND_TITLEMESSAGE_3,
1664 IMG_BACKGROUND_TITLEMESSAGE_4,
1665 IMG_BACKGROUND_TITLEMESSAGE_5,
1670 checked_free(graphic_info);
1672 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1674 /* initialize "use_image_size" flag with default value */
1675 for (i = 0; i < num_images; i++)
1676 graphic_info[i].use_image_size = FALSE;
1678 /* initialize "use_image_size" flag from static configuration above */
1679 for (i = 0; full_size_graphics[i] != -1; i++)
1680 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1682 /* first set all graphic paramaters ... */
1683 for (i = 0; i < num_images; i++)
1684 set_graphic_parameters(i);
1686 /* ... then copy these parameters for cloned graphics */
1687 for (i = 0; i < num_images; i++)
1688 if (graphic_info[i].clone_from != -1)
1689 set_cloned_graphic_parameters(i);
1691 for (i = 0; i < num_images; i++)
1696 int first_frame, last_frame;
1697 int src_bitmap_width, src_bitmap_height;
1699 /* now check if no animation frames are outside of the loaded image */
1701 if (graphic_info[i].bitmap == NULL)
1702 continue; /* skip check for optional images that are undefined */
1704 /* get image size (this can differ from the standard element tile size!) */
1705 width = graphic_info[i].width;
1706 height = graphic_info[i].height;
1708 /* get final bitmap size (with scaling, but without small images) */
1709 src_bitmap_width = graphic_info[i].src_image_width;
1710 src_bitmap_height = graphic_info[i].src_image_height;
1712 /* check if first animation frame is inside specified bitmap */
1715 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1717 /* this avoids calculating wrong start position for out-of-bounds frame */
1718 src_x = graphic_info[i].src_x;
1719 src_y = graphic_info[i].src_y;
1721 if (program.headless)
1724 if (src_x < 0 || src_y < 0 ||
1725 src_x + width > src_bitmap_width ||
1726 src_y + height > src_bitmap_height)
1728 Error(ERR_INFO_LINE, "-");
1729 Error(ERR_INFO, "warning: error found in config file:");
1730 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1731 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1732 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1733 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1735 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1736 src_x, src_y, src_bitmap_width, src_bitmap_height);
1737 Error(ERR_INFO, "custom graphic rejected for this element/action");
1739 if (i == fallback_graphic)
1740 Error(ERR_EXIT, "no fallback graphic available");
1742 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1743 Error(ERR_INFO_LINE, "-");
1745 graphic_info[i] = graphic_info[fallback_graphic];
1748 /* check if last animation frame is inside specified bitmap */
1750 last_frame = graphic_info[i].anim_frames - 1;
1751 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1753 if (src_x < 0 || src_y < 0 ||
1754 src_x + width > src_bitmap_width ||
1755 src_y + height > src_bitmap_height)
1757 Error(ERR_INFO_LINE, "-");
1758 Error(ERR_INFO, "warning: error found in config file:");
1759 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1760 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1761 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1762 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1764 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1765 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1766 Error(ERR_INFO, "custom graphic rejected for this element/action");
1768 if (i == fallback_graphic)
1769 Error(ERR_EXIT, "no fallback graphic available");
1771 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1772 Error(ERR_INFO_LINE, "-");
1774 graphic_info[i] = graphic_info[fallback_graphic];
1779 static void InitGraphicCompatibilityInfo()
1781 struct FileInfo *fi_global_door =
1782 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1783 int num_images = getImageListSize();
1786 /* the following compatibility handling is needed for the following case:
1787 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1788 graphics mainly used for door and panel graphics, like editor, tape and
1789 in-game buttons with hard-coded bitmap positions and button sizes; as
1790 these graphics now have individual definitions, redefining "global.door"
1791 to change all these graphics at once like before does not work anymore
1792 (because all those individual definitions still have their default values);
1793 to solve this, remap all those individual definitions that are not
1794 redefined to the new bitmap of "global.door" if it was redefined */
1796 /* special compatibility handling if image "global.door" was redefined */
1797 if (fi_global_door->redefined)
1799 for (i = 0; i < num_images; i++)
1801 struct FileInfo *fi = getImageListEntryFromImageID(i);
1803 /* process only those images that still use the default settings */
1806 /* process all images which default to same image as "global.door" */
1807 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1809 // printf("::: special treatment needed for token '%s'\n", fi->token);
1811 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1812 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1818 InitGraphicCompatibilityInfo_Doors();
1821 static void InitElementSoundInfo()
1823 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1824 int num_property_mappings = getSoundListPropertyMappingSize();
1827 /* set values to -1 to identify later as "uninitialized" values */
1828 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1829 for (act = 0; act < NUM_ACTIONS; act++)
1830 element_info[i].sound[act] = -1;
1832 /* initialize element/sound mapping from static configuration */
1833 for (i = 0; element_to_sound[i].element > -1; i++)
1835 int element = element_to_sound[i].element;
1836 int action = element_to_sound[i].action;
1837 int sound = element_to_sound[i].sound;
1838 boolean is_class = element_to_sound[i].is_class;
1841 action = ACTION_DEFAULT;
1844 element_info[element].sound[action] = sound;
1846 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1847 if (strEqual(element_info[j].class_name,
1848 element_info[element].class_name))
1849 element_info[j].sound[action] = sound;
1852 /* initialize element class/sound mapping from dynamic configuration */
1853 for (i = 0; i < num_property_mappings; i++)
1855 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1856 int action = property_mapping[i].ext1_index;
1857 int sound = property_mapping[i].artwork_index;
1859 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1863 action = ACTION_DEFAULT;
1865 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1866 if (strEqual(element_info[j].class_name,
1867 element_info[element_class].class_name))
1868 element_info[j].sound[action] = sound;
1871 /* initialize element/sound mapping from dynamic configuration */
1872 for (i = 0; i < num_property_mappings; i++)
1874 int element = property_mapping[i].base_index;
1875 int action = property_mapping[i].ext1_index;
1876 int sound = property_mapping[i].artwork_index;
1878 if (element >= MAX_NUM_ELEMENTS)
1882 action = ACTION_DEFAULT;
1884 element_info[element].sound[action] = sound;
1887 /* now set all '-1' values to element specific default values */
1888 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1890 for (act = 0; act < NUM_ACTIONS; act++)
1892 /* generic default action sound (defined by "[default]" directive) */
1893 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1895 /* look for special default action sound (classic game specific) */
1896 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1897 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1898 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1899 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1900 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1901 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1903 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1904 /* !!! make this better !!! */
1905 if (i == EL_EMPTY_SPACE)
1906 default_action_sound = element_info[EL_DEFAULT].sound[act];
1908 /* no sound for this specific action -- use default action sound */
1909 if (element_info[i].sound[act] == -1)
1910 element_info[i].sound[act] = default_action_sound;
1914 /* copy sound settings to some elements that are only stored in level file
1915 in native R'n'D levels, but are used by game engine in native EM levels */
1916 for (i = 0; copy_properties[i][0] != -1; i++)
1917 for (j = 1; j <= 4; j++)
1918 for (act = 0; act < NUM_ACTIONS; act++)
1919 element_info[copy_properties[i][j]].sound[act] =
1920 element_info[copy_properties[i][0]].sound[act];
1923 static void InitGameModeSoundInfo()
1927 /* set values to -1 to identify later as "uninitialized" values */
1928 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1931 /* initialize gamemode/sound mapping from static configuration */
1932 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1934 int gamemode = gamemode_to_sound[i].gamemode;
1935 int sound = gamemode_to_sound[i].sound;
1938 gamemode = GAME_MODE_DEFAULT;
1940 menu.sound[gamemode] = sound;
1943 /* now set all '-1' values to levelset specific default values */
1944 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1945 if (menu.sound[i] == -1)
1946 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1949 static void set_sound_parameters(int sound, char **parameter_raw)
1951 int parameter[NUM_SND_ARGS];
1954 /* get integer values from string parameters */
1955 for (i = 0; i < NUM_SND_ARGS; i++)
1957 get_parameter_value(parameter_raw[i],
1958 sound_config_suffix[i].token,
1959 sound_config_suffix[i].type);
1961 /* explicit loop mode setting in configuration overrides default value */
1962 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1963 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1965 /* sound volume to change the original volume when loading the sound file */
1966 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1968 /* sound priority to give certain sounds a higher or lower priority */
1969 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1972 static void InitSoundInfo()
1974 int *sound_effect_properties;
1975 int num_sounds = getSoundListSize();
1978 checked_free(sound_info);
1980 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1981 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1983 /* initialize sound effect for all elements to "no sound" */
1984 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1985 for (j = 0; j < NUM_ACTIONS; j++)
1986 element_info[i].sound[j] = SND_UNDEFINED;
1988 for (i = 0; i < num_sounds; i++)
1990 struct FileInfo *sound = getSoundListEntry(i);
1991 int len_effect_text = strlen(sound->token);
1993 sound_effect_properties[i] = ACTION_OTHER;
1994 sound_info[i].loop = FALSE; /* default: play sound only once */
1996 /* determine all loop sounds and identify certain sound classes */
1998 for (j = 0; element_action_info[j].suffix; j++)
2000 int len_action_text = strlen(element_action_info[j].suffix);
2002 if (len_action_text < len_effect_text &&
2003 strEqual(&sound->token[len_effect_text - len_action_text],
2004 element_action_info[j].suffix))
2006 sound_effect_properties[i] = element_action_info[j].value;
2007 sound_info[i].loop = element_action_info[j].is_loop_sound;
2013 /* associate elements and some selected sound actions */
2015 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2017 if (element_info[j].class_name)
2019 int len_class_text = strlen(element_info[j].class_name);
2021 if (len_class_text + 1 < len_effect_text &&
2022 strncmp(sound->token,
2023 element_info[j].class_name, len_class_text) == 0 &&
2024 sound->token[len_class_text] == '.')
2026 int sound_action_value = sound_effect_properties[i];
2028 element_info[j].sound[sound_action_value] = i;
2033 set_sound_parameters(i, sound->parameter);
2036 free(sound_effect_properties);
2039 static void InitGameModeMusicInfo()
2041 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2042 int num_property_mappings = getMusicListPropertyMappingSize();
2043 int default_levelset_music = -1;
2046 /* set values to -1 to identify later as "uninitialized" values */
2047 for (i = 0; i < MAX_LEVELS; i++)
2048 levelset.music[i] = -1;
2049 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2052 /* initialize gamemode/music mapping from static configuration */
2053 for (i = 0; gamemode_to_music[i].music > -1; i++)
2055 int gamemode = gamemode_to_music[i].gamemode;
2056 int music = gamemode_to_music[i].music;
2059 gamemode = GAME_MODE_DEFAULT;
2061 menu.music[gamemode] = music;
2064 /* initialize gamemode/music mapping from dynamic configuration */
2065 for (i = 0; i < num_property_mappings; i++)
2067 int prefix = property_mapping[i].base_index;
2068 int gamemode = property_mapping[i].ext2_index;
2069 int level = property_mapping[i].ext3_index;
2070 int music = property_mapping[i].artwork_index;
2072 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2076 gamemode = GAME_MODE_DEFAULT;
2078 /* level specific music only allowed for in-game music */
2079 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2080 gamemode = GAME_MODE_PLAYING;
2085 default_levelset_music = music;
2088 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2089 levelset.music[level] = music;
2090 if (gamemode != GAME_MODE_PLAYING)
2091 menu.music[gamemode] = music;
2094 /* now set all '-1' values to menu specific default values */
2095 /* (undefined values of "levelset.music[]" might stay at "-1" to
2096 allow dynamic selection of music files from music directory!) */
2097 for (i = 0; i < MAX_LEVELS; i++)
2098 if (levelset.music[i] == -1)
2099 levelset.music[i] = default_levelset_music;
2100 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2101 if (menu.music[i] == -1)
2102 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2105 static void set_music_parameters(int music, char **parameter_raw)
2107 int parameter[NUM_MUS_ARGS];
2110 /* get integer values from string parameters */
2111 for (i = 0; i < NUM_MUS_ARGS; i++)
2113 get_parameter_value(parameter_raw[i],
2114 music_config_suffix[i].token,
2115 music_config_suffix[i].type);
2117 /* explicit loop mode setting in configuration overrides default value */
2118 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2119 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2122 static void InitMusicInfo()
2124 int num_music = getMusicListSize();
2127 checked_free(music_info);
2129 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2131 for (i = 0; i < num_music; i++)
2133 struct FileInfo *music = getMusicListEntry(i);
2134 int len_music_text = strlen(music->token);
2136 music_info[i].loop = TRUE; /* default: play music in loop mode */
2138 /* determine all loop music */
2140 for (j = 0; music_prefix_info[j].prefix; j++)
2142 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2144 if (len_prefix_text < len_music_text &&
2145 strncmp(music->token,
2146 music_prefix_info[j].prefix, len_prefix_text) == 0)
2148 music_info[i].loop = music_prefix_info[j].is_loop_music;
2154 set_music_parameters(i, music->parameter);
2158 static void ReinitializeGraphics()
2160 print_timestamp_init("ReinitializeGraphics");
2162 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2164 InitGraphicInfo(); /* graphic properties mapping */
2165 print_timestamp_time("InitGraphicInfo");
2166 InitElementGraphicInfo(); /* element game graphic mapping */
2167 print_timestamp_time("InitElementGraphicInfo");
2168 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2169 print_timestamp_time("InitElementSpecialGraphicInfo");
2171 InitElementSmallImages(); /* scale elements to all needed sizes */
2172 print_timestamp_time("InitElementSmallImages");
2173 InitScaledImages(); /* scale all other images, if needed */
2174 print_timestamp_time("InitScaledImages");
2175 InitBitmapPointers(); /* set standard size bitmap pointers */
2176 print_timestamp_time("InitBitmapPointers");
2177 InitFontGraphicInfo(); /* initialize text drawing functions */
2178 print_timestamp_time("InitFontGraphicInfo");
2179 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2180 print_timestamp_time("InitGlobalAnimGraphicInfo");
2182 InitImageTextures(); /* create textures for certain images */
2183 print_timestamp_time("InitImageTextures");
2185 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2186 print_timestamp_time("InitGraphicInfo_EM");
2188 InitGraphicCompatibilityInfo();
2189 print_timestamp_time("InitGraphicCompatibilityInfo");
2191 SetMainBackgroundImage(IMG_BACKGROUND);
2192 print_timestamp_time("SetMainBackgroundImage");
2193 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2194 print_timestamp_time("SetDoorBackgroundImage");
2197 print_timestamp_time("InitGadgets");
2199 print_timestamp_time("InitDoors");
2201 print_timestamp_done("ReinitializeGraphics");
2204 static void ReinitializeSounds()
2206 InitSoundInfo(); /* sound properties mapping */
2207 InitElementSoundInfo(); /* element game sound mapping */
2208 InitGameModeSoundInfo(); /* game mode sound mapping */
2209 InitGlobalAnimSoundInfo(); /* global animation sound settings */
2211 InitPlayLevelSound(); /* internal game sound settings */
2214 static void ReinitializeMusic()
2216 InitMusicInfo(); /* music properties mapping */
2217 InitGameModeMusicInfo(); /* game mode music mapping */
2218 InitGlobalAnimMusicInfo(); /* global animation music settings */
2221 static int get_special_property_bit(int element, int property_bit_nr)
2223 struct PropertyBitInfo
2229 static struct PropertyBitInfo pb_can_move_into_acid[] =
2231 /* the player may be able fall into acid when gravity is activated */
2236 { EL_SP_MURPHY, 0 },
2237 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2239 /* all elements that can move may be able to also move into acid */
2242 { EL_BUG_RIGHT, 1 },
2245 { EL_SPACESHIP, 2 },
2246 { EL_SPACESHIP_LEFT, 2 },
2247 { EL_SPACESHIP_RIGHT, 2 },
2248 { EL_SPACESHIP_UP, 2 },
2249 { EL_SPACESHIP_DOWN, 2 },
2250 { EL_BD_BUTTERFLY, 3 },
2251 { EL_BD_BUTTERFLY_LEFT, 3 },
2252 { EL_BD_BUTTERFLY_RIGHT, 3 },
2253 { EL_BD_BUTTERFLY_UP, 3 },
2254 { EL_BD_BUTTERFLY_DOWN, 3 },
2255 { EL_BD_FIREFLY, 4 },
2256 { EL_BD_FIREFLY_LEFT, 4 },
2257 { EL_BD_FIREFLY_RIGHT, 4 },
2258 { EL_BD_FIREFLY_UP, 4 },
2259 { EL_BD_FIREFLY_DOWN, 4 },
2261 { EL_YAMYAM_LEFT, 5 },
2262 { EL_YAMYAM_RIGHT, 5 },
2263 { EL_YAMYAM_UP, 5 },
2264 { EL_YAMYAM_DOWN, 5 },
2265 { EL_DARK_YAMYAM, 6 },
2268 { EL_PACMAN_LEFT, 8 },
2269 { EL_PACMAN_RIGHT, 8 },
2270 { EL_PACMAN_UP, 8 },
2271 { EL_PACMAN_DOWN, 8 },
2273 { EL_MOLE_LEFT, 9 },
2274 { EL_MOLE_RIGHT, 9 },
2276 { EL_MOLE_DOWN, 9 },
2280 { EL_SATELLITE, 13 },
2281 { EL_SP_SNIKSNAK, 14 },
2282 { EL_SP_ELECTRON, 15 },
2285 { EL_EMC_ANDROID, 18 },
2290 static struct PropertyBitInfo pb_dont_collide_with[] =
2292 { EL_SP_SNIKSNAK, 0 },
2293 { EL_SP_ELECTRON, 1 },
2301 struct PropertyBitInfo *pb_info;
2304 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2305 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2310 struct PropertyBitInfo *pb_info = NULL;
2313 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2314 if (pb_definition[i].bit_nr == property_bit_nr)
2315 pb_info = pb_definition[i].pb_info;
2317 if (pb_info == NULL)
2320 for (i = 0; pb_info[i].element != -1; i++)
2321 if (pb_info[i].element == element)
2322 return pb_info[i].bit_nr;
2327 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2328 boolean property_value)
2330 int bit_nr = get_special_property_bit(element, property_bit_nr);
2335 *bitfield |= (1 << bit_nr);
2337 *bitfield &= ~(1 << bit_nr);
2341 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2343 int bit_nr = get_special_property_bit(element, property_bit_nr);
2346 return ((*bitfield & (1 << bit_nr)) != 0);
2351 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2353 static int group_nr;
2354 static struct ElementGroupInfo *group;
2355 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2358 if (actual_group == NULL) /* not yet initialized */
2361 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2363 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2364 group_element - EL_GROUP_START + 1);
2366 /* replace element which caused too deep recursion by question mark */
2367 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2372 if (recursion_depth == 0) /* initialization */
2374 group = actual_group;
2375 group_nr = GROUP_NR(group_element);
2377 group->num_elements_resolved = 0;
2378 group->choice_pos = 0;
2380 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2381 element_info[i].in_group[group_nr] = FALSE;
2384 for (i = 0; i < actual_group->num_elements; i++)
2386 int element = actual_group->element[i];
2388 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2391 if (IS_GROUP_ELEMENT(element))
2392 ResolveGroupElementExt(element, recursion_depth + 1);
2395 group->element_resolved[group->num_elements_resolved++] = element;
2396 element_info[element].in_group[group_nr] = TRUE;
2401 void ResolveGroupElement(int group_element)
2403 ResolveGroupElementExt(group_element, 0);
2406 void InitElementPropertiesStatic()
2408 static boolean clipboard_elements_initialized = FALSE;
2410 static int ep_diggable[] =
2415 EL_SP_BUGGY_BASE_ACTIVATING,
2418 EL_INVISIBLE_SAND_ACTIVE,
2421 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2422 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2427 EL_SP_BUGGY_BASE_ACTIVE,
2434 static int ep_collectible_only[] =
2456 EL_DYNABOMB_INCREASE_NUMBER,
2457 EL_DYNABOMB_INCREASE_SIZE,
2458 EL_DYNABOMB_INCREASE_POWER,
2476 /* !!! handle separately !!! */
2477 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2483 static int ep_dont_run_into[] =
2485 /* same elements as in 'ep_dont_touch' */
2491 /* same elements as in 'ep_dont_collide_with' */
2503 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2508 EL_SP_BUGGY_BASE_ACTIVE,
2515 static int ep_dont_collide_with[] =
2517 /* same elements as in 'ep_dont_touch' */
2534 static int ep_dont_touch[] =
2544 static int ep_indestructible[] =
2548 EL_ACID_POOL_TOPLEFT,
2549 EL_ACID_POOL_TOPRIGHT,
2550 EL_ACID_POOL_BOTTOMLEFT,
2551 EL_ACID_POOL_BOTTOM,
2552 EL_ACID_POOL_BOTTOMRIGHT,
2553 EL_SP_HARDWARE_GRAY,
2554 EL_SP_HARDWARE_GREEN,
2555 EL_SP_HARDWARE_BLUE,
2557 EL_SP_HARDWARE_YELLOW,
2558 EL_SP_HARDWARE_BASE_1,
2559 EL_SP_HARDWARE_BASE_2,
2560 EL_SP_HARDWARE_BASE_3,
2561 EL_SP_HARDWARE_BASE_4,
2562 EL_SP_HARDWARE_BASE_5,
2563 EL_SP_HARDWARE_BASE_6,
2564 EL_INVISIBLE_STEELWALL,
2565 EL_INVISIBLE_STEELWALL_ACTIVE,
2566 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2567 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2568 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2569 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2570 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2571 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2572 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2573 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2574 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2575 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2576 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2577 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2579 EL_LIGHT_SWITCH_ACTIVE,
2580 EL_SIGN_EXCLAMATION,
2581 EL_SIGN_RADIOACTIVITY,
2588 EL_SIGN_ENTRY_FORBIDDEN,
2589 EL_SIGN_EMERGENCY_EXIT,
2597 EL_STEEL_EXIT_CLOSED,
2599 EL_STEEL_EXIT_OPENING,
2600 EL_STEEL_EXIT_CLOSING,
2601 EL_EM_STEEL_EXIT_CLOSED,
2602 EL_EM_STEEL_EXIT_OPEN,
2603 EL_EM_STEEL_EXIT_OPENING,
2604 EL_EM_STEEL_EXIT_CLOSING,
2605 EL_DC_STEELWALL_1_LEFT,
2606 EL_DC_STEELWALL_1_RIGHT,
2607 EL_DC_STEELWALL_1_TOP,
2608 EL_DC_STEELWALL_1_BOTTOM,
2609 EL_DC_STEELWALL_1_HORIZONTAL,
2610 EL_DC_STEELWALL_1_VERTICAL,
2611 EL_DC_STEELWALL_1_TOPLEFT,
2612 EL_DC_STEELWALL_1_TOPRIGHT,
2613 EL_DC_STEELWALL_1_BOTTOMLEFT,
2614 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2615 EL_DC_STEELWALL_1_TOPLEFT_2,
2616 EL_DC_STEELWALL_1_TOPRIGHT_2,
2617 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2618 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2619 EL_DC_STEELWALL_2_LEFT,
2620 EL_DC_STEELWALL_2_RIGHT,
2621 EL_DC_STEELWALL_2_TOP,
2622 EL_DC_STEELWALL_2_BOTTOM,
2623 EL_DC_STEELWALL_2_HORIZONTAL,
2624 EL_DC_STEELWALL_2_VERTICAL,
2625 EL_DC_STEELWALL_2_MIDDLE,
2626 EL_DC_STEELWALL_2_SINGLE,
2627 EL_STEELWALL_SLIPPERY,
2641 EL_GATE_1_GRAY_ACTIVE,
2642 EL_GATE_2_GRAY_ACTIVE,
2643 EL_GATE_3_GRAY_ACTIVE,
2644 EL_GATE_4_GRAY_ACTIVE,
2653 EL_EM_GATE_1_GRAY_ACTIVE,
2654 EL_EM_GATE_2_GRAY_ACTIVE,
2655 EL_EM_GATE_3_GRAY_ACTIVE,
2656 EL_EM_GATE_4_GRAY_ACTIVE,
2665 EL_EMC_GATE_5_GRAY_ACTIVE,
2666 EL_EMC_GATE_6_GRAY_ACTIVE,
2667 EL_EMC_GATE_7_GRAY_ACTIVE,
2668 EL_EMC_GATE_8_GRAY_ACTIVE,
2670 EL_DC_GATE_WHITE_GRAY,
2671 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2672 EL_DC_GATE_FAKE_GRAY,
2674 EL_SWITCHGATE_OPENING,
2675 EL_SWITCHGATE_CLOSED,
2676 EL_SWITCHGATE_CLOSING,
2677 EL_DC_SWITCHGATE_SWITCH_UP,
2678 EL_DC_SWITCHGATE_SWITCH_DOWN,
2680 EL_TIMEGATE_OPENING,
2682 EL_TIMEGATE_CLOSING,
2683 EL_DC_TIMEGATE_SWITCH,
2684 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2688 EL_TUBE_VERTICAL_LEFT,
2689 EL_TUBE_VERTICAL_RIGHT,
2690 EL_TUBE_HORIZONTAL_UP,
2691 EL_TUBE_HORIZONTAL_DOWN,
2696 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2697 EL_EXPANDABLE_STEELWALL_VERTICAL,
2698 EL_EXPANDABLE_STEELWALL_ANY,
2703 static int ep_slippery[] =
2717 EL_ROBOT_WHEEL_ACTIVE,
2723 EL_ACID_POOL_TOPLEFT,
2724 EL_ACID_POOL_TOPRIGHT,
2734 EL_STEELWALL_SLIPPERY,
2737 EL_EMC_WALL_SLIPPERY_1,
2738 EL_EMC_WALL_SLIPPERY_2,
2739 EL_EMC_WALL_SLIPPERY_3,
2740 EL_EMC_WALL_SLIPPERY_4,
2742 EL_EMC_MAGIC_BALL_ACTIVE,
2747 static int ep_can_change[] =
2752 static int ep_can_move[] =
2754 /* same elements as in 'pb_can_move_into_acid' */
2777 static int ep_can_fall[] =
2791 EL_QUICKSAND_FAST_FULL,
2793 EL_BD_MAGIC_WALL_FULL,
2794 EL_DC_MAGIC_WALL_FULL,
2808 static int ep_can_smash_player[] =
2834 static int ep_can_smash_enemies[] =
2843 static int ep_can_smash_everything[] =
2852 static int ep_explodes_by_fire[] =
2854 /* same elements as in 'ep_explodes_impact' */
2859 /* same elements as in 'ep_explodes_smashed' */
2869 EL_EM_DYNAMITE_ACTIVE,
2870 EL_DYNABOMB_PLAYER_1_ACTIVE,
2871 EL_DYNABOMB_PLAYER_2_ACTIVE,
2872 EL_DYNABOMB_PLAYER_3_ACTIVE,
2873 EL_DYNABOMB_PLAYER_4_ACTIVE,
2874 EL_DYNABOMB_INCREASE_NUMBER,
2875 EL_DYNABOMB_INCREASE_SIZE,
2876 EL_DYNABOMB_INCREASE_POWER,
2877 EL_SP_DISK_RED_ACTIVE,
2891 static int ep_explodes_smashed[] =
2893 /* same elements as in 'ep_explodes_impact' */
2907 static int ep_explodes_impact[] =
2916 static int ep_walkable_over[] =
2920 EL_SOKOBAN_FIELD_EMPTY,
2927 EL_EM_STEEL_EXIT_OPEN,
2928 EL_EM_STEEL_EXIT_OPENING,
2937 EL_GATE_1_GRAY_ACTIVE,
2938 EL_GATE_2_GRAY_ACTIVE,
2939 EL_GATE_3_GRAY_ACTIVE,
2940 EL_GATE_4_GRAY_ACTIVE,
2948 static int ep_walkable_inside[] =
2953 EL_TUBE_VERTICAL_LEFT,
2954 EL_TUBE_VERTICAL_RIGHT,
2955 EL_TUBE_HORIZONTAL_UP,
2956 EL_TUBE_HORIZONTAL_DOWN,
2965 static int ep_walkable_under[] =
2970 static int ep_passable_over[] =
2980 EL_EM_GATE_1_GRAY_ACTIVE,
2981 EL_EM_GATE_2_GRAY_ACTIVE,
2982 EL_EM_GATE_3_GRAY_ACTIVE,
2983 EL_EM_GATE_4_GRAY_ACTIVE,
2992 EL_EMC_GATE_5_GRAY_ACTIVE,
2993 EL_EMC_GATE_6_GRAY_ACTIVE,
2994 EL_EMC_GATE_7_GRAY_ACTIVE,
2995 EL_EMC_GATE_8_GRAY_ACTIVE,
2997 EL_DC_GATE_WHITE_GRAY,
2998 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3005 static int ep_passable_inside[] =
3011 EL_SP_PORT_HORIZONTAL,
3012 EL_SP_PORT_VERTICAL,
3014 EL_SP_GRAVITY_PORT_LEFT,
3015 EL_SP_GRAVITY_PORT_RIGHT,
3016 EL_SP_GRAVITY_PORT_UP,
3017 EL_SP_GRAVITY_PORT_DOWN,
3018 EL_SP_GRAVITY_ON_PORT_LEFT,
3019 EL_SP_GRAVITY_ON_PORT_RIGHT,
3020 EL_SP_GRAVITY_ON_PORT_UP,
3021 EL_SP_GRAVITY_ON_PORT_DOWN,
3022 EL_SP_GRAVITY_OFF_PORT_LEFT,
3023 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3024 EL_SP_GRAVITY_OFF_PORT_UP,
3025 EL_SP_GRAVITY_OFF_PORT_DOWN,
3030 static int ep_passable_under[] =
3035 static int ep_droppable[] =
3040 static int ep_explodes_1x1_old[] =
3045 static int ep_pushable[] =
3057 EL_SOKOBAN_FIELD_FULL,
3066 static int ep_explodes_cross_old[] =
3071 static int ep_protected[] =
3073 /* same elements as in 'ep_walkable_inside' */
3077 EL_TUBE_VERTICAL_LEFT,
3078 EL_TUBE_VERTICAL_RIGHT,
3079 EL_TUBE_HORIZONTAL_UP,
3080 EL_TUBE_HORIZONTAL_DOWN,
3086 /* same elements as in 'ep_passable_over' */
3095 EL_EM_GATE_1_GRAY_ACTIVE,
3096 EL_EM_GATE_2_GRAY_ACTIVE,
3097 EL_EM_GATE_3_GRAY_ACTIVE,
3098 EL_EM_GATE_4_GRAY_ACTIVE,
3107 EL_EMC_GATE_5_GRAY_ACTIVE,
3108 EL_EMC_GATE_6_GRAY_ACTIVE,
3109 EL_EMC_GATE_7_GRAY_ACTIVE,
3110 EL_EMC_GATE_8_GRAY_ACTIVE,
3112 EL_DC_GATE_WHITE_GRAY,
3113 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3117 /* same elements as in 'ep_passable_inside' */
3122 EL_SP_PORT_HORIZONTAL,
3123 EL_SP_PORT_VERTICAL,
3125 EL_SP_GRAVITY_PORT_LEFT,
3126 EL_SP_GRAVITY_PORT_RIGHT,
3127 EL_SP_GRAVITY_PORT_UP,
3128 EL_SP_GRAVITY_PORT_DOWN,
3129 EL_SP_GRAVITY_ON_PORT_LEFT,
3130 EL_SP_GRAVITY_ON_PORT_RIGHT,
3131 EL_SP_GRAVITY_ON_PORT_UP,
3132 EL_SP_GRAVITY_ON_PORT_DOWN,
3133 EL_SP_GRAVITY_OFF_PORT_LEFT,
3134 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3135 EL_SP_GRAVITY_OFF_PORT_UP,
3136 EL_SP_GRAVITY_OFF_PORT_DOWN,
3141 static int ep_throwable[] =
3146 static int ep_can_explode[] =
3148 /* same elements as in 'ep_explodes_impact' */
3153 /* same elements as in 'ep_explodes_smashed' */
3159 /* elements that can explode by explosion or by dragonfire */
3163 EL_EM_DYNAMITE_ACTIVE,
3164 EL_DYNABOMB_PLAYER_1_ACTIVE,
3165 EL_DYNABOMB_PLAYER_2_ACTIVE,
3166 EL_DYNABOMB_PLAYER_3_ACTIVE,
3167 EL_DYNABOMB_PLAYER_4_ACTIVE,
3168 EL_DYNABOMB_INCREASE_NUMBER,
3169 EL_DYNABOMB_INCREASE_SIZE,
3170 EL_DYNABOMB_INCREASE_POWER,
3171 EL_SP_DISK_RED_ACTIVE,
3179 /* elements that can explode only by explosion */
3185 static int ep_gravity_reachable[] =
3191 EL_INVISIBLE_SAND_ACTIVE,
3196 EL_SP_PORT_HORIZONTAL,
3197 EL_SP_PORT_VERTICAL,
3199 EL_SP_GRAVITY_PORT_LEFT,
3200 EL_SP_GRAVITY_PORT_RIGHT,
3201 EL_SP_GRAVITY_PORT_UP,
3202 EL_SP_GRAVITY_PORT_DOWN,
3203 EL_SP_GRAVITY_ON_PORT_LEFT,
3204 EL_SP_GRAVITY_ON_PORT_RIGHT,
3205 EL_SP_GRAVITY_ON_PORT_UP,
3206 EL_SP_GRAVITY_ON_PORT_DOWN,
3207 EL_SP_GRAVITY_OFF_PORT_LEFT,
3208 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3209 EL_SP_GRAVITY_OFF_PORT_UP,
3210 EL_SP_GRAVITY_OFF_PORT_DOWN,
3216 static int ep_player[] =
3223 EL_SOKOBAN_FIELD_PLAYER,
3229 static int ep_can_pass_magic_wall[] =
3243 static int ep_can_pass_dc_magic_wall[] =
3259 static int ep_switchable[] =
3263 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3264 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3265 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3266 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3267 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3268 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3269 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3270 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3271 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3272 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3273 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3274 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3275 EL_SWITCHGATE_SWITCH_UP,
3276 EL_SWITCHGATE_SWITCH_DOWN,
3277 EL_DC_SWITCHGATE_SWITCH_UP,
3278 EL_DC_SWITCHGATE_SWITCH_DOWN,
3280 EL_LIGHT_SWITCH_ACTIVE,
3282 EL_DC_TIMEGATE_SWITCH,
3283 EL_BALLOON_SWITCH_LEFT,
3284 EL_BALLOON_SWITCH_RIGHT,
3285 EL_BALLOON_SWITCH_UP,
3286 EL_BALLOON_SWITCH_DOWN,
3287 EL_BALLOON_SWITCH_ANY,
3288 EL_BALLOON_SWITCH_NONE,
3291 EL_EMC_MAGIC_BALL_SWITCH,
3292 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3297 static int ep_bd_element[] =
3331 static int ep_sp_element[] =
3333 /* should always be valid */
3336 /* standard classic Supaplex elements */
3343 EL_SP_HARDWARE_GRAY,
3351 EL_SP_GRAVITY_PORT_RIGHT,
3352 EL_SP_GRAVITY_PORT_DOWN,
3353 EL_SP_GRAVITY_PORT_LEFT,
3354 EL_SP_GRAVITY_PORT_UP,
3359 EL_SP_PORT_VERTICAL,
3360 EL_SP_PORT_HORIZONTAL,
3366 EL_SP_HARDWARE_BASE_1,
3367 EL_SP_HARDWARE_GREEN,
3368 EL_SP_HARDWARE_BLUE,
3370 EL_SP_HARDWARE_YELLOW,
3371 EL_SP_HARDWARE_BASE_2,
3372 EL_SP_HARDWARE_BASE_3,
3373 EL_SP_HARDWARE_BASE_4,
3374 EL_SP_HARDWARE_BASE_5,
3375 EL_SP_HARDWARE_BASE_6,
3379 /* additional elements that appeared in newer Supaplex levels */
3382 /* additional gravity port elements (not switching, but setting gravity) */
3383 EL_SP_GRAVITY_ON_PORT_LEFT,
3384 EL_SP_GRAVITY_ON_PORT_RIGHT,
3385 EL_SP_GRAVITY_ON_PORT_UP,
3386 EL_SP_GRAVITY_ON_PORT_DOWN,
3387 EL_SP_GRAVITY_OFF_PORT_LEFT,
3388 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3389 EL_SP_GRAVITY_OFF_PORT_UP,
3390 EL_SP_GRAVITY_OFF_PORT_DOWN,
3392 /* more than one Murphy in a level results in an inactive clone */
3395 /* runtime Supaplex elements */
3396 EL_SP_DISK_RED_ACTIVE,
3397 EL_SP_TERMINAL_ACTIVE,
3398 EL_SP_BUGGY_BASE_ACTIVATING,
3399 EL_SP_BUGGY_BASE_ACTIVE,
3406 static int ep_sb_element[] =
3411 EL_SOKOBAN_FIELD_EMPTY,
3412 EL_SOKOBAN_FIELD_FULL,
3413 EL_SOKOBAN_FIELD_PLAYER,
3418 EL_INVISIBLE_STEELWALL,
3423 static int ep_gem[] =
3435 static int ep_food_dark_yamyam[] =
3463 static int ep_food_penguin[] =
3477 static int ep_food_pig[] =
3489 static int ep_historic_wall[] =
3500 EL_GATE_1_GRAY_ACTIVE,
3501 EL_GATE_2_GRAY_ACTIVE,
3502 EL_GATE_3_GRAY_ACTIVE,
3503 EL_GATE_4_GRAY_ACTIVE,
3512 EL_EM_GATE_1_GRAY_ACTIVE,
3513 EL_EM_GATE_2_GRAY_ACTIVE,
3514 EL_EM_GATE_3_GRAY_ACTIVE,
3515 EL_EM_GATE_4_GRAY_ACTIVE,
3522 EL_EXPANDABLE_WALL_HORIZONTAL,
3523 EL_EXPANDABLE_WALL_VERTICAL,
3524 EL_EXPANDABLE_WALL_ANY,
3525 EL_EXPANDABLE_WALL_GROWING,
3526 EL_BD_EXPANDABLE_WALL,
3533 EL_SP_HARDWARE_GRAY,
3534 EL_SP_HARDWARE_GREEN,
3535 EL_SP_HARDWARE_BLUE,
3537 EL_SP_HARDWARE_YELLOW,
3538 EL_SP_HARDWARE_BASE_1,
3539 EL_SP_HARDWARE_BASE_2,
3540 EL_SP_HARDWARE_BASE_3,
3541 EL_SP_HARDWARE_BASE_4,
3542 EL_SP_HARDWARE_BASE_5,
3543 EL_SP_HARDWARE_BASE_6,
3545 EL_SP_TERMINAL_ACTIVE,
3548 EL_INVISIBLE_STEELWALL,
3549 EL_INVISIBLE_STEELWALL_ACTIVE,
3551 EL_INVISIBLE_WALL_ACTIVE,
3552 EL_STEELWALL_SLIPPERY,
3569 static int ep_historic_solid[] =
3573 EL_EXPANDABLE_WALL_HORIZONTAL,
3574 EL_EXPANDABLE_WALL_VERTICAL,
3575 EL_EXPANDABLE_WALL_ANY,
3576 EL_BD_EXPANDABLE_WALL,
3589 EL_QUICKSAND_FILLING,
3590 EL_QUICKSAND_EMPTYING,
3592 EL_MAGIC_WALL_ACTIVE,
3593 EL_MAGIC_WALL_EMPTYING,
3594 EL_MAGIC_WALL_FILLING,
3598 EL_BD_MAGIC_WALL_ACTIVE,
3599 EL_BD_MAGIC_WALL_EMPTYING,
3600 EL_BD_MAGIC_WALL_FULL,
3601 EL_BD_MAGIC_WALL_FILLING,
3602 EL_BD_MAGIC_WALL_DEAD,
3611 EL_SP_TERMINAL_ACTIVE,
3615 EL_INVISIBLE_WALL_ACTIVE,
3616 EL_SWITCHGATE_SWITCH_UP,
3617 EL_SWITCHGATE_SWITCH_DOWN,
3618 EL_DC_SWITCHGATE_SWITCH_UP,
3619 EL_DC_SWITCHGATE_SWITCH_DOWN,
3621 EL_TIMEGATE_SWITCH_ACTIVE,
3622 EL_DC_TIMEGATE_SWITCH,
3623 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3635 /* the following elements are a direct copy of "indestructible" elements,
3636 except "EL_ACID", which is "indestructible", but not "solid"! */
3641 EL_ACID_POOL_TOPLEFT,
3642 EL_ACID_POOL_TOPRIGHT,
3643 EL_ACID_POOL_BOTTOMLEFT,
3644 EL_ACID_POOL_BOTTOM,
3645 EL_ACID_POOL_BOTTOMRIGHT,
3646 EL_SP_HARDWARE_GRAY,
3647 EL_SP_HARDWARE_GREEN,
3648 EL_SP_HARDWARE_BLUE,
3650 EL_SP_HARDWARE_YELLOW,
3651 EL_SP_HARDWARE_BASE_1,
3652 EL_SP_HARDWARE_BASE_2,
3653 EL_SP_HARDWARE_BASE_3,
3654 EL_SP_HARDWARE_BASE_4,
3655 EL_SP_HARDWARE_BASE_5,
3656 EL_SP_HARDWARE_BASE_6,
3657 EL_INVISIBLE_STEELWALL,
3658 EL_INVISIBLE_STEELWALL_ACTIVE,
3659 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3660 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3661 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3662 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3663 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3664 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3665 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3666 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3667 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3668 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3669 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3670 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3672 EL_LIGHT_SWITCH_ACTIVE,
3673 EL_SIGN_EXCLAMATION,
3674 EL_SIGN_RADIOACTIVITY,
3681 EL_SIGN_ENTRY_FORBIDDEN,
3682 EL_SIGN_EMERGENCY_EXIT,
3690 EL_STEEL_EXIT_CLOSED,
3692 EL_DC_STEELWALL_1_LEFT,
3693 EL_DC_STEELWALL_1_RIGHT,
3694 EL_DC_STEELWALL_1_TOP,
3695 EL_DC_STEELWALL_1_BOTTOM,
3696 EL_DC_STEELWALL_1_HORIZONTAL,
3697 EL_DC_STEELWALL_1_VERTICAL,
3698 EL_DC_STEELWALL_1_TOPLEFT,
3699 EL_DC_STEELWALL_1_TOPRIGHT,
3700 EL_DC_STEELWALL_1_BOTTOMLEFT,
3701 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3702 EL_DC_STEELWALL_1_TOPLEFT_2,
3703 EL_DC_STEELWALL_1_TOPRIGHT_2,
3704 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3705 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3706 EL_DC_STEELWALL_2_LEFT,
3707 EL_DC_STEELWALL_2_RIGHT,
3708 EL_DC_STEELWALL_2_TOP,
3709 EL_DC_STEELWALL_2_BOTTOM,
3710 EL_DC_STEELWALL_2_HORIZONTAL,
3711 EL_DC_STEELWALL_2_VERTICAL,
3712 EL_DC_STEELWALL_2_MIDDLE,
3713 EL_DC_STEELWALL_2_SINGLE,
3714 EL_STEELWALL_SLIPPERY,
3728 EL_GATE_1_GRAY_ACTIVE,
3729 EL_GATE_2_GRAY_ACTIVE,
3730 EL_GATE_3_GRAY_ACTIVE,
3731 EL_GATE_4_GRAY_ACTIVE,
3740 EL_EM_GATE_1_GRAY_ACTIVE,
3741 EL_EM_GATE_2_GRAY_ACTIVE,
3742 EL_EM_GATE_3_GRAY_ACTIVE,
3743 EL_EM_GATE_4_GRAY_ACTIVE,
3745 EL_SWITCHGATE_OPENING,
3746 EL_SWITCHGATE_CLOSED,
3747 EL_SWITCHGATE_CLOSING,
3749 EL_TIMEGATE_OPENING,
3751 EL_TIMEGATE_CLOSING,
3755 EL_TUBE_VERTICAL_LEFT,
3756 EL_TUBE_VERTICAL_RIGHT,
3757 EL_TUBE_HORIZONTAL_UP,
3758 EL_TUBE_HORIZONTAL_DOWN,
3767 static int ep_classic_enemy[] =
3784 static int ep_belt[] =
3786 EL_CONVEYOR_BELT_1_LEFT,
3787 EL_CONVEYOR_BELT_1_MIDDLE,
3788 EL_CONVEYOR_BELT_1_RIGHT,
3789 EL_CONVEYOR_BELT_2_LEFT,
3790 EL_CONVEYOR_BELT_2_MIDDLE,
3791 EL_CONVEYOR_BELT_2_RIGHT,
3792 EL_CONVEYOR_BELT_3_LEFT,
3793 EL_CONVEYOR_BELT_3_MIDDLE,
3794 EL_CONVEYOR_BELT_3_RIGHT,
3795 EL_CONVEYOR_BELT_4_LEFT,
3796 EL_CONVEYOR_BELT_4_MIDDLE,
3797 EL_CONVEYOR_BELT_4_RIGHT,
3802 static int ep_belt_active[] =
3804 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3805 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3806 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3807 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3808 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3809 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3810 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3811 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3812 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3813 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3814 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3815 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3820 static int ep_belt_switch[] =
3822 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3823 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3824 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3825 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3826 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3827 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3828 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3829 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3830 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3831 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3832 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3833 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3838 static int ep_tube[] =
3845 EL_TUBE_HORIZONTAL_UP,
3846 EL_TUBE_HORIZONTAL_DOWN,
3848 EL_TUBE_VERTICAL_LEFT,
3849 EL_TUBE_VERTICAL_RIGHT,
3855 static int ep_acid_pool[] =
3857 EL_ACID_POOL_TOPLEFT,
3858 EL_ACID_POOL_TOPRIGHT,
3859 EL_ACID_POOL_BOTTOMLEFT,
3860 EL_ACID_POOL_BOTTOM,
3861 EL_ACID_POOL_BOTTOMRIGHT,
3866 static int ep_keygate[] =
3876 EL_GATE_1_GRAY_ACTIVE,
3877 EL_GATE_2_GRAY_ACTIVE,
3878 EL_GATE_3_GRAY_ACTIVE,
3879 EL_GATE_4_GRAY_ACTIVE,
3888 EL_EM_GATE_1_GRAY_ACTIVE,
3889 EL_EM_GATE_2_GRAY_ACTIVE,
3890 EL_EM_GATE_3_GRAY_ACTIVE,
3891 EL_EM_GATE_4_GRAY_ACTIVE,
3900 EL_EMC_GATE_5_GRAY_ACTIVE,
3901 EL_EMC_GATE_6_GRAY_ACTIVE,
3902 EL_EMC_GATE_7_GRAY_ACTIVE,
3903 EL_EMC_GATE_8_GRAY_ACTIVE,
3905 EL_DC_GATE_WHITE_GRAY,
3906 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3911 static int ep_amoeboid[] =
3923 static int ep_amoebalive[] =
3934 static int ep_has_editor_content[] =
3940 EL_SOKOBAN_FIELD_PLAYER,
3957 static int ep_can_turn_each_move[] =
3959 /* !!! do something with this one !!! */
3963 static int ep_can_grow[] =
3977 static int ep_active_bomb[] =
3980 EL_EM_DYNAMITE_ACTIVE,
3981 EL_DYNABOMB_PLAYER_1_ACTIVE,
3982 EL_DYNABOMB_PLAYER_2_ACTIVE,
3983 EL_DYNABOMB_PLAYER_3_ACTIVE,
3984 EL_DYNABOMB_PLAYER_4_ACTIVE,
3985 EL_SP_DISK_RED_ACTIVE,
3990 static int ep_inactive[] =
4000 EL_QUICKSAND_FAST_EMPTY,
4023 EL_GATE_1_GRAY_ACTIVE,
4024 EL_GATE_2_GRAY_ACTIVE,
4025 EL_GATE_3_GRAY_ACTIVE,
4026 EL_GATE_4_GRAY_ACTIVE,
4035 EL_EM_GATE_1_GRAY_ACTIVE,
4036 EL_EM_GATE_2_GRAY_ACTIVE,
4037 EL_EM_GATE_3_GRAY_ACTIVE,
4038 EL_EM_GATE_4_GRAY_ACTIVE,
4047 EL_EMC_GATE_5_GRAY_ACTIVE,
4048 EL_EMC_GATE_6_GRAY_ACTIVE,
4049 EL_EMC_GATE_7_GRAY_ACTIVE,
4050 EL_EMC_GATE_8_GRAY_ACTIVE,
4052 EL_DC_GATE_WHITE_GRAY,
4053 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4054 EL_DC_GATE_FAKE_GRAY,
4057 EL_INVISIBLE_STEELWALL,
4065 EL_WALL_EMERALD_YELLOW,
4066 EL_DYNABOMB_INCREASE_NUMBER,
4067 EL_DYNABOMB_INCREASE_SIZE,
4068 EL_DYNABOMB_INCREASE_POWER,
4072 EL_SOKOBAN_FIELD_EMPTY,
4073 EL_SOKOBAN_FIELD_FULL,
4074 EL_WALL_EMERALD_RED,
4075 EL_WALL_EMERALD_PURPLE,
4076 EL_ACID_POOL_TOPLEFT,
4077 EL_ACID_POOL_TOPRIGHT,
4078 EL_ACID_POOL_BOTTOMLEFT,
4079 EL_ACID_POOL_BOTTOM,
4080 EL_ACID_POOL_BOTTOMRIGHT,
4084 EL_BD_MAGIC_WALL_DEAD,
4086 EL_DC_MAGIC_WALL_DEAD,
4087 EL_AMOEBA_TO_DIAMOND,
4095 EL_SP_GRAVITY_PORT_RIGHT,
4096 EL_SP_GRAVITY_PORT_DOWN,
4097 EL_SP_GRAVITY_PORT_LEFT,
4098 EL_SP_GRAVITY_PORT_UP,
4099 EL_SP_PORT_HORIZONTAL,
4100 EL_SP_PORT_VERTICAL,
4111 EL_SP_HARDWARE_GRAY,
4112 EL_SP_HARDWARE_GREEN,
4113 EL_SP_HARDWARE_BLUE,
4115 EL_SP_HARDWARE_YELLOW,
4116 EL_SP_HARDWARE_BASE_1,
4117 EL_SP_HARDWARE_BASE_2,
4118 EL_SP_HARDWARE_BASE_3,
4119 EL_SP_HARDWARE_BASE_4,
4120 EL_SP_HARDWARE_BASE_5,
4121 EL_SP_HARDWARE_BASE_6,
4122 EL_SP_GRAVITY_ON_PORT_LEFT,
4123 EL_SP_GRAVITY_ON_PORT_RIGHT,
4124 EL_SP_GRAVITY_ON_PORT_UP,
4125 EL_SP_GRAVITY_ON_PORT_DOWN,
4126 EL_SP_GRAVITY_OFF_PORT_LEFT,
4127 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4128 EL_SP_GRAVITY_OFF_PORT_UP,
4129 EL_SP_GRAVITY_OFF_PORT_DOWN,
4130 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4131 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4132 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4133 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4134 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4135 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4136 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4137 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4138 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4139 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4140 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4141 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4142 EL_SIGN_EXCLAMATION,
4143 EL_SIGN_RADIOACTIVITY,
4150 EL_SIGN_ENTRY_FORBIDDEN,
4151 EL_SIGN_EMERGENCY_EXIT,
4159 EL_DC_STEELWALL_1_LEFT,
4160 EL_DC_STEELWALL_1_RIGHT,
4161 EL_DC_STEELWALL_1_TOP,
4162 EL_DC_STEELWALL_1_BOTTOM,
4163 EL_DC_STEELWALL_1_HORIZONTAL,
4164 EL_DC_STEELWALL_1_VERTICAL,
4165 EL_DC_STEELWALL_1_TOPLEFT,
4166 EL_DC_STEELWALL_1_TOPRIGHT,
4167 EL_DC_STEELWALL_1_BOTTOMLEFT,
4168 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4169 EL_DC_STEELWALL_1_TOPLEFT_2,
4170 EL_DC_STEELWALL_1_TOPRIGHT_2,
4171 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4172 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4173 EL_DC_STEELWALL_2_LEFT,
4174 EL_DC_STEELWALL_2_RIGHT,
4175 EL_DC_STEELWALL_2_TOP,
4176 EL_DC_STEELWALL_2_BOTTOM,
4177 EL_DC_STEELWALL_2_HORIZONTAL,
4178 EL_DC_STEELWALL_2_VERTICAL,
4179 EL_DC_STEELWALL_2_MIDDLE,
4180 EL_DC_STEELWALL_2_SINGLE,
4181 EL_STEELWALL_SLIPPERY,
4186 EL_EMC_WALL_SLIPPERY_1,
4187 EL_EMC_WALL_SLIPPERY_2,
4188 EL_EMC_WALL_SLIPPERY_3,
4189 EL_EMC_WALL_SLIPPERY_4,
4210 static int ep_em_slippery_wall[] =
4215 static int ep_gfx_crumbled[] =
4226 static int ep_editor_cascade_active[] =
4228 EL_INTERNAL_CASCADE_BD_ACTIVE,
4229 EL_INTERNAL_CASCADE_EM_ACTIVE,
4230 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4231 EL_INTERNAL_CASCADE_RND_ACTIVE,
4232 EL_INTERNAL_CASCADE_SB_ACTIVE,
4233 EL_INTERNAL_CASCADE_SP_ACTIVE,
4234 EL_INTERNAL_CASCADE_DC_ACTIVE,
4235 EL_INTERNAL_CASCADE_DX_ACTIVE,
4236 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4237 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4238 EL_INTERNAL_CASCADE_CE_ACTIVE,
4239 EL_INTERNAL_CASCADE_GE_ACTIVE,
4240 EL_INTERNAL_CASCADE_REF_ACTIVE,
4241 EL_INTERNAL_CASCADE_USER_ACTIVE,
4242 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4247 static int ep_editor_cascade_inactive[] =
4249 EL_INTERNAL_CASCADE_BD,
4250 EL_INTERNAL_CASCADE_EM,
4251 EL_INTERNAL_CASCADE_EMC,
4252 EL_INTERNAL_CASCADE_RND,
4253 EL_INTERNAL_CASCADE_SB,
4254 EL_INTERNAL_CASCADE_SP,
4255 EL_INTERNAL_CASCADE_DC,
4256 EL_INTERNAL_CASCADE_DX,
4257 EL_INTERNAL_CASCADE_CHARS,
4258 EL_INTERNAL_CASCADE_STEEL_CHARS,
4259 EL_INTERNAL_CASCADE_CE,
4260 EL_INTERNAL_CASCADE_GE,
4261 EL_INTERNAL_CASCADE_REF,
4262 EL_INTERNAL_CASCADE_USER,
4263 EL_INTERNAL_CASCADE_DYNAMIC,
4268 static int ep_obsolete[] =
4272 EL_EM_KEY_1_FILE_OBSOLETE,
4273 EL_EM_KEY_2_FILE_OBSOLETE,
4274 EL_EM_KEY_3_FILE_OBSOLETE,
4275 EL_EM_KEY_4_FILE_OBSOLETE,
4276 EL_ENVELOPE_OBSOLETE,
4285 } element_properties[] =
4287 { ep_diggable, EP_DIGGABLE },
4288 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4289 { ep_dont_run_into, EP_DONT_RUN_INTO },
4290 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4291 { ep_dont_touch, EP_DONT_TOUCH },
4292 { ep_indestructible, EP_INDESTRUCTIBLE },
4293 { ep_slippery, EP_SLIPPERY },
4294 { ep_can_change, EP_CAN_CHANGE },
4295 { ep_can_move, EP_CAN_MOVE },
4296 { ep_can_fall, EP_CAN_FALL },
4297 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4298 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4299 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4300 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4301 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4302 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4303 { ep_walkable_over, EP_WALKABLE_OVER },
4304 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4305 { ep_walkable_under, EP_WALKABLE_UNDER },
4306 { ep_passable_over, EP_PASSABLE_OVER },
4307 { ep_passable_inside, EP_PASSABLE_INSIDE },
4308 { ep_passable_under, EP_PASSABLE_UNDER },
4309 { ep_droppable, EP_DROPPABLE },
4310 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4311 { ep_pushable, EP_PUSHABLE },
4312 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4313 { ep_protected, EP_PROTECTED },
4314 { ep_throwable, EP_THROWABLE },
4315 { ep_can_explode, EP_CAN_EXPLODE },
4316 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4318 { ep_player, EP_PLAYER },
4319 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4320 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4321 { ep_switchable, EP_SWITCHABLE },
4322 { ep_bd_element, EP_BD_ELEMENT },
4323 { ep_sp_element, EP_SP_ELEMENT },
4324 { ep_sb_element, EP_SB_ELEMENT },
4326 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4327 { ep_food_penguin, EP_FOOD_PENGUIN },
4328 { ep_food_pig, EP_FOOD_PIG },
4329 { ep_historic_wall, EP_HISTORIC_WALL },
4330 { ep_historic_solid, EP_HISTORIC_SOLID },
4331 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4332 { ep_belt, EP_BELT },
4333 { ep_belt_active, EP_BELT_ACTIVE },
4334 { ep_belt_switch, EP_BELT_SWITCH },
4335 { ep_tube, EP_TUBE },
4336 { ep_acid_pool, EP_ACID_POOL },
4337 { ep_keygate, EP_KEYGATE },
4338 { ep_amoeboid, EP_AMOEBOID },
4339 { ep_amoebalive, EP_AMOEBALIVE },
4340 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4341 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4342 { ep_can_grow, EP_CAN_GROW },
4343 { ep_active_bomb, EP_ACTIVE_BOMB },
4344 { ep_inactive, EP_INACTIVE },
4346 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4348 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4350 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4351 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4353 { ep_obsolete, EP_OBSOLETE },
4360 /* always start with reliable default values (element has no properties) */
4361 /* (but never initialize clipboard elements after the very first time) */
4362 /* (to be able to use clipboard elements between several levels) */
4363 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4364 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4365 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4366 SET_PROPERTY(i, j, FALSE);
4368 /* set all base element properties from above array definitions */
4369 for (i = 0; element_properties[i].elements != NULL; i++)
4370 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4371 SET_PROPERTY((element_properties[i].elements)[j],
4372 element_properties[i].property, TRUE);
4374 /* copy properties to some elements that are only stored in level file */
4375 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4376 for (j = 0; copy_properties[j][0] != -1; j++)
4377 if (HAS_PROPERTY(copy_properties[j][0], i))
4378 for (k = 1; k <= 4; k++)
4379 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4381 /* set static element properties that are not listed in array definitions */
4382 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4383 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4385 clipboard_elements_initialized = TRUE;
4388 void InitElementPropertiesEngine(int engine_version)
4390 static int no_wall_properties[] =
4393 EP_COLLECTIBLE_ONLY,
4395 EP_DONT_COLLIDE_WITH,
4398 EP_CAN_SMASH_PLAYER,
4399 EP_CAN_SMASH_ENEMIES,
4400 EP_CAN_SMASH_EVERYTHING,
4405 EP_FOOD_DARK_YAMYAM,
4421 /* important: after initialization in InitElementPropertiesStatic(), the
4422 elements are not again initialized to a default value; therefore all
4423 changes have to make sure that they leave the element with a defined
4424 property (which means that conditional property changes must be set to
4425 a reliable default value before) */
4427 /* resolve group elements */
4428 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4429 ResolveGroupElement(EL_GROUP_START + i);
4431 /* set all special, combined or engine dependent element properties */
4432 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4434 /* do not change (already initialized) clipboard elements here */
4435 if (IS_CLIPBOARD_ELEMENT(i))
4438 /* ---------- INACTIVE ------------------------------------------------- */
4439 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4440 i <= EL_CHAR_END) ||
4441 (i >= EL_STEEL_CHAR_START &&
4442 i <= EL_STEEL_CHAR_END)));
4444 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4445 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4446 IS_WALKABLE_INSIDE(i) ||
4447 IS_WALKABLE_UNDER(i)));
4449 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4450 IS_PASSABLE_INSIDE(i) ||
4451 IS_PASSABLE_UNDER(i)));
4453 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4454 IS_PASSABLE_OVER(i)));
4456 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4457 IS_PASSABLE_INSIDE(i)));
4459 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4460 IS_PASSABLE_UNDER(i)));
4462 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4465 /* ---------- COLLECTIBLE ---------------------------------------------- */
4466 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4470 /* ---------- SNAPPABLE ------------------------------------------------ */
4471 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4472 IS_COLLECTIBLE(i) ||
4476 /* ---------- WALL ----------------------------------------------------- */
4477 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4479 for (j = 0; no_wall_properties[j] != -1; j++)
4480 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4481 i >= EL_FIRST_RUNTIME_UNREAL)
4482 SET_PROPERTY(i, EP_WALL, FALSE);
4484 if (IS_HISTORIC_WALL(i))
4485 SET_PROPERTY(i, EP_WALL, TRUE);
4487 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4488 if (engine_version < VERSION_IDENT(2,2,0,0))
4489 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4491 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4493 !IS_COLLECTIBLE(i)));
4495 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4496 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4497 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4499 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4500 IS_INDESTRUCTIBLE(i)));
4502 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4504 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4505 else if (engine_version < VERSION_IDENT(2,2,0,0))
4506 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4508 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4512 if (IS_CUSTOM_ELEMENT(i))
4514 /* these are additional properties which are initially false when set */
4516 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4518 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4519 if (DONT_COLLIDE_WITH(i))
4520 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4522 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4523 if (CAN_SMASH_EVERYTHING(i))
4524 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4525 if (CAN_SMASH_ENEMIES(i))
4526 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4529 /* ---------- CAN_SMASH ------------------------------------------------ */
4530 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4531 CAN_SMASH_ENEMIES(i) ||
4532 CAN_SMASH_EVERYTHING(i)));
4534 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4535 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4536 EXPLODES_BY_FIRE(i)));
4538 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4539 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4540 EXPLODES_SMASHED(i)));
4542 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4543 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4544 EXPLODES_IMPACT(i)));
4546 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4547 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4549 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4550 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4551 i == EL_BLACK_ORB));
4553 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4554 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4556 IS_CUSTOM_ELEMENT(i)));
4558 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4559 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4560 i == EL_SP_ELECTRON));
4562 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4563 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4564 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4565 getMoveIntoAcidProperty(&level, i));
4567 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4568 if (MAYBE_DONT_COLLIDE_WITH(i))
4569 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4570 getDontCollideWithProperty(&level, i));
4572 /* ---------- SP_PORT -------------------------------------------------- */
4573 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4574 IS_PASSABLE_INSIDE(i)));
4576 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4577 for (j = 0; j < level.num_android_clone_elements; j++)
4578 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4580 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4582 /* ---------- CAN_CHANGE ----------------------------------------------- */
4583 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4584 for (j = 0; j < element_info[i].num_change_pages; j++)
4585 if (element_info[i].change_page[j].can_change)
4586 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4588 /* ---------- HAS_ACTION ----------------------------------------------- */
4589 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4590 for (j = 0; j < element_info[i].num_change_pages; j++)
4591 if (element_info[i].change_page[j].has_action)
4592 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4594 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4595 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4598 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4599 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4600 element_info[i].crumbled[ACTION_DEFAULT] !=
4601 element_info[i].graphic[ACTION_DEFAULT]);
4603 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4604 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4605 IS_EDITOR_CASCADE_INACTIVE(i)));
4608 /* dynamically adjust element properties according to game engine version */
4610 static int ep_em_slippery_wall[] =
4615 EL_EXPANDABLE_WALL_HORIZONTAL,
4616 EL_EXPANDABLE_WALL_VERTICAL,
4617 EL_EXPANDABLE_WALL_ANY,
4618 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4619 EL_EXPANDABLE_STEELWALL_VERTICAL,
4620 EL_EXPANDABLE_STEELWALL_ANY,
4621 EL_EXPANDABLE_STEELWALL_GROWING,
4625 static int ep_em_explodes_by_fire[] =
4628 EL_EM_DYNAMITE_ACTIVE,
4633 /* special EM style gems behaviour */
4634 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4635 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4636 level.em_slippery_gems);
4638 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4639 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4640 (level.em_slippery_gems &&
4641 engine_version > VERSION_IDENT(2,0,1,0)));
4643 /* special EM style explosion behaviour regarding chain reactions */
4644 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4645 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4646 level.em_explodes_by_fire);
4649 /* this is needed because some graphics depend on element properties */
4650 if (game_status == GAME_MODE_PLAYING)
4651 InitElementGraphicInfo();
4654 void InitElementPropertiesAfterLoading(int engine_version)
4658 /* set some other uninitialized values of custom elements in older levels */
4659 if (engine_version < VERSION_IDENT(3,1,0,0))
4661 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4663 int element = EL_CUSTOM_START + i;
4665 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4667 element_info[element].explosion_delay = 17;
4668 element_info[element].ignition_delay = 8;
4673 void InitElementPropertiesGfxElement()
4677 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4679 struct ElementInfo *ei = &element_info[i];
4681 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4685 static void InitGlobal()
4690 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4692 /* check if element_name_info entry defined for each element in "main.h" */
4693 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4694 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4696 element_info[i].token_name = element_name_info[i].token_name;
4697 element_info[i].class_name = element_name_info[i].class_name;
4698 element_info[i].editor_description= element_name_info[i].editor_description;
4701 /* create hash from image config list */
4702 image_config_hash = newSetupFileHash();
4703 for (i = 0; image_config[i].token != NULL; i++)
4704 setHashEntry(image_config_hash,
4705 image_config[i].token,
4706 image_config[i].value);
4708 /* create hash from element token list */
4709 element_token_hash = newSetupFileHash();
4710 for (i = 0; element_name_info[i].token_name != NULL; i++)
4711 setHashEntry(element_token_hash,
4712 element_name_info[i].token_name,
4715 /* create hash from graphic token list */
4716 graphic_token_hash = newSetupFileHash();
4717 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4718 if (strSuffix(image_config[i].value, ".png") ||
4719 strSuffix(image_config[i].value, ".pcx") ||
4720 strSuffix(image_config[i].value, ".wav") ||
4721 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4722 setHashEntry(graphic_token_hash,
4723 image_config[i].token,
4724 int2str(graphic++, 0));
4726 /* create hash from font token list */
4727 font_token_hash = newSetupFileHash();
4728 for (i = 0; font_info[i].token_name != NULL; i++)
4729 setHashEntry(font_token_hash,
4730 font_info[i].token_name,
4733 /* set default filenames for all cloned graphics in static configuration */
4734 for (i = 0; image_config[i].token != NULL; i++)
4736 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4738 char *token = image_config[i].token;
4739 char *token_clone_from = getStringCat2(token, ".clone_from");
4740 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4742 if (token_cloned != NULL)
4744 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4746 if (value_cloned != NULL)
4748 /* set default filename in static configuration */
4749 image_config[i].value = value_cloned;
4751 /* set default filename in image config hash */
4752 setHashEntry(image_config_hash, token, value_cloned);
4756 free(token_clone_from);
4760 /* always start with reliable default values (all elements) */
4761 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4762 ActiveElement[i] = i;
4764 /* now add all entries that have an active state (active elements) */
4765 for (i = 0; element_with_active_state[i].element != -1; i++)
4767 int element = element_with_active_state[i].element;
4768 int element_active = element_with_active_state[i].element_active;
4770 ActiveElement[element] = element_active;
4773 /* always start with reliable default values (all buttons) */
4774 for (i = 0; i < NUM_IMAGE_FILES; i++)
4775 ActiveButton[i] = i;
4777 /* now add all entries that have an active state (active buttons) */
4778 for (i = 0; button_with_active_state[i].button != -1; i++)
4780 int button = button_with_active_state[i].button;
4781 int button_active = button_with_active_state[i].button_active;
4783 ActiveButton[button] = button_active;
4786 /* always start with reliable default values (all fonts) */
4787 for (i = 0; i < NUM_FONTS; i++)
4790 /* now add all entries that have an active state (active fonts) */
4791 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4793 int font = font_with_active_state[i].font_nr;
4794 int font_active = font_with_active_state[i].font_nr_active;
4796 ActiveFont[font] = font_active;
4799 global.autoplay_leveldir = NULL;
4800 global.convert_leveldir = NULL;
4801 global.create_images_dir = NULL;
4803 global.frames_per_second = 0;
4805 global.border_status = GAME_MODE_LOADING;
4806 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4808 global.use_envelope_request = FALSE;
4811 void Execute_Command(char *command)
4815 if (strEqual(command, "print graphicsinfo.conf"))
4817 Print("# You can configure additional/alternative image files here.\n");
4818 Print("# (The entries below are default and therefore commented out.)\n");
4820 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4822 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4825 for (i = 0; image_config[i].token != NULL; i++)
4826 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4827 image_config[i].value));
4831 else if (strEqual(command, "print soundsinfo.conf"))
4833 Print("# You can configure additional/alternative sound files here.\n");
4834 Print("# (The entries below are default and therefore commented out.)\n");
4836 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4838 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4841 for (i = 0; sound_config[i].token != NULL; i++)
4842 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4843 sound_config[i].value));
4847 else if (strEqual(command, "print musicinfo.conf"))
4849 Print("# You can configure additional/alternative music files here.\n");
4850 Print("# (The entries below are default and therefore commented out.)\n");
4852 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4854 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4857 for (i = 0; music_config[i].token != NULL; i++)
4858 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4859 music_config[i].value));
4863 else if (strEqual(command, "print editorsetup.conf"))
4865 Print("# You can configure your personal editor element list here.\n");
4866 Print("# (The entries below are default and therefore commented out.)\n");
4869 /* this is needed to be able to check element list for cascade elements */
4870 InitElementPropertiesStatic();
4871 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4873 PrintEditorElementList();
4877 else if (strEqual(command, "print helpanim.conf"))
4879 Print("# You can configure different element help animations here.\n");
4880 Print("# (The entries below are default and therefore commented out.)\n");
4883 for (i = 0; helpanim_config[i].token != NULL; i++)
4885 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4886 helpanim_config[i].value));
4888 if (strEqual(helpanim_config[i].token, "end"))
4894 else if (strEqual(command, "print helptext.conf"))
4896 Print("# You can configure different element help text here.\n");
4897 Print("# (The entries below are default and therefore commented out.)\n");
4900 for (i = 0; helptext_config[i].token != NULL; i++)
4901 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4902 helptext_config[i].value));
4906 else if (strPrefix(command, "dump level "))
4908 char *filename = &command[11];
4910 if (!fileExists(filename))
4911 Error(ERR_EXIT, "cannot open file '%s'", filename);
4913 LoadLevelFromFilename(&level, filename);
4918 else if (strPrefix(command, "dump tape "))
4920 char *filename = &command[10];
4922 if (!fileExists(filename))
4923 Error(ERR_EXIT, "cannot open file '%s'", filename);
4925 LoadTapeFromFilename(filename);
4930 else if (strPrefix(command, "autotest ") ||
4931 strPrefix(command, "autoplay ") ||
4932 strPrefix(command, "autoffwd ") ||
4933 strPrefix(command, "autowarp "))
4935 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4937 global.autoplay_mode =
4938 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
4939 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
4940 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
4941 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
4942 AUTOPLAY_MODE_NONE);
4944 while (*str_ptr != '\0') /* continue parsing string */
4946 /* cut leading whitespace from string, replace it by string terminator */
4947 while (*str_ptr == ' ' || *str_ptr == '\t')
4950 if (*str_ptr == '\0') /* end of string reached */
4953 if (global.autoplay_leveldir == NULL) /* read level set string */
4955 global.autoplay_leveldir = str_ptr;
4956 global.autoplay_all = TRUE; /* default: play all tapes */
4958 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4959 global.autoplay_level[i] = FALSE;
4961 else /* read level number string */
4963 int level_nr = atoi(str_ptr); /* get level_nr value */
4965 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4966 global.autoplay_level[level_nr] = TRUE;
4968 global.autoplay_all = FALSE;
4971 /* advance string pointer to the next whitespace (or end of string) */
4972 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4976 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
4977 program.headless = TRUE;
4979 else if (strPrefix(command, "convert "))
4981 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4982 char *str_ptr = strchr(str_copy, ' ');
4984 global.convert_leveldir = str_copy;
4985 global.convert_level_nr = -1;
4987 if (str_ptr != NULL) /* level number follows */
4989 *str_ptr++ = '\0'; /* terminate leveldir string */
4990 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4993 program.headless = TRUE;
4995 else if (strPrefix(command, "create images "))
4997 global.create_images_dir = getStringCopy(&command[14]);
4999 if (access(global.create_images_dir, W_OK) != 0)
5000 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5001 global.create_images_dir);
5003 else if (strPrefix(command, "create CE image "))
5005 CreateCustomElementImages(&command[16]);
5011 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5015 static void InitSetup()
5017 LoadSetup(); /* global setup info */
5019 /* set some options from setup file */
5021 if (setup.options.verbose)
5022 options.verbose = TRUE;
5025 static void InitGameInfo()
5027 game.restart_level = FALSE;
5030 static void InitPlayerInfo()
5034 /* choose default local player */
5035 local_player = &stored_player[0];
5037 for (i = 0; i < MAX_PLAYERS; i++)
5038 stored_player[i].connected = FALSE;
5040 local_player->connected = TRUE;
5043 static void InitArtworkInfo()
5048 static char *get_string_in_brackets(char *string)
5050 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5052 sprintf(string_in_brackets, "[%s]", string);
5054 return string_in_brackets;
5057 static char *get_level_id_suffix(int id_nr)
5059 char *id_suffix = checked_malloc(1 + 3 + 1);
5061 if (id_nr < 0 || id_nr > 999)
5064 sprintf(id_suffix, ".%03d", id_nr);
5069 static void InitArtworkConfig()
5071 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5073 NUM_GLOBAL_ANIM_TOKENS + 1];
5074 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5075 NUM_GLOBAL_ANIM_TOKENS + 1];
5076 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5077 NUM_GLOBAL_ANIM_TOKENS + 1];
5078 static char *action_id_suffix[NUM_ACTIONS + 1];
5079 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5080 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5081 static char *level_id_suffix[MAX_LEVELS + 1];
5082 static char *dummy[1] = { NULL };
5083 static char *ignore_generic_tokens[] =
5089 static char **ignore_image_tokens;
5090 static char **ignore_sound_tokens;
5091 static char **ignore_music_tokens;
5092 int num_ignore_generic_tokens;
5093 int num_ignore_image_tokens;
5094 int num_ignore_sound_tokens;
5095 int num_ignore_music_tokens;
5098 /* dynamically determine list of generic tokens to be ignored */
5099 num_ignore_generic_tokens = 0;
5100 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5101 num_ignore_generic_tokens++;
5103 /* dynamically determine list of image tokens to be ignored */
5104 num_ignore_image_tokens = num_ignore_generic_tokens;
5105 for (i = 0; image_config_vars[i].token != NULL; i++)
5106 num_ignore_image_tokens++;
5107 ignore_image_tokens =
5108 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5109 for (i = 0; i < num_ignore_generic_tokens; i++)
5110 ignore_image_tokens[i] = ignore_generic_tokens[i];
5111 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5112 ignore_image_tokens[num_ignore_generic_tokens + i] =
5113 image_config_vars[i].token;
5114 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5116 /* dynamically determine list of sound tokens to be ignored */
5117 num_ignore_sound_tokens = num_ignore_generic_tokens;
5118 ignore_sound_tokens =
5119 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5120 for (i = 0; i < num_ignore_generic_tokens; i++)
5121 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5122 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5124 /* dynamically determine list of music tokens to be ignored */
5125 num_ignore_music_tokens = num_ignore_generic_tokens;
5126 ignore_music_tokens =
5127 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5128 for (i = 0; i < num_ignore_generic_tokens; i++)
5129 ignore_music_tokens[i] = ignore_generic_tokens[i];
5130 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5132 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5133 image_id_prefix[i] = element_info[i].token_name;
5134 for (i = 0; i < NUM_FONTS; i++)
5135 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5136 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5137 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5138 global_anim_info[i].token_name;
5139 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5141 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5142 sound_id_prefix[i] = element_info[i].token_name;
5143 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5144 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5145 get_string_in_brackets(element_info[i].class_name);
5146 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5147 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5148 global_anim_info[i].token_name;
5149 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5151 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5152 music_id_prefix[i] = music_prefix_info[i].prefix;
5153 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5154 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5155 global_anim_info[i].token_name;
5156 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5158 for (i = 0; i < NUM_ACTIONS; i++)
5159 action_id_suffix[i] = element_action_info[i].suffix;
5160 action_id_suffix[NUM_ACTIONS] = NULL;
5162 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5163 direction_id_suffix[i] = element_direction_info[i].suffix;
5164 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5166 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5167 special_id_suffix[i] = special_suffix_info[i].suffix;
5168 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5170 for (i = 0; i < MAX_LEVELS; i++)
5171 level_id_suffix[i] = get_level_id_suffix(i);
5172 level_id_suffix[MAX_LEVELS] = NULL;
5174 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5175 image_id_prefix, action_id_suffix, direction_id_suffix,
5176 special_id_suffix, ignore_image_tokens);
5177 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5178 sound_id_prefix, action_id_suffix, dummy,
5179 special_id_suffix, ignore_sound_tokens);
5180 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5181 music_id_prefix, action_id_suffix, special_id_suffix,
5182 level_id_suffix, ignore_music_tokens);
5185 static void InitMixer()
5192 void InitGfxBuffers()
5194 static int win_xsize_last = -1;
5195 static int win_ysize_last = -1;
5197 /* create additional image buffers for double-buffering and cross-fading */
5199 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5201 /* used to temporarily store the backbuffer -- only re-create if changed */
5202 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5203 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5205 win_xsize_last = WIN_XSIZE;
5206 win_ysize_last = WIN_YSIZE;
5209 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5210 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5211 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5212 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5214 /* initialize screen properties */
5215 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5216 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5218 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5219 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5220 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5221 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5222 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5223 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5225 /* required if door size definitions have changed */
5226 InitGraphicCompatibilityInfo_Doors();
5228 InitGfxBuffers_EM();
5229 InitGfxBuffers_SP();
5234 struct GraphicInfo *graphic_info_last = graphic_info;
5235 char *filename_font_initial = NULL;
5236 char *filename_anim_initial = NULL;
5237 Bitmap *bitmap_font_initial = NULL;
5241 /* determine settings for initial font (for displaying startup messages) */
5242 for (i = 0; image_config[i].token != NULL; i++)
5244 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5246 char font_token[128];
5249 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5250 len_font_token = strlen(font_token);
5252 if (strEqual(image_config[i].token, font_token))
5253 filename_font_initial = image_config[i].value;
5254 else if (strlen(image_config[i].token) > len_font_token &&
5255 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5257 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5258 font_initial[j].src_x = atoi(image_config[i].value);
5259 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5260 font_initial[j].src_y = atoi(image_config[i].value);
5261 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5262 font_initial[j].width = atoi(image_config[i].value);
5263 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5264 font_initial[j].height = atoi(image_config[i].value);
5269 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5271 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5272 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5275 if (filename_font_initial == NULL) /* should not happen */
5276 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5279 InitGfxCustomArtworkInfo();
5280 InitGfxOtherSettings();
5282 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5284 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5285 font_initial[j].bitmap = bitmap_font_initial;
5287 InitFontGraphicInfo();
5289 font_height = getFontHeight(FC_RED);
5291 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5292 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5293 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5296 DrawInitText("Loading graphics", 120, FC_GREEN);
5298 /* initialize settings for busy animation with default values */
5299 int parameter[NUM_GFX_ARGS];
5300 for (i = 0; i < NUM_GFX_ARGS; i++)
5301 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5302 image_config_suffix[i].token,
5303 image_config_suffix[i].type);
5305 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5306 int len_anim_token = strlen(anim_token);
5308 /* read settings for busy animation from default custom artwork config */
5309 char *gfx_config_filename = getPath3(options.graphics_directory,
5311 GRAPHICSINFO_FILENAME);
5313 if (fileExists(gfx_config_filename))
5315 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5317 if (setup_file_hash)
5319 char *filename = getHashEntry(setup_file_hash, anim_token);
5323 filename_anim_initial = getStringCopy(filename);
5325 for (j = 0; image_config_suffix[j].token != NULL; j++)
5327 int type = image_config_suffix[j].type;
5328 char *suffix = image_config_suffix[j].token;
5329 char *token = getStringCat2(anim_token, suffix);
5330 char *value = getHashEntry(setup_file_hash, token);
5332 checked_free(token);
5335 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5339 freeSetupFileHash(setup_file_hash);
5343 if (filename_anim_initial == NULL)
5345 /* read settings for busy animation from static default artwork config */
5346 for (i = 0; image_config[i].token != NULL; i++)
5348 if (strEqual(image_config[i].token, anim_token))
5349 filename_anim_initial = getStringCopy(image_config[i].value);
5350 else if (strlen(image_config[i].token) > len_anim_token &&
5351 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5353 for (j = 0; image_config_suffix[j].token != NULL; j++)
5355 if (strEqual(&image_config[i].token[len_anim_token],
5356 image_config_suffix[j].token))
5358 get_graphic_parameter_value(image_config[i].value,
5359 image_config_suffix[j].token,
5360 image_config_suffix[j].type);
5366 if (filename_anim_initial == NULL) /* should not happen */
5367 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5369 anim_initial.bitmaps =
5370 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5372 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5373 LoadCustomImage(filename_anim_initial);
5375 checked_free(filename_anim_initial);
5377 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5379 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5381 graphic_info = graphic_info_last;
5383 init.busy.width = anim_initial.width;
5384 init.busy.height = anim_initial.height;
5386 InitMenuDesignSettings_Static();
5388 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5389 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5390 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5392 gfx.fade_border_source_status = global.border_status;
5393 gfx.fade_border_target_status = global.border_status;
5394 gfx.masked_border_bitmap_ptr = backbuffer;
5396 /* use copy of busy animation to prevent change while reloading artwork */
5400 void InitGfxBackground()
5402 fieldbuffer = bitmap_db_field;
5403 SetDrawtoField(DRAW_TO_BACKBUFFER);
5405 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5407 redraw_mask = REDRAW_ALL;
5410 static void InitLevelInfo()
5412 LoadLevelInfo(); /* global level info */
5413 LoadLevelSetup_LastSeries(); /* last played series info */
5414 LoadLevelSetup_SeriesInfo(); /* last played level info */
5416 if (global.autoplay_leveldir &&
5417 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5419 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5420 global.autoplay_leveldir);
5421 if (leveldir_current == NULL)
5422 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5426 static void InitLevelArtworkInfo()
5428 LoadLevelArtworkInfo();
5431 static void InitImages()
5433 print_timestamp_init("InitImages");
5436 printf("::: leveldir_current->identifier == '%s'\n",
5437 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5438 printf("::: leveldir_current->graphics_path == '%s'\n",
5439 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5440 printf("::: leveldir_current->graphics_set == '%s'\n",
5441 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5442 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5443 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5446 setLevelArtworkDir(artwork.gfx_first);
5449 printf("::: leveldir_current->identifier == '%s'\n",
5450 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5451 printf("::: leveldir_current->graphics_path == '%s'\n",
5452 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5453 printf("::: leveldir_current->graphics_set == '%s'\n",
5454 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5455 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5456 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5460 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5461 leveldir_current->identifier,
5462 artwork.gfx_current_identifier,
5463 artwork.gfx_current->identifier,
5464 leveldir_current->graphics_set,
5465 leveldir_current->graphics_path);
5468 UPDATE_BUSY_STATE();
5470 ReloadCustomImages();
5471 print_timestamp_time("ReloadCustomImages");
5473 UPDATE_BUSY_STATE();
5475 LoadCustomElementDescriptions();
5476 print_timestamp_time("LoadCustomElementDescriptions");
5478 UPDATE_BUSY_STATE();
5480 LoadMenuDesignSettings();
5481 print_timestamp_time("LoadMenuDesignSettings");
5483 UPDATE_BUSY_STATE();
5485 ReinitializeGraphics();
5486 print_timestamp_time("ReinitializeGraphics");
5488 LoadMenuDesignSettings_AfterGraphics();
5489 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5491 UPDATE_BUSY_STATE();
5493 print_timestamp_done("InitImages");
5496 static void InitSound(char *identifier)
5498 print_timestamp_init("InitSound");
5500 if (identifier == NULL)
5501 identifier = artwork.snd_current->identifier;
5503 /* set artwork path to send it to the sound server process */
5504 setLevelArtworkDir(artwork.snd_first);
5506 InitReloadCustomSounds(identifier);
5507 print_timestamp_time("InitReloadCustomSounds");
5509 ReinitializeSounds();
5510 print_timestamp_time("ReinitializeSounds");
5512 print_timestamp_done("InitSound");
5515 static void InitMusic(char *identifier)
5517 print_timestamp_init("InitMusic");
5519 if (identifier == NULL)
5520 identifier = artwork.mus_current->identifier;
5522 /* set artwork path to send it to the sound server process */
5523 setLevelArtworkDir(artwork.mus_first);
5525 InitReloadCustomMusic(identifier);
5526 print_timestamp_time("InitReloadCustomMusic");
5528 ReinitializeMusic();
5529 print_timestamp_time("ReinitializeMusic");
5531 print_timestamp_done("InitMusic");
5534 static void InitArtworkDone()
5536 if (program.headless)
5539 InitGlobalAnimations();
5542 void InitNetworkServer()
5544 #if defined(NETWORK_AVALIABLE)
5548 if (!options.network)
5551 #if defined(NETWORK_AVALIABLE)
5552 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5554 if (!ConnectToServer(options.server_host, options.server_port))
5555 Error(ERR_EXIT, "cannot connect to network game server");
5557 SendToServer_PlayerName(setup.player_name);
5558 SendToServer_ProtocolVersion();
5561 SendToServer_NrWanted(nr_wanted);
5565 static boolean CheckArtworkConfigForCustomElements(char *filename)
5567 SetupFileHash *setup_file_hash;
5568 boolean redefined_ce_found = FALSE;
5570 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5572 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5574 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5576 char *token = HASH_ITERATION_TOKEN(itr);
5578 if (strPrefix(token, "custom_"))
5580 redefined_ce_found = TRUE;
5585 END_HASH_ITERATION(setup_file_hash, itr)
5587 freeSetupFileHash(setup_file_hash);
5590 return redefined_ce_found;
5593 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5595 char *filename_base, *filename_local;
5596 boolean redefined_ce_found = FALSE;
5598 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5601 printf("::: leveldir_current->identifier == '%s'\n",
5602 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5603 printf("::: leveldir_current->graphics_path == '%s'\n",
5604 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5605 printf("::: leveldir_current->graphics_set == '%s'\n",
5606 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5607 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5608 leveldir_current == NULL ? "[NULL]" :
5609 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5612 /* first look for special artwork configured in level series config */
5613 filename_base = getCustomArtworkLevelConfigFilename(type);
5616 printf("::: filename_base == '%s'\n", filename_base);
5619 if (fileExists(filename_base))
5620 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5622 filename_local = getCustomArtworkConfigFilename(type);
5625 printf("::: filename_local == '%s'\n", filename_local);
5628 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5629 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5632 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5635 return redefined_ce_found;
5638 static void InitOverrideArtwork()
5640 boolean redefined_ce_found = FALSE;
5642 /* to check if this level set redefines any CEs, do not use overriding */
5643 gfx.override_level_graphics = FALSE;
5644 gfx.override_level_sounds = FALSE;
5645 gfx.override_level_music = FALSE;
5647 /* now check if this level set has definitions for custom elements */
5648 if (setup.override_level_graphics == AUTO ||
5649 setup.override_level_sounds == AUTO ||
5650 setup.override_level_music == AUTO)
5651 redefined_ce_found =
5652 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5653 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5654 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5657 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5660 if (redefined_ce_found)
5662 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5663 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5664 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5665 gfx.override_level_music = (setup.override_level_music == TRUE);
5669 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5670 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5671 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5672 gfx.override_level_music = (setup.override_level_music != FALSE);
5676 printf("::: => %d, %d, %d\n",
5677 gfx.override_level_graphics,
5678 gfx.override_level_sounds,
5679 gfx.override_level_music);
5683 static char *getNewArtworkIdentifier(int type)
5685 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5686 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5687 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5688 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5689 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5690 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5691 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5692 char *leveldir_identifier = leveldir_current->identifier;
5693 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5694 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5695 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5696 char *artwork_current_identifier;
5697 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5699 /* leveldir_current may be invalid (level group, parent link) */
5700 if (!validLevelSeries(leveldir_current))
5703 /* 1st step: determine artwork set to be activated in descending order:
5704 --------------------------------------------------------------------
5705 1. setup artwork (when configured to override everything else)
5706 2. artwork set configured in "levelinfo.conf" of current level set
5707 (artwork in level directory will have priority when loading later)
5708 3. artwork in level directory (stored in artwork sub-directory)
5709 4. setup artwork (currently configured in setup menu) */
5711 if (setup_override_artwork)
5712 artwork_current_identifier = setup_artwork_set;
5713 else if (leveldir_artwork_set != NULL)
5714 artwork_current_identifier = leveldir_artwork_set;
5715 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5716 artwork_current_identifier = leveldir_identifier;
5718 artwork_current_identifier = setup_artwork_set;
5721 /* 2nd step: check if it is really needed to reload artwork set
5722 ------------------------------------------------------------ */
5724 /* ---------- reload if level set and also artwork set has changed ------- */
5725 if (leveldir_current_identifier[type] != leveldir_identifier &&
5726 (last_has_level_artwork_set[type] || has_level_artwork_set))
5727 artwork_new_identifier = artwork_current_identifier;
5729 leveldir_current_identifier[type] = leveldir_identifier;
5730 last_has_level_artwork_set[type] = has_level_artwork_set;
5732 /* ---------- reload if "override artwork" setting has changed ----------- */
5733 if (last_override_level_artwork[type] != setup_override_artwork)
5734 artwork_new_identifier = artwork_current_identifier;
5736 last_override_level_artwork[type] = setup_override_artwork;
5738 /* ---------- reload if current artwork identifier has changed ----------- */
5739 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5740 artwork_current_identifier))
5741 artwork_new_identifier = artwork_current_identifier;
5743 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5745 /* ---------- do not reload directly after starting ---------------------- */
5746 if (!initialized[type])
5747 artwork_new_identifier = NULL;
5749 initialized[type] = TRUE;
5751 return artwork_new_identifier;
5754 void ReloadCustomArtwork(int force_reload)
5756 int last_game_status = game_status; /* save current game status */
5757 char *gfx_new_identifier;
5758 char *snd_new_identifier;
5759 char *mus_new_identifier;
5760 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5761 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5762 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5763 boolean reload_needed;
5765 InitOverrideArtwork();
5767 force_reload_gfx |= AdjustGraphicsForEMC();
5769 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5770 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5771 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5773 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5774 snd_new_identifier != NULL || force_reload_snd ||
5775 mus_new_identifier != NULL || force_reload_mus);
5780 print_timestamp_init("ReloadCustomArtwork");
5782 SetGameStatus(GAME_MODE_LOADING);
5784 FadeOut(REDRAW_ALL);
5786 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5787 print_timestamp_time("ClearRectangle");
5791 if (gfx_new_identifier != NULL || force_reload_gfx)
5794 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5795 artwork.gfx_current_identifier,
5797 artwork.gfx_current->identifier,
5798 leveldir_current->graphics_set);
5802 print_timestamp_time("InitImages");
5805 if (snd_new_identifier != NULL || force_reload_snd)
5807 InitSound(snd_new_identifier);
5808 print_timestamp_time("InitSound");
5811 if (mus_new_identifier != NULL || force_reload_mus)
5813 InitMusic(mus_new_identifier);
5814 print_timestamp_time("InitMusic");
5819 SetGameStatus(last_game_status); /* restore current game status */
5821 init_last = init; /* switch to new busy animation */
5823 FadeOut(REDRAW_ALL);
5825 RedrawGlobalBorder();
5827 /* force redraw of (open or closed) door graphics */
5828 SetDoorState(DOOR_OPEN_ALL);
5829 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5831 FadeSetEnterScreen();
5832 FadeSkipNextFadeOut();
5834 print_timestamp_done("ReloadCustomArtwork");
5836 LimitScreenUpdates(FALSE);
5839 void KeyboardAutoRepeatOffUnlessAutoplay()
5841 if (global.autoplay_leveldir == NULL)
5842 KeyboardAutoRepeatOff();
5845 void DisplayExitMessage(char *format, va_list ap)
5847 // check if draw buffer and fonts for exit message are already available
5848 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5851 int font_1 = FC_RED;
5852 int font_2 = FC_YELLOW;
5853 int font_3 = FC_BLUE;
5854 int font_width = getFontWidth(font_2);
5855 int font_height = getFontHeight(font_2);
5858 int sxsize = WIN_XSIZE - 2 * sx;
5859 int sysize = WIN_YSIZE - 2 * sy;
5860 int line_length = sxsize / font_width;
5861 int max_lines = sysize / font_height;
5862 int num_lines_printed;
5866 gfx.sxsize = sxsize;
5867 gfx.sysize = sysize;
5871 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5873 DrawTextSCentered(sy, font_1, "Fatal error:");
5874 sy += 3 * font_height;;
5877 DrawTextBufferVA(sx, sy, format, ap, font_2,
5878 line_length, line_length, max_lines,
5879 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5880 sy += (num_lines_printed + 3) * font_height;
5882 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5883 sy += 3 * font_height;
5886 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5887 line_length, line_length, max_lines,
5888 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5890 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5892 redraw_mask = REDRAW_ALL;
5894 /* force drawing exit message even if screen updates are currently limited */
5895 LimitScreenUpdates(FALSE);
5899 /* deactivate toons on error message screen */
5900 setup.toons = FALSE;
5902 WaitForEventToContinue();
5906 /* ========================================================================= */
5908 /* ========================================================================= */
5912 print_timestamp_init("OpenAll");
5914 SetGameStatus(GAME_MODE_LOADING);
5918 InitGlobal(); /* initialize some global variables */
5920 print_timestamp_time("[init global stuff]");
5924 print_timestamp_time("[init setup/config stuff (1)]");
5928 if (options.execute_command)
5929 Execute_Command(options.execute_command);
5931 if (options.serveronly)
5933 #if defined(PLATFORM_UNIX)
5934 NetworkServer(options.server_port, options.serveronly);
5936 Error(ERR_WARN, "networking only supported in Unix version");
5939 exit(0); /* never reached, server loops forever */
5943 print_timestamp_time("[init setup/config stuff (2)]");
5945 print_timestamp_time("[init setup/config stuff (3)]");
5946 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5947 print_timestamp_time("[init setup/config stuff (4)]");
5948 InitArtworkConfig(); /* needed before forking sound child process */
5949 print_timestamp_time("[init setup/config stuff (5)]");
5951 print_timestamp_time("[init setup/config stuff (6)]");
5953 InitRND(NEW_RANDOMIZE);
5954 InitSimpleRandom(NEW_RANDOMIZE);
5958 print_timestamp_time("[init setup/config stuff]");
5961 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5965 print_timestamp_time("[init video stuff]");
5967 InitElementPropertiesStatic();
5968 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5969 InitElementPropertiesGfxElement();
5971 print_timestamp_time("[init element properties stuff]");
5975 print_timestamp_time("InitGfx");
5978 print_timestamp_time("InitLevelInfo");
5980 InitLevelArtworkInfo();
5981 print_timestamp_time("InitLevelArtworkInfo");
5983 InitOverrideArtwork(); /* needs to know current level directory */
5984 print_timestamp_time("InitOverrideArtwork");
5986 InitImages(); /* needs to know current level directory */
5987 print_timestamp_time("InitImages");
5989 InitSound(NULL); /* needs to know current level directory */
5990 print_timestamp_time("InitSound");
5992 InitMusic(NULL); /* needs to know current level directory */
5993 print_timestamp_time("InitMusic");
5997 InitGfxBackground();
6002 if (global.autoplay_leveldir)
6007 else if (global.convert_leveldir)
6012 else if (global.create_images_dir)
6014 CreateLevelSketchImages();
6018 SetGameStatus(GAME_MODE_MAIN);
6020 FadeSetEnterScreen();
6021 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6022 FadeSkipNextFadeOut();
6024 print_timestamp_time("[post-artwork]");
6026 print_timestamp_done("OpenAll");
6030 InitNetworkServer();
6033 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6035 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6036 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6037 #if defined(PLATFORM_ANDROID)
6038 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6039 SDL_AndroidGetInternalStoragePath());
6040 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6041 SDL_AndroidGetExternalStoragePath());
6042 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6043 (SDL_AndroidGetExternalStorageState() ==
6044 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
6045 SDL_AndroidGetExternalStorageState() ==
6046 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
6051 void CloseAllAndExit(int exit_value)
6056 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6063 #if defined(TARGET_SDL)
6064 #if defined(TARGET_SDL2)
6066 // set a flag to tell the network server thread to quit and wait for it
6067 // using SDL_WaitThread()
6069 if (network_server) /* terminate network server */
6070 SDL_KillThread(server_thread);
6074 CloseVideoDisplay();
6075 ClosePlatformDependentStuff();
6077 if (exit_value != 0)
6079 /* fall back to default level set (current set may have caused an error) */
6080 SaveLevelSetup_LastSeries_Deactivate();
6082 /* tell user where to find error log file which may contain more details */
6083 // (error notification now directly displayed on screen inside R'n'D
6084 // NotifyUserAboutErrorFile(); /* currently only works for Windows */