1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // https://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
82 EL_SPRING_LEFT, EL_SPRING_RIGHT,
83 EL_SPRING_LEFT, EL_SPRING_RIGHT, // (to match array size)
92 // forward declaration for internal use
93 static int get_graphic_parameter_value(char *, char *, int);
96 static void DrawInitAnim(void)
98 struct GraphicInfo *graphic_info_last = graphic_info;
100 static unsigned int action_delay = 0;
101 unsigned int action_delay_value = GameFrameDelay;
102 int sync_frame = FrameCounter;
105 // prevent OS (Windows) from complaining about program not responding
108 if (game_status != GAME_MODE_LOADING)
111 if (anim_initial.bitmap == NULL || window == NULL)
114 if (!DelayReached(&action_delay, action_delay_value))
117 if (init_last.busy.x == -1)
118 init_last.busy.x = WIN_XSIZE / 2;
119 if (init_last.busy.y == -1)
120 init_last.busy.y = WIN_YSIZE / 2;
122 x = ALIGNED_TEXT_XPOS(&init_last.busy);
123 y = ALIGNED_TEXT_YPOS(&init_last.busy);
125 graphic_info = &anim_initial; // graphic == 0 => anim_initial
127 if (sync_frame % anim_initial.anim_delay == 0)
131 int width = graphic_info[graphic].width;
132 int height = graphic_info[graphic].height;
133 int frame = getGraphicAnimationFrame(graphic, sync_frame);
135 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
136 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
139 graphic_info = graphic_info_last;
144 static void DrawProgramInfo(void)
146 int font1_nr = FC_YELLOW;
147 int font2_nr = FC_RED;
148 int font2_height = getFontHeight(font2_nr);
151 int ypos3 = WIN_YSIZE - 20 - font2_height;
153 DrawInitText(getProgramInitString(), ypos1, font1_nr);
154 DrawInitText(setup.internal.program_copyright, ypos2, font2_nr);
155 DrawInitText(setup.internal.program_website, ypos3, font2_nr);
158 static void FreeGadgets(void)
160 FreeLevelEditorGadgets();
167 void InitGadgets(void)
169 static boolean gadgets_initialized = FALSE;
171 if (gadgets_initialized)
174 CreateLevelEditorGadgets();
178 CreateScreenGadgets();
180 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
182 gadgets_initialized = TRUE;
185 static void InitElementSmallImagesScaledUp(int graphic)
187 struct GraphicInfo *g = &graphic_info[graphic];
189 // create small and game tile sized bitmaps (and scale up, if needed)
190 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
193 static void InitElementSmallImages(void)
195 print_timestamp_init("InitElementSmallImages");
197 static int special_graphics[] =
211 IMG_EDITOR_ELEMENT_BORDER,
212 IMG_EDITOR_ELEMENT_BORDER_INPUT,
213 IMG_EDITOR_CASCADE_LIST,
214 IMG_EDITOR_CASCADE_LIST_ACTIVE,
217 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
218 int num_property_mappings = getImageListPropertyMappingSize();
221 print_timestamp_time("getImageListPropertyMapping/Size");
223 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
224 // initialize normal element images from static configuration
225 for (i = 0; element_to_graphic[i].element > -1; i++)
226 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
227 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
229 // initialize special element images from static configuration
230 for (i = 0; element_to_special_graphic[i].element > -1; i++)
231 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
232 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
234 // initialize element images from dynamic configuration
235 for (i = 0; i < num_property_mappings; i++)
236 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
237 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
238 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
240 // initialize special non-element images from above list
241 for (i = 0; special_graphics[i] > -1; i++)
242 InitElementSmallImagesScaledUp(special_graphics[i]);
243 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
245 print_timestamp_done("InitElementSmallImages");
248 static void InitScaledImagesScaledUp(int graphic)
250 struct GraphicInfo *g = &graphic_info[graphic];
252 ScaleImage(graphic, g->scale_up_factor);
255 static void InitScaledImages(void)
257 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
258 int num_property_mappings = getImageListPropertyMappingSize();
261 // scale normal images from static configuration, if not already scaled
262 for (i = 0; i < NUM_IMAGE_FILES; i++)
263 InitScaledImagesScaledUp(i);
265 // scale images from dynamic configuration, if not already scaled
266 for (i = 0; i < num_property_mappings; i++)
267 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
270 static void InitBitmapPointers(void)
272 int num_images = getImageListSize();
275 // standard size bitmap may have changed -- update default bitmap pointer
276 for (i = 0; i < num_images; i++)
277 if (graphic_info[i].bitmaps)
278 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
281 void InitImageTextures(void)
283 static int texture_graphics[] =
285 IMG_GFX_REQUEST_BUTTON_TOUCH_YES,
286 IMG_GFX_REQUEST_BUTTON_TOUCH_NO,
287 IMG_GFX_REQUEST_BUTTON_TOUCH_CONFIRM,
288 IMG_GFX_GAME_BUTTON_TOUCH_STOP,
289 IMG_GFX_GAME_BUTTON_TOUCH_PAUSE,
290 IMG_MENU_BUTTON_TOUCH_BACK,
291 IMG_MENU_BUTTON_TOUCH_NEXT,
292 IMG_MENU_BUTTON_TOUCH_BACK2,
293 IMG_MENU_BUTTON_TOUCH_NEXT2,
298 FreeAllImageTextures();
300 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
301 CreateImageTextures(i);
303 for (i = 0; i < MAX_NUM_TOONS; i++)
304 CreateImageTextures(IMG_TOON_1 + i);
306 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
308 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
310 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
312 int graphic = global_anim_info[i].graphic[j][k];
314 if (graphic == IMG_UNDEFINED)
317 CreateImageTextures(graphic);
322 for (i = 0; texture_graphics[i] > -1; i++)
323 CreateImageTextures(texture_graphics[i]);
326 static int getFontBitmapID(int font_nr)
330 // (special case: do not use special font for GAME_MODE_LOADING)
331 if (game_status >= GAME_MODE_TITLE_INITIAL &&
332 game_status <= GAME_MODE_PSEUDO_PREVIEW)
333 special = game_status;
334 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
335 special = GFX_SPECIAL_ARG_MAIN;
338 return font_info[font_nr].special_bitmap_id[special];
343 static int getFontFromToken(char *token)
345 char *value = getHashEntry(font_token_hash, token);
350 // if font not found, use reliable default value
351 return FONT_INITIAL_1;
354 static void InitFontGraphicInfo(void)
356 static struct FontBitmapInfo *font_bitmap_info = NULL;
357 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
358 int num_property_mappings = getImageListPropertyMappingSize();
359 int num_font_bitmaps = NUM_FONTS;
362 if (graphic_info == NULL) // still at startup phase
364 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
365 getFontBitmapID, getFontFromToken);
370 // ---------- initialize font graphic definitions ----------
372 // always start with reliable default values (normal font graphics)
373 for (i = 0; i < NUM_FONTS; i++)
374 font_info[i].graphic = IMG_FONT_INITIAL_1;
376 // initialize normal font/graphic mapping from static configuration
377 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
379 int font_nr = font_to_graphic[i].font_nr;
380 int special = font_to_graphic[i].special;
381 int graphic = font_to_graphic[i].graphic;
386 font_info[font_nr].graphic = graphic;
389 // always start with reliable default values (special font graphics)
390 for (i = 0; i < NUM_FONTS; i++)
392 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
394 font_info[i].special_graphic[j] = font_info[i].graphic;
395 font_info[i].special_bitmap_id[j] = i;
399 // initialize special font/graphic mapping from static configuration
400 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
402 int font_nr = font_to_graphic[i].font_nr;
403 int special = font_to_graphic[i].special;
404 int graphic = font_to_graphic[i].graphic;
405 int base_graphic = font2baseimg(font_nr);
407 if (IS_SPECIAL_GFX_ARG(special))
409 boolean base_redefined =
410 getImageListEntryFromImageID(base_graphic)->redefined;
411 boolean special_redefined =
412 getImageListEntryFromImageID(graphic)->redefined;
413 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
415 /* if the base font ("font.title_1", for example) has been redefined,
416 but not the special font ("font.title_1.LEVELS", for example), do not
417 use an existing (in this case considered obsolete) special font
418 anymore, but use the automatically determined default font */
419 /* special case: cloned special fonts must be explicitly redefined,
420 but are not automatically redefined by redefining base font */
421 if (base_redefined && !special_redefined && !special_cloned)
424 font_info[font_nr].special_graphic[special] = graphic;
425 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
430 // initialize special font/graphic mapping from dynamic configuration
431 for (i = 0; i < num_property_mappings; i++)
433 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
434 int special = property_mapping[i].ext3_index;
435 int graphic = property_mapping[i].artwork_index;
437 if (font_nr < 0 || font_nr >= NUM_FONTS)
440 if (IS_SPECIAL_GFX_ARG(special))
442 font_info[font_nr].special_graphic[special] = graphic;
443 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
448 /* correct special font/graphic mapping for cloned fonts for downwards
449 compatibility of PREVIEW fonts -- this is only needed for implicit
450 redefinition of special font by redefined base font, and only if other
451 fonts are cloned from this special font (like in the "Zelda" level set) */
452 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
454 int font_nr = font_to_graphic[i].font_nr;
455 int special = font_to_graphic[i].special;
456 int graphic = font_to_graphic[i].graphic;
458 if (IS_SPECIAL_GFX_ARG(special))
460 boolean special_redefined =
461 getImageListEntryFromImageID(graphic)->redefined;
462 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
464 if (special_cloned && !special_redefined)
468 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
470 int font_nr2 = font_to_graphic[j].font_nr;
471 int special2 = font_to_graphic[j].special;
472 int graphic2 = font_to_graphic[j].graphic;
474 if (IS_SPECIAL_GFX_ARG(special2) &&
475 graphic2 == graphic_info[graphic].clone_from)
477 font_info[font_nr].special_graphic[special] =
478 font_info[font_nr2].special_graphic[special2];
479 font_info[font_nr].special_bitmap_id[special] =
480 font_info[font_nr2].special_bitmap_id[special2];
487 // reset non-redefined ".active" font graphics if normal font is redefined
488 // (this different treatment is needed because normal and active fonts are
489 // independently defined ("active" is not a property of font definitions!)
490 for (i = 0; i < NUM_FONTS; i++)
492 int font_nr_base = i;
493 int font_nr_active = FONT_ACTIVE(font_nr_base);
495 // check only those fonts with exist as normal and ".active" variant
496 if (font_nr_base != font_nr_active)
498 int base_graphic = font_info[font_nr_base].graphic;
499 int active_graphic = font_info[font_nr_active].graphic;
500 boolean base_redefined =
501 getImageListEntryFromImageID(base_graphic)->redefined;
502 boolean active_redefined =
503 getImageListEntryFromImageID(active_graphic)->redefined;
505 /* if the base font ("font.menu_1", for example) has been redefined,
506 but not the active font ("font.menu_1.active", for example), do not
507 use an existing (in this case considered obsolete) active font
508 anymore, but use the automatically determined default font */
509 if (base_redefined && !active_redefined)
510 font_info[font_nr_active].graphic = base_graphic;
512 // now also check each "special" font (which may be the same as above)
513 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
515 int base_graphic = font_info[font_nr_base].special_graphic[j];
516 int active_graphic = font_info[font_nr_active].special_graphic[j];
517 boolean base_redefined =
518 getImageListEntryFromImageID(base_graphic)->redefined;
519 boolean active_redefined =
520 getImageListEntryFromImageID(active_graphic)->redefined;
522 // same as above, but check special graphic definitions, for example:
523 // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
524 if (base_redefined && !active_redefined)
526 font_info[font_nr_active].special_graphic[j] =
527 font_info[font_nr_base].special_graphic[j];
528 font_info[font_nr_active].special_bitmap_id[j] =
529 font_info[font_nr_base].special_bitmap_id[j];
535 // ---------- initialize font bitmap array ----------
537 if (font_bitmap_info != NULL)
538 FreeFontInfo(font_bitmap_info);
541 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
543 // ---------- initialize font bitmap definitions ----------
545 for (i = 0; i < NUM_FONTS; i++)
547 if (i < NUM_INITIAL_FONTS)
549 font_bitmap_info[i] = font_initial[i];
553 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
555 int font_bitmap_id = font_info[i].special_bitmap_id[j];
556 int graphic = font_info[i].special_graphic[j];
558 // set 'graphic_info' for font entries, if uninitialized (guessed)
559 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
561 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
562 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
565 // copy font relevant information from graphics information
566 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
567 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
568 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
569 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
570 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
572 font_bitmap_info[font_bitmap_id].offset_x =
573 graphic_info[graphic].offset_x;
574 font_bitmap_info[font_bitmap_id].offset_y =
575 graphic_info[graphic].offset_y;
577 font_bitmap_info[font_bitmap_id].draw_xoffset =
578 graphic_info[graphic].draw_xoffset;
579 font_bitmap_info[font_bitmap_id].draw_yoffset =
580 graphic_info[graphic].draw_yoffset;
582 font_bitmap_info[font_bitmap_id].num_chars =
583 graphic_info[graphic].anim_frames;
584 font_bitmap_info[font_bitmap_id].num_chars_per_line =
585 graphic_info[graphic].anim_frames_per_line;
589 InitFontInfo(font_bitmap_info, num_font_bitmaps,
590 getFontBitmapID, getFontFromToken);
593 static void InitGlobalAnimGraphicInfo(void)
595 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
596 int num_property_mappings = getImageListPropertyMappingSize();
599 if (graphic_info == NULL) // still at startup phase
602 // always start with reliable default values (no global animations)
603 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
604 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
605 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
606 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
608 // initialize global animation definitions from static configuration
609 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
611 int j = GLOBAL_ANIM_ID_PART_BASE;
612 int k = GFX_SPECIAL_ARG_DEFAULT;
614 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
617 // initialize global animation definitions from dynamic configuration
618 for (i = 0; i < num_property_mappings; i++)
620 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
621 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
622 int special = property_mapping[i].ext3_index;
623 int graphic = property_mapping[i].artwork_index;
625 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
628 // set animation part to base part, if not specified
629 if (!IS_GLOBAL_ANIM_PART(part_nr))
630 part_nr = GLOBAL_ANIM_ID_PART_BASE;
632 // set animation screen to default, if not specified
633 if (!IS_SPECIAL_GFX_ARG(special))
634 special = GFX_SPECIAL_ARG_DEFAULT;
636 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
638 // fix default value for ".draw_masked" (for backward compatibility)
639 struct GraphicInfo *g = &graphic_info[graphic];
640 struct FileInfo *image = getImageListEntryFromImageID(graphic);
641 char **parameter_raw = image->parameter;
642 int p = GFX_ARG_DRAW_MASKED;
643 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
644 image_config_suffix[p].token,
645 image_config_suffix[p].type);
647 // if ".draw_masked" parameter is undefined, use default value "TRUE"
648 if (draw_masked == ARG_UNDEFINED_VALUE)
649 g->draw_masked = TRUE;
653 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
654 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
655 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
656 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
657 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
658 Debug("init:InitGlobalAnimGraphicInfo",
659 "anim %d, part %d, mode %d => %d",
660 i, j, k, global_anim_info[i].graphic[j][k]);
664 static void InitGlobalAnimSoundInfo(void)
666 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
667 int num_property_mappings = getSoundListPropertyMappingSize();
670 // always start with reliable default values (no global animation sounds)
671 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
672 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
673 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
674 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
676 // initialize global animation sound definitions from dynamic configuration
677 for (i = 0; i < num_property_mappings; i++)
679 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
680 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
681 int special = property_mapping[i].ext3_index;
682 int sound = property_mapping[i].artwork_index;
684 // sound uses control definition; map it to position of graphic (artwork)
685 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
687 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
690 // set animation part to base part, if not specified
691 if (!IS_GLOBAL_ANIM_PART(part_nr))
692 part_nr = GLOBAL_ANIM_ID_PART_BASE;
694 // set animation screen to default, if not specified
695 if (!IS_SPECIAL_GFX_ARG(special))
696 special = GFX_SPECIAL_ARG_DEFAULT;
698 global_anim_info[anim_nr].sound[part_nr][special] = sound;
702 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
703 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
704 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
705 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
706 Debug("init:InitGlobalAnimSoundInfo",
707 "anim %d, part %d, mode %d => %d",
708 i, j, k, global_anim_info[i].sound[j][k]);
712 static void InitGlobalAnimMusicInfo(void)
714 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
715 int num_property_mappings = getMusicListPropertyMappingSize();
718 // always start with reliable default values (no global animation music)
719 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
720 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
721 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
722 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
724 // initialize global animation music definitions from dynamic configuration
725 for (i = 0; i < num_property_mappings; i++)
727 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
728 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
729 int special = property_mapping[i].ext2_index;
730 int music = property_mapping[i].artwork_index;
732 // music uses control definition; map it to position of graphic (artwork)
733 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
735 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
738 // set animation part to base part, if not specified
739 if (!IS_GLOBAL_ANIM_PART(part_nr))
740 part_nr = GLOBAL_ANIM_ID_PART_BASE;
742 // set animation screen to default, if not specified
743 if (!IS_SPECIAL_GFX_ARG(special))
744 special = GFX_SPECIAL_ARG_DEFAULT;
746 global_anim_info[anim_nr].music[part_nr][special] = music;
750 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
751 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
752 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
753 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
754 Debug("init:InitGlobalAnimMusicInfo",
755 "anim %d, part %d, mode %d => %d",
756 i, j, k, global_anim_info[i].music[j][k]);
760 static void InitElementGraphicInfo(void)
762 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
763 int num_property_mappings = getImageListPropertyMappingSize();
766 if (graphic_info == NULL) // still at startup phase
769 // set values to -1 to identify later as "uninitialized" values
770 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
772 for (act = 0; act < NUM_ACTIONS; act++)
774 element_info[i].graphic[act] = -1;
775 element_info[i].crumbled[act] = -1;
777 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
779 element_info[i].direction_graphic[act][dir] = -1;
780 element_info[i].direction_crumbled[act][dir] = -1;
787 // initialize normal element/graphic mapping from static configuration
788 for (i = 0; element_to_graphic[i].element > -1; i++)
790 int element = element_to_graphic[i].element;
791 int action = element_to_graphic[i].action;
792 int direction = element_to_graphic[i].direction;
793 boolean crumbled = element_to_graphic[i].crumbled;
794 int graphic = element_to_graphic[i].graphic;
795 int base_graphic = el2baseimg(element);
797 if (graphic_info[graphic].bitmap == NULL)
800 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
803 boolean base_redefined =
804 getImageListEntryFromImageID(base_graphic)->redefined;
805 boolean act_dir_redefined =
806 getImageListEntryFromImageID(graphic)->redefined;
808 /* if the base graphic ("emerald", for example) has been redefined,
809 but not the action graphic ("emerald.falling", for example), do not
810 use an existing (in this case considered obsolete) action graphic
811 anymore, but use the automatically determined default graphic */
812 if (base_redefined && !act_dir_redefined)
817 action = ACTION_DEFAULT;
822 element_info[element].direction_crumbled[action][direction] = graphic;
824 element_info[element].crumbled[action] = graphic;
829 element_info[element].direction_graphic[action][direction] = graphic;
831 element_info[element].graphic[action] = graphic;
835 // initialize normal element/graphic mapping from dynamic configuration
836 for (i = 0; i < num_property_mappings; i++)
838 int element = property_mapping[i].base_index;
839 int action = property_mapping[i].ext1_index;
840 int direction = property_mapping[i].ext2_index;
841 int special = property_mapping[i].ext3_index;
842 int graphic = property_mapping[i].artwork_index;
843 boolean crumbled = FALSE;
845 if (special == GFX_SPECIAL_ARG_CRUMBLED)
851 if (graphic_info[graphic].bitmap == NULL)
854 if (element >= MAX_NUM_ELEMENTS || special != -1)
858 action = ACTION_DEFAULT;
863 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
864 element_info[element].direction_crumbled[action][dir] = -1;
867 element_info[element].direction_crumbled[action][direction] = graphic;
869 element_info[element].crumbled[action] = graphic;
874 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
875 element_info[element].direction_graphic[action][dir] = -1;
878 element_info[element].direction_graphic[action][direction] = graphic;
880 element_info[element].graphic[action] = graphic;
884 // now copy all graphics that are defined to be cloned from other graphics
885 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
887 int graphic = element_info[i].graphic[ACTION_DEFAULT];
888 int crumbled_like, diggable_like;
893 crumbled_like = graphic_info[graphic].crumbled_like;
894 diggable_like = graphic_info[graphic].diggable_like;
896 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
898 for (act = 0; act < NUM_ACTIONS; act++)
899 element_info[i].crumbled[act] =
900 element_info[crumbled_like].crumbled[act];
901 for (act = 0; act < NUM_ACTIONS; act++)
902 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
903 element_info[i].direction_crumbled[act][dir] =
904 element_info[crumbled_like].direction_crumbled[act][dir];
907 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
909 element_info[i].graphic[ACTION_DIGGING] =
910 element_info[diggable_like].graphic[ACTION_DIGGING];
911 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
912 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
913 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
917 // set hardcoded definitions for some runtime elements without graphic
918 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
920 // set hardcoded definitions for some internal elements without graphic
921 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
923 if (IS_EDITOR_CASCADE_INACTIVE(i))
924 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
925 else if (IS_EDITOR_CASCADE_ACTIVE(i))
926 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
929 // now set all undefined/invalid graphics to -1 to set to default after it
930 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
932 for (act = 0; act < NUM_ACTIONS; act++)
936 graphic = element_info[i].graphic[act];
937 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
938 element_info[i].graphic[act] = -1;
940 graphic = element_info[i].crumbled[act];
941 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
942 element_info[i].crumbled[act] = -1;
944 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
946 graphic = element_info[i].direction_graphic[act][dir];
947 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
948 element_info[i].direction_graphic[act][dir] = -1;
950 graphic = element_info[i].direction_crumbled[act][dir];
951 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
952 element_info[i].direction_crumbled[act][dir] = -1;
959 // adjust graphics with 2nd tile for movement according to direction
960 // (do this before correcting '-1' values to minimize calculations)
961 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
963 for (act = 0; act < NUM_ACTIONS; act++)
965 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
967 int graphic = element_info[i].direction_graphic[act][dir];
968 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
970 if (act == ACTION_FALLING) // special case
971 graphic = element_info[i].graphic[act];
974 graphic_info[graphic].double_movement &&
975 graphic_info[graphic].swap_double_tiles != 0)
977 struct GraphicInfo *g = &graphic_info[graphic];
978 int src_x_front = g->src_x;
979 int src_y_front = g->src_y;
980 int src_x_back = g->src_x + g->offset2_x;
981 int src_y_back = g->src_y + g->offset2_y;
982 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
984 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
985 src_y_front < src_y_back);
986 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
987 boolean swap_movement_tiles_autodetected =
988 (!frames_are_ordered_diagonally &&
989 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
990 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
991 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
992 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
994 // swap frontside and backside graphic tile coordinates, if needed
995 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
997 // get current (wrong) backside tile coordinates
998 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1000 // set frontside tile coordinates to backside tile coordinates
1001 g->src_x = src_x_back;
1002 g->src_y = src_y_back;
1004 // invert tile offset to point to new backside tile coordinates
1008 // do not swap front and backside tiles again after correction
1009 g->swap_double_tiles = 0;
1016 UPDATE_BUSY_STATE();
1018 // now set all '-1' values to element specific default values
1019 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1021 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1022 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1023 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1024 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1026 if (default_graphic == -1)
1027 default_graphic = IMG_UNKNOWN;
1029 if (default_crumbled == -1)
1030 default_crumbled = default_graphic;
1032 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1034 default_direction_graphic[dir] =
1035 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1036 default_direction_crumbled[dir] =
1037 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1039 if (default_direction_graphic[dir] == -1)
1040 default_direction_graphic[dir] = default_graphic;
1042 if (default_direction_crumbled[dir] == -1)
1043 default_direction_crumbled[dir] = default_direction_graphic[dir];
1046 for (act = 0; act < NUM_ACTIONS; act++)
1048 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1049 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1050 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1051 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1052 act == ACTION_TURNING_FROM_RIGHT ||
1053 act == ACTION_TURNING_FROM_UP ||
1054 act == ACTION_TURNING_FROM_DOWN);
1056 // generic default action graphic (defined by "[default]" directive)
1057 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1058 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1059 int default_remove_graphic = IMG_EMPTY;
1061 if (act_remove && default_action_graphic != -1)
1062 default_remove_graphic = default_action_graphic;
1064 // look for special default action graphic (classic game specific)
1065 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1066 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1067 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1068 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1069 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1070 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1071 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1072 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1074 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1075 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1076 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1077 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1078 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1079 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1080 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1081 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1083 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1084 // !!! make this better !!!
1085 if (i == EL_EMPTY_SPACE)
1087 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1088 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1091 if (default_action_graphic == -1)
1092 default_action_graphic = default_graphic;
1094 if (default_action_crumbled == -1)
1095 default_action_crumbled = default_action_graphic;
1097 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1099 // use action graphic as the default direction graphic, if undefined
1100 int default_action_direction_graphic = element_info[i].graphic[act];
1101 int default_action_direction_crumbled = element_info[i].crumbled[act];
1103 // no graphic for current action -- use default direction graphic
1104 if (default_action_direction_graphic == -1)
1105 default_action_direction_graphic =
1106 (act_remove ? default_remove_graphic :
1108 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1109 default_action_graphic != default_graphic ?
1110 default_action_graphic :
1111 default_direction_graphic[dir]);
1113 if (element_info[i].direction_graphic[act][dir] == -1)
1114 element_info[i].direction_graphic[act][dir] =
1115 default_action_direction_graphic;
1117 if (default_action_direction_crumbled == -1)
1118 default_action_direction_crumbled =
1119 element_info[i].direction_graphic[act][dir];
1121 if (element_info[i].direction_crumbled[act][dir] == -1)
1122 element_info[i].direction_crumbled[act][dir] =
1123 default_action_direction_crumbled;
1126 // no graphic for this specific action -- use default action graphic
1127 if (element_info[i].graphic[act] == -1)
1128 element_info[i].graphic[act] =
1129 (act_remove ? default_remove_graphic :
1130 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1131 default_action_graphic);
1133 if (element_info[i].crumbled[act] == -1)
1134 element_info[i].crumbled[act] = element_info[i].graphic[act];
1138 UPDATE_BUSY_STATE();
1141 static void InitElementSpecialGraphicInfo(void)
1143 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1144 int num_property_mappings = getImageListPropertyMappingSize();
1147 // always start with reliable default values
1148 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1149 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1150 element_info[i].special_graphic[j] =
1151 element_info[i].graphic[ACTION_DEFAULT];
1153 // initialize special element/graphic mapping from static configuration
1154 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1156 int element = element_to_special_graphic[i].element;
1157 int special = element_to_special_graphic[i].special;
1158 int graphic = element_to_special_graphic[i].graphic;
1159 int base_graphic = el2baseimg(element);
1160 boolean base_redefined =
1161 getImageListEntryFromImageID(base_graphic)->redefined;
1162 boolean special_redefined =
1163 getImageListEntryFromImageID(graphic)->redefined;
1165 /* if the base graphic ("emerald", for example) has been redefined,
1166 but not the special graphic ("emerald.EDITOR", for example), do not
1167 use an existing (in this case considered obsolete) special graphic
1168 anymore, but use the automatically created (down-scaled) graphic */
1169 if (base_redefined && !special_redefined)
1172 element_info[element].special_graphic[special] = graphic;
1175 // initialize special element/graphic mapping from dynamic configuration
1176 for (i = 0; i < num_property_mappings; i++)
1178 int element = property_mapping[i].base_index;
1179 int action = property_mapping[i].ext1_index;
1180 int direction = property_mapping[i].ext2_index;
1181 int special = property_mapping[i].ext3_index;
1182 int graphic = property_mapping[i].artwork_index;
1184 // for action ".active", replace element with active element, if exists
1185 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1187 element = ELEMENT_ACTIVE(element);
1191 if (element >= MAX_NUM_ELEMENTS)
1194 // do not change special graphic if action or direction was specified
1195 if (action != -1 || direction != -1)
1198 if (IS_SPECIAL_GFX_ARG(special))
1199 element_info[element].special_graphic[special] = graphic;
1202 // now set all undefined/invalid graphics to default
1203 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1204 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1205 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1206 element_info[i].special_graphic[j] =
1207 element_info[i].graphic[ACTION_DEFAULT];
1210 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1212 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1213 return get_parameter_value(value_raw, suffix, type);
1215 if (strEqual(value_raw, ARG_UNDEFINED))
1216 return ARG_UNDEFINED_VALUE;
1218 if (type == TYPE_ELEMENT)
1220 char *value = getHashEntry(element_token_hash, value_raw);
1225 Warn("error found in config file:");
1226 Warn("- config file: '%s'", getImageConfigFilename());
1227 Warn("error: invalid element token '%s'", value_raw);
1228 Warn("custom graphic rejected for this element/action");
1229 Warn("fallback done to undefined element for this graphic");
1233 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1235 else if (type == TYPE_GRAPHIC)
1237 char *value = getHashEntry(graphic_token_hash, value_raw);
1238 int fallback_graphic = IMG_CHAR_EXCLAM;
1243 Warn("error found in config file:");
1244 Warn("- config file: '%s'", getImageConfigFilename());
1245 Warn("error: invalid graphic token '%s'", value_raw);
1246 Warn("custom graphic rejected for this element/action");
1247 Warn("fallback done to 'char_exclam' for this graphic");
1251 return (value != NULL ? atoi(value) : fallback_graphic);
1257 static int get_scaled_graphic_width(int graphic)
1259 int original_width = getOriginalImageWidthFromImageID(graphic);
1260 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1262 return original_width * scale_up_factor;
1265 static int get_scaled_graphic_height(int graphic)
1267 int original_height = getOriginalImageHeightFromImageID(graphic);
1268 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1270 return original_height * scale_up_factor;
1273 static void set_graphic_parameters_ext(int graphic, int *parameter,
1274 Bitmap **src_bitmaps)
1276 struct GraphicInfo *g = &graphic_info[graphic];
1277 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1278 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1279 int anim_frames_per_line = 1;
1281 // always start with reliable default values
1282 g->src_image_width = 0;
1283 g->src_image_height = 0;
1286 g->width = TILEX; // default for element graphics
1287 g->height = TILEY; // default for element graphics
1288 g->offset_x = 0; // one or both of these values ...
1289 g->offset_y = 0; // ... will be corrected later
1290 g->offset2_x = 0; // one or both of these values ...
1291 g->offset2_y = 0; // ... will be corrected later
1292 g->swap_double_tiles = -1; // auto-detect tile swapping
1293 g->crumbled_like = -1; // do not use clone element
1294 g->diggable_like = -1; // do not use clone element
1295 g->border_size = TILEX / 8; // "CRUMBLED" border size
1296 g->scale_up_factor = 1; // default: no scaling up
1297 g->tile_size = TILESIZE; // default: standard tile size
1298 g->clone_from = -1; // do not use clone graphic
1299 g->init_delay_fixed = 0;
1300 g->init_delay_random = 0;
1301 g->init_delay_action = -1;
1302 g->anim_delay_fixed = 0;
1303 g->anim_delay_random = 0;
1304 g->anim_delay_action = -1;
1305 g->post_delay_fixed = 0;
1306 g->post_delay_random = 0;
1307 g->post_delay_action = -1;
1308 g->init_event = ANIM_EVENT_UNDEFINED;
1309 g->anim_event = ANIM_EVENT_UNDEFINED;
1310 g->init_event_action = -1;
1311 g->anim_event_action = -1;
1312 g->draw_masked = FALSE;
1314 g->fade_mode = FADE_MODE_DEFAULT;
1318 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1319 g->align = ALIGN_CENTER; // default for title screens
1320 g->valign = VALIGN_MIDDLE; // default for title screens
1321 g->sort_priority = 0; // default for title screens
1323 g->style = STYLE_DEFAULT;
1325 g->bitmaps = src_bitmaps;
1326 g->bitmap = src_bitmap;
1328 // optional zoom factor for scaling up the image to a larger size
1329 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1330 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1331 if (g->scale_up_factor < 1)
1332 g->scale_up_factor = 1; // no scaling
1334 // optional tile size for using non-standard image size
1335 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1337 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1340 // CHECK: should tile sizes less than standard tile size be allowed?
1341 if (g->tile_size < TILESIZE)
1342 g->tile_size = TILESIZE; // standard tile size
1345 // when setting tile size, also set width and height accordingly
1346 g->width = g->tile_size;
1347 g->height = g->tile_size;
1350 if (g->use_image_size)
1352 // set new default bitmap size (with scaling, but without small images)
1353 g->width = get_scaled_graphic_width(graphic);
1354 g->height = get_scaled_graphic_height(graphic);
1357 // optional width and height of each animation frame
1358 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1359 g->width = parameter[GFX_ARG_WIDTH];
1360 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1361 g->height = parameter[GFX_ARG_HEIGHT];
1363 // optional x and y tile position of animation frame sequence
1364 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1365 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1366 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1367 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1369 // optional x and y pixel position of animation frame sequence
1370 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1371 g->src_x = parameter[GFX_ARG_X];
1372 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1373 g->src_y = parameter[GFX_ARG_Y];
1380 Warn("invalid value %d for '%s.width' (fallback done to %d)",
1381 g->width, getTokenFromImageID(graphic), TILEX);
1384 g->width = TILEX; // will be checked to be inside bitmap later
1390 Warn("invalid value %d for '%s.height' (fallback done to %d)",
1391 g->height, getTokenFromImageID(graphic), TILEY);
1394 g->height = TILEY; // will be checked to be inside bitmap later
1400 // get final bitmap size (with scaling, but without small images)
1401 int src_image_width = get_scaled_graphic_width(graphic);
1402 int src_image_height = get_scaled_graphic_height(graphic);
1404 if (src_image_width == 0 || src_image_height == 0)
1406 // only happens when loaded outside artwork system (like "global.busy")
1407 src_image_width = src_bitmap->width;
1408 src_image_height = src_bitmap->height;
1411 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1413 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1414 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1418 anim_frames_per_row = MAX(1, src_image_width / g->width);
1419 anim_frames_per_col = MAX(1, src_image_height / g->height);
1422 g->src_image_width = src_image_width;
1423 g->src_image_height = src_image_height;
1426 // correct x or y offset dependent of vertical or horizontal frame order
1427 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1429 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1430 parameter[GFX_ARG_OFFSET] : g->height);
1431 anim_frames_per_line = anim_frames_per_col;
1433 else // frames are ordered horizontally
1435 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1436 parameter[GFX_ARG_OFFSET] : g->width);
1437 anim_frames_per_line = anim_frames_per_row;
1440 // optionally, the x and y offset of frames can be specified directly
1441 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1442 g->offset_x = parameter[GFX_ARG_XOFFSET];
1443 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1444 g->offset_y = parameter[GFX_ARG_YOFFSET];
1446 // optionally, moving animations may have separate start and end graphics
1447 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1449 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1450 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1452 // correct x or y offset2 dependent of vertical or horizontal frame order
1453 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1454 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1455 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1456 else // frames are ordered horizontally
1457 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1458 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1460 // optionally, the x and y offset of 2nd graphic can be specified directly
1461 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1462 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1463 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1464 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1466 // optionally, the second movement tile can be specified as start tile
1467 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1468 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1470 // automatically determine correct number of frames, if not defined
1471 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1472 g->anim_frames = parameter[GFX_ARG_FRAMES];
1473 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1474 g->anim_frames = anim_frames_per_row;
1475 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1476 g->anim_frames = anim_frames_per_col;
1480 if (g->anim_frames < 1) // frames must be at least 1
1483 g->anim_frames_per_line =
1484 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1485 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1487 g->anim_delay = parameter[GFX_ARG_DELAY];
1488 if (g->anim_delay < 1) // delay must be at least 1
1491 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1493 // automatically determine correct start frame, if not defined
1494 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1495 g->anim_start_frame = 0;
1496 else if (g->anim_mode & ANIM_REVERSE)
1497 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1499 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1501 // animation synchronized with global frame counter, not move position
1502 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1504 // optional element for cloning crumble graphics
1505 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1506 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1508 // optional element for cloning digging graphics
1509 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1510 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1512 // optional border size for "crumbling" diggable graphics
1513 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1514 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1516 // used for global animations and player "boring" and "sleeping" actions
1517 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1518 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1519 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1520 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1521 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1522 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1523 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1524 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1525 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1526 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1527 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1528 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1530 // used for global animations
1531 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1532 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1533 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1534 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1535 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1536 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1537 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1538 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1539 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1540 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1541 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1542 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1543 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1544 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1546 // used for toon animations and global animations
1547 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1548 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1549 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1550 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1551 g->direction = parameter[GFX_ARG_DIRECTION];
1552 g->position = parameter[GFX_ARG_POSITION];
1553 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1554 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1556 if (g->step_delay < 1) // delay must be at least 1
1559 // this is only used for drawing font characters
1560 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1561 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1563 // use a different default value for global animations and toons
1564 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1565 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1566 g->draw_masked = TRUE;
1568 // this is used for drawing envelopes, global animations and toons
1569 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1570 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1572 // used for toon animations and global animations
1573 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1574 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1576 // optional graphic for cloning all graphics settings
1577 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1578 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1580 // optional settings for drawing title screens and title messages
1581 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1582 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1583 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1584 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1585 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1586 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1587 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1588 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1589 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1590 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1591 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1592 g->align = parameter[GFX_ARG_ALIGN];
1593 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1594 g->valign = parameter[GFX_ARG_VALIGN];
1595 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1596 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1598 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1599 g->class = parameter[GFX_ARG_CLASS];
1600 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1601 g->style = parameter[GFX_ARG_STYLE];
1603 // this is only used for drawing menu buttons and text
1604 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1605 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1606 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1607 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1610 static void set_graphic_parameters(int graphic)
1612 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1613 char **parameter_raw = image->parameter;
1614 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1615 int parameter[NUM_GFX_ARGS];
1618 // if fallback to default artwork is done, also use the default parameters
1619 if (image->fallback_to_default)
1620 parameter_raw = image->default_parameter;
1622 // get integer values from string parameters
1623 for (i = 0; i < NUM_GFX_ARGS; i++)
1624 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1625 image_config_suffix[i].token,
1626 image_config_suffix[i].type);
1628 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1630 UPDATE_BUSY_STATE();
1633 static void set_cloned_graphic_parameters(int graphic)
1635 int fallback_graphic = IMG_CHAR_EXCLAM;
1636 int max_num_images = getImageListSize();
1637 int clone_graphic = graphic_info[graphic].clone_from;
1638 int num_references_followed = 1;
1640 while (graphic_info[clone_graphic].clone_from != -1 &&
1641 num_references_followed < max_num_images)
1643 clone_graphic = graphic_info[clone_graphic].clone_from;
1645 num_references_followed++;
1648 if (num_references_followed >= max_num_images)
1651 Warn("error found in config file:");
1652 Warn("- config file: '%s'", getImageConfigFilename());
1653 Warn("- config token: '%s'", getTokenFromImageID(graphic));
1654 Warn("error: loop discovered when resolving cloned graphics");
1655 Warn("custom graphic rejected for this element/action");
1657 if (graphic == fallback_graphic)
1658 Error(ERR_EXIT, "no fallback graphic available");
1660 Warn("fallback done to 'char_exclam' for this graphic");
1663 graphic_info[graphic] = graphic_info[fallback_graphic];
1667 graphic_info[graphic] = graphic_info[clone_graphic];
1668 graphic_info[graphic].clone_from = clone_graphic;
1672 static void InitGraphicInfo(void)
1674 int fallback_graphic = IMG_CHAR_EXCLAM;
1675 int num_images = getImageListSize();
1678 // use image size as default values for width and height for these images
1679 static int full_size_graphics[] =
1682 IMG_GLOBAL_BORDER_MAIN,
1683 IMG_GLOBAL_BORDER_SCORES,
1684 IMG_GLOBAL_BORDER_EDITOR,
1685 IMG_GLOBAL_BORDER_PLAYING,
1688 IMG_BACKGROUND_ENVELOPE_1,
1689 IMG_BACKGROUND_ENVELOPE_2,
1690 IMG_BACKGROUND_ENVELOPE_3,
1691 IMG_BACKGROUND_ENVELOPE_4,
1692 IMG_BACKGROUND_REQUEST,
1695 IMG_BACKGROUND_TITLE_INITIAL,
1696 IMG_BACKGROUND_TITLE,
1697 IMG_BACKGROUND_MAIN,
1698 IMG_BACKGROUND_LEVELS,
1699 IMG_BACKGROUND_LEVELNR,
1700 IMG_BACKGROUND_SCORES,
1701 IMG_BACKGROUND_EDITOR,
1702 IMG_BACKGROUND_INFO,
1703 IMG_BACKGROUND_INFO_ELEMENTS,
1704 IMG_BACKGROUND_INFO_MUSIC,
1705 IMG_BACKGROUND_INFO_CREDITS,
1706 IMG_BACKGROUND_INFO_PROGRAM,
1707 IMG_BACKGROUND_INFO_VERSION,
1708 IMG_BACKGROUND_INFO_LEVELSET,
1709 IMG_BACKGROUND_SETUP,
1710 IMG_BACKGROUND_PLAYING,
1711 IMG_BACKGROUND_DOOR,
1712 IMG_BACKGROUND_TAPE,
1713 IMG_BACKGROUND_PANEL,
1714 IMG_BACKGROUND_PALETTE,
1715 IMG_BACKGROUND_TOOLBOX,
1717 IMG_TITLESCREEN_INITIAL_1,
1718 IMG_TITLESCREEN_INITIAL_2,
1719 IMG_TITLESCREEN_INITIAL_3,
1720 IMG_TITLESCREEN_INITIAL_4,
1721 IMG_TITLESCREEN_INITIAL_5,
1728 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1729 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1730 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1731 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1732 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1733 IMG_BACKGROUND_TITLEMESSAGE_1,
1734 IMG_BACKGROUND_TITLEMESSAGE_2,
1735 IMG_BACKGROUND_TITLEMESSAGE_3,
1736 IMG_BACKGROUND_TITLEMESSAGE_4,
1737 IMG_BACKGROUND_TITLEMESSAGE_5,
1742 FreeGlobalAnimEventInfo();
1744 checked_free(graphic_info);
1746 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1748 // initialize "use_image_size" flag with default value
1749 for (i = 0; i < num_images; i++)
1750 graphic_info[i].use_image_size = FALSE;
1752 // initialize "use_image_size" flag from static configuration above
1753 for (i = 0; full_size_graphics[i] != -1; i++)
1754 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1756 // first set all graphic paramaters ...
1757 for (i = 0; i < num_images; i++)
1758 set_graphic_parameters(i);
1760 // ... then copy these parameters for cloned graphics
1761 for (i = 0; i < num_images; i++)
1762 if (graphic_info[i].clone_from != -1)
1763 set_cloned_graphic_parameters(i);
1765 for (i = 0; i < num_images; i++)
1767 Bitmap *src_bitmap = graphic_info[i].bitmap;
1771 int src_bitmap_width, src_bitmap_height;
1773 // now check if no animation frames are outside of the loaded image
1775 if (graphic_info[i].bitmap == NULL)
1776 continue; // skip check for optional images that are undefined
1778 // get image size (this can differ from the standard element tile size!)
1779 width = graphic_info[i].width;
1780 height = graphic_info[i].height;
1782 // get final bitmap size (with scaling, but without small images)
1783 src_bitmap_width = graphic_info[i].src_image_width;
1784 src_bitmap_height = graphic_info[i].src_image_height;
1786 // check if first animation frame is inside specified bitmap
1788 // do not use getGraphicSourceXY() here to get position of first frame;
1789 // this avoids calculating wrong start position for out-of-bounds frame
1790 src_x = graphic_info[i].src_x;
1791 src_y = graphic_info[i].src_y;
1793 if (program.headless)
1796 if (src_x < 0 || src_y < 0 ||
1797 src_x + width > src_bitmap_width ||
1798 src_y + height > src_bitmap_height)
1801 Warn("error found in config file:");
1802 Warn("- config file: '%s'", getImageConfigFilename());
1803 Warn("- config token: '%s'", getTokenFromImageID(i));
1804 Warn("- image file: '%s'", src_bitmap->source_filename);
1805 Warn("- frame size: %d, %d", width, height);
1806 Warn("error: first animation frame out of bounds (%d, %d) [%d, %d]",
1807 src_x, src_y, src_bitmap_width, src_bitmap_height);
1808 Warn("custom graphic rejected for this element/action");
1810 if (i == fallback_graphic)
1811 Error(ERR_EXIT, "no fallback graphic available");
1813 Warn("fallback done to 'char_exclam' for this graphic");
1816 graphic_info[i] = graphic_info[fallback_graphic];
1818 // if first frame out of bounds, do not check last frame anymore
1822 // check if last animation frame is inside specified bitmap
1824 last_frame = graphic_info[i].anim_frames - 1;
1825 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1827 if (src_x < 0 || src_y < 0 ||
1828 src_x + width > src_bitmap_width ||
1829 src_y + height > src_bitmap_height)
1832 Warn("error found in config file:");
1833 Warn("- config file: '%s'", getImageConfigFilename());
1834 Warn("- config token: '%s'", getTokenFromImageID(i));
1835 Warn("- image file: '%s'", src_bitmap->source_filename);
1836 Warn("- frame size: %d, %d", width, height);
1837 Warn("error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1838 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1839 Warn("custom graphic rejected for this element/action");
1841 if (i == fallback_graphic)
1842 Error(ERR_EXIT, "no fallback graphic available");
1844 Warn("fallback done to 'char_exclam' for this graphic");
1847 graphic_info[i] = graphic_info[fallback_graphic];
1852 static void InitGraphicCompatibilityInfo(void)
1854 struct FileInfo *fi_global_door =
1855 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1856 int num_images = getImageListSize();
1859 /* the following compatibility handling is needed for the following case:
1860 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1861 graphics mainly used for door and panel graphics, like editor, tape and
1862 in-game buttons with hard-coded bitmap positions and button sizes; as
1863 these graphics now have individual definitions, redefining "global.door"
1864 to change all these graphics at once like before does not work anymore
1865 (because all those individual definitions still have their default values);
1866 to solve this, remap all those individual definitions that are not
1867 redefined to the new bitmap of "global.door" if it was redefined */
1869 // special compatibility handling if image "global.door" was redefined
1870 if (fi_global_door->redefined)
1872 for (i = 0; i < num_images; i++)
1874 struct FileInfo *fi = getImageListEntryFromImageID(i);
1876 // process only those images that still use the default settings
1879 // process all images which default to same image as "global.door"
1880 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1882 // printf("::: special treatment needed for token '%s'\n", fi->token);
1884 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1885 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1891 InitGraphicCompatibilityInfo_Doors();
1894 static void InitElementSoundInfo(void)
1896 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1897 int num_property_mappings = getSoundListPropertyMappingSize();
1900 // set values to -1 to identify later as "uninitialized" values
1901 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1902 for (act = 0; act < NUM_ACTIONS; act++)
1903 element_info[i].sound[act] = -1;
1905 // initialize element/sound mapping from static configuration
1906 for (i = 0; element_to_sound[i].element > -1; i++)
1908 int element = element_to_sound[i].element;
1909 int action = element_to_sound[i].action;
1910 int sound = element_to_sound[i].sound;
1911 boolean is_class = element_to_sound[i].is_class;
1914 action = ACTION_DEFAULT;
1917 element_info[element].sound[action] = sound;
1919 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1920 if (strEqual(element_info[j].class_name,
1921 element_info[element].class_name))
1922 element_info[j].sound[action] = sound;
1925 // initialize element class/sound mapping from dynamic configuration
1926 for (i = 0; i < num_property_mappings; i++)
1928 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1929 int action = property_mapping[i].ext1_index;
1930 int sound = property_mapping[i].artwork_index;
1932 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1936 action = ACTION_DEFAULT;
1938 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1939 if (strEqual(element_info[j].class_name,
1940 element_info[element_class].class_name))
1941 element_info[j].sound[action] = sound;
1944 // initialize element/sound mapping from dynamic configuration
1945 for (i = 0; i < num_property_mappings; i++)
1947 int element = property_mapping[i].base_index;
1948 int action = property_mapping[i].ext1_index;
1949 int sound = property_mapping[i].artwork_index;
1951 if (element >= MAX_NUM_ELEMENTS)
1955 action = ACTION_DEFAULT;
1957 element_info[element].sound[action] = sound;
1960 // now set all '-1' values to element specific default values
1961 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1963 for (act = 0; act < NUM_ACTIONS; act++)
1965 // generic default action sound (defined by "[default]" directive)
1966 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1968 // look for special default action sound (classic game specific)
1969 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1970 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1971 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1972 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1973 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1974 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1975 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1976 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1978 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1979 // !!! make this better !!!
1980 if (i == EL_EMPTY_SPACE)
1981 default_action_sound = element_info[EL_DEFAULT].sound[act];
1983 // no sound for this specific action -- use default action sound
1984 if (element_info[i].sound[act] == -1)
1985 element_info[i].sound[act] = default_action_sound;
1989 // copy sound settings to some elements that are only stored in level file
1990 // in native R'n'D levels, but are used by game engine in native EM levels
1991 for (i = 0; copy_properties[i][0] != -1; i++)
1992 for (j = 1; j <= 4; j++)
1993 for (act = 0; act < NUM_ACTIONS; act++)
1994 element_info[copy_properties[i][j]].sound[act] =
1995 element_info[copy_properties[i][0]].sound[act];
1998 static void InitGameModeSoundInfo(void)
2002 // set values to -1 to identify later as "uninitialized" values
2003 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2006 // initialize gamemode/sound mapping from static configuration
2007 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2009 int gamemode = gamemode_to_sound[i].gamemode;
2010 int sound = gamemode_to_sound[i].sound;
2013 gamemode = GAME_MODE_DEFAULT;
2015 menu.sound[gamemode] = sound;
2018 // now set all '-1' values to levelset specific default values
2019 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2020 if (menu.sound[i] == -1)
2021 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2024 static void set_sound_parameters(int sound, char **parameter_raw)
2026 int parameter[NUM_SND_ARGS];
2029 // get integer values from string parameters
2030 for (i = 0; i < NUM_SND_ARGS; i++)
2032 get_parameter_value(parameter_raw[i],
2033 sound_config_suffix[i].token,
2034 sound_config_suffix[i].type);
2036 // explicit loop mode setting in configuration overrides default value
2037 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2038 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2040 // sound volume to change the original volume when loading the sound file
2041 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2043 // sound priority to give certain sounds a higher or lower priority
2044 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2047 static void InitSoundInfo(void)
2049 int *sound_effect_properties;
2050 int num_sounds = getSoundListSize();
2053 checked_free(sound_info);
2055 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2056 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2058 // initialize sound effect for all elements to "no sound"
2059 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2060 for (j = 0; j < NUM_ACTIONS; j++)
2061 element_info[i].sound[j] = SND_UNDEFINED;
2063 for (i = 0; i < num_sounds; i++)
2065 struct FileInfo *sound = getSoundListEntry(i);
2066 int len_effect_text = strlen(sound->token);
2068 sound_effect_properties[i] = ACTION_OTHER;
2069 sound_info[i].loop = FALSE; // default: play sound only once
2071 // determine all loop sounds and identify certain sound classes
2073 for (j = 0; element_action_info[j].suffix; j++)
2075 int len_action_text = strlen(element_action_info[j].suffix);
2077 if (len_action_text < len_effect_text &&
2078 strEqual(&sound->token[len_effect_text - len_action_text],
2079 element_action_info[j].suffix))
2081 sound_effect_properties[i] = element_action_info[j].value;
2082 sound_info[i].loop = element_action_info[j].is_loop_sound;
2088 // associate elements and some selected sound actions
2090 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2092 if (element_info[j].class_name)
2094 int len_class_text = strlen(element_info[j].class_name);
2096 if (len_class_text + 1 < len_effect_text &&
2097 strncmp(sound->token,
2098 element_info[j].class_name, len_class_text) == 0 &&
2099 sound->token[len_class_text] == '.')
2101 int sound_action_value = sound_effect_properties[i];
2103 element_info[j].sound[sound_action_value] = i;
2108 set_sound_parameters(i, sound->parameter);
2111 free(sound_effect_properties);
2114 static void InitGameModeMusicInfo(void)
2116 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2117 int num_property_mappings = getMusicListPropertyMappingSize();
2118 int default_levelset_music = -1;
2121 // set values to -1 to identify later as "uninitialized" values
2122 for (i = 0; i < MAX_LEVELS; i++)
2123 levelset.music[i] = -1;
2124 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2127 // initialize gamemode/music mapping from static configuration
2128 for (i = 0; gamemode_to_music[i].music > -1; i++)
2130 int gamemode = gamemode_to_music[i].gamemode;
2131 int music = gamemode_to_music[i].music;
2134 gamemode = GAME_MODE_DEFAULT;
2136 menu.music[gamemode] = music;
2139 // initialize gamemode/music mapping from dynamic configuration
2140 for (i = 0; i < num_property_mappings; i++)
2142 int prefix = property_mapping[i].base_index;
2143 int gamemode = property_mapping[i].ext2_index;
2144 int level = property_mapping[i].ext3_index;
2145 int music = property_mapping[i].artwork_index;
2147 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2151 gamemode = GAME_MODE_DEFAULT;
2153 // level specific music only allowed for in-game music
2154 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2155 gamemode = GAME_MODE_PLAYING;
2160 default_levelset_music = music;
2163 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2164 levelset.music[level] = music;
2165 if (gamemode != GAME_MODE_PLAYING)
2166 menu.music[gamemode] = music;
2169 // now set all '-1' values to menu specific default values
2170 // (undefined values of "levelset.music[]" might stay at "-1" to
2171 // allow dynamic selection of music files from music directory!)
2172 for (i = 0; i < MAX_LEVELS; i++)
2173 if (levelset.music[i] == -1)
2174 levelset.music[i] = default_levelset_music;
2175 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2176 if (menu.music[i] == -1)
2177 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2180 static void set_music_parameters(int music, char **parameter_raw)
2182 int parameter[NUM_MUS_ARGS];
2185 // get integer values from string parameters
2186 for (i = 0; i < NUM_MUS_ARGS; i++)
2188 get_parameter_value(parameter_raw[i],
2189 music_config_suffix[i].token,
2190 music_config_suffix[i].type);
2192 // explicit loop mode setting in configuration overrides default value
2193 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2194 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2197 static void InitMusicInfo(void)
2199 int num_music = getMusicListSize();
2202 checked_free(music_info);
2204 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2206 for (i = 0; i < num_music; i++)
2208 struct FileInfo *music = getMusicListEntry(i);
2209 int len_music_text = strlen(music->token);
2211 music_info[i].loop = TRUE; // default: play music in loop mode
2213 // determine all loop music
2215 for (j = 0; music_prefix_info[j].prefix; j++)
2217 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2219 if (len_prefix_text < len_music_text &&
2220 strncmp(music->token,
2221 music_prefix_info[j].prefix, len_prefix_text) == 0)
2223 music_info[i].loop = music_prefix_info[j].is_loop_music;
2229 set_music_parameters(i, music->parameter);
2233 static void ReinitializeGraphics(void)
2235 print_timestamp_init("ReinitializeGraphics");
2237 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2239 InitGraphicInfo(); // graphic properties mapping
2240 print_timestamp_time("InitGraphicInfo");
2241 InitElementGraphicInfo(); // element game graphic mapping
2242 print_timestamp_time("InitElementGraphicInfo");
2243 InitElementSpecialGraphicInfo(); // element special graphic mapping
2244 print_timestamp_time("InitElementSpecialGraphicInfo");
2246 InitElementSmallImages(); // scale elements to all needed sizes
2247 print_timestamp_time("InitElementSmallImages");
2248 InitScaledImages(); // scale all other images, if needed
2249 print_timestamp_time("InitScaledImages");
2250 InitBitmapPointers(); // set standard size bitmap pointers
2251 print_timestamp_time("InitBitmapPointers");
2252 InitFontGraphicInfo(); // initialize text drawing functions
2253 print_timestamp_time("InitFontGraphicInfo");
2254 InitGlobalAnimGraphicInfo(); // initialize global animation config
2255 print_timestamp_time("InitGlobalAnimGraphicInfo");
2257 InitImageTextures(); // create textures for certain images
2258 print_timestamp_time("InitImageTextures");
2260 InitGraphicInfo_EM(); // graphic mapping for EM engine
2261 print_timestamp_time("InitGraphicInfo_EM");
2263 InitGraphicCompatibilityInfo();
2264 print_timestamp_time("InitGraphicCompatibilityInfo");
2266 SetMainBackgroundImage(IMG_BACKGROUND);
2267 print_timestamp_time("SetMainBackgroundImage");
2268 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2269 print_timestamp_time("SetDoorBackgroundImage");
2272 print_timestamp_time("InitGadgets");
2274 print_timestamp_time("InitDoors");
2276 print_timestamp_done("ReinitializeGraphics");
2279 static void ReinitializeSounds(void)
2281 InitSoundInfo(); // sound properties mapping
2282 InitElementSoundInfo(); // element game sound mapping
2283 InitGameModeSoundInfo(); // game mode sound mapping
2284 InitGlobalAnimSoundInfo(); // global animation sound settings
2286 InitPlayLevelSound(); // internal game sound settings
2289 static void ReinitializeMusic(void)
2291 InitMusicInfo(); // music properties mapping
2292 InitGameModeMusicInfo(); // game mode music mapping
2293 InitGlobalAnimMusicInfo(); // global animation music settings
2296 static int get_special_property_bit(int element, int property_bit_nr)
2298 struct PropertyBitInfo
2304 static struct PropertyBitInfo pb_can_move_into_acid[] =
2306 // the player may be able fall into acid when gravity is activated
2311 { EL_SP_MURPHY, 0 },
2312 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2314 // all elements that can move may be able to also move into acid
2317 { EL_BUG_RIGHT, 1 },
2320 { EL_SPACESHIP, 2 },
2321 { EL_SPACESHIP_LEFT, 2 },
2322 { EL_SPACESHIP_RIGHT, 2 },
2323 { EL_SPACESHIP_UP, 2 },
2324 { EL_SPACESHIP_DOWN, 2 },
2325 { EL_BD_BUTTERFLY, 3 },
2326 { EL_BD_BUTTERFLY_LEFT, 3 },
2327 { EL_BD_BUTTERFLY_RIGHT, 3 },
2328 { EL_BD_BUTTERFLY_UP, 3 },
2329 { EL_BD_BUTTERFLY_DOWN, 3 },
2330 { EL_BD_FIREFLY, 4 },
2331 { EL_BD_FIREFLY_LEFT, 4 },
2332 { EL_BD_FIREFLY_RIGHT, 4 },
2333 { EL_BD_FIREFLY_UP, 4 },
2334 { EL_BD_FIREFLY_DOWN, 4 },
2336 { EL_YAMYAM_LEFT, 5 },
2337 { EL_YAMYAM_RIGHT, 5 },
2338 { EL_YAMYAM_UP, 5 },
2339 { EL_YAMYAM_DOWN, 5 },
2340 { EL_DARK_YAMYAM, 6 },
2343 { EL_PACMAN_LEFT, 8 },
2344 { EL_PACMAN_RIGHT, 8 },
2345 { EL_PACMAN_UP, 8 },
2346 { EL_PACMAN_DOWN, 8 },
2348 { EL_MOLE_LEFT, 9 },
2349 { EL_MOLE_RIGHT, 9 },
2351 { EL_MOLE_DOWN, 9 },
2355 { EL_SATELLITE, 13 },
2356 { EL_SP_SNIKSNAK, 14 },
2357 { EL_SP_ELECTRON, 15 },
2360 { EL_SPRING_LEFT, 17 },
2361 { EL_SPRING_RIGHT, 17 },
2362 { EL_EMC_ANDROID, 18 },
2367 static struct PropertyBitInfo pb_dont_collide_with[] =
2369 { EL_SP_SNIKSNAK, 0 },
2370 { EL_SP_ELECTRON, 1 },
2378 struct PropertyBitInfo *pb_info;
2381 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2382 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2387 struct PropertyBitInfo *pb_info = NULL;
2390 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2391 if (pb_definition[i].bit_nr == property_bit_nr)
2392 pb_info = pb_definition[i].pb_info;
2394 if (pb_info == NULL)
2397 for (i = 0; pb_info[i].element != -1; i++)
2398 if (pb_info[i].element == element)
2399 return pb_info[i].bit_nr;
2404 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2405 boolean property_value)
2407 int bit_nr = get_special_property_bit(element, property_bit_nr);
2412 *bitfield |= (1 << bit_nr);
2414 *bitfield &= ~(1 << bit_nr);
2418 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2420 int bit_nr = get_special_property_bit(element, property_bit_nr);
2423 return ((*bitfield & (1 << bit_nr)) != 0);
2428 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2430 static int group_nr;
2431 static struct ElementGroupInfo *group;
2432 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2435 if (actual_group == NULL) // not yet initialized
2438 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2440 Warn("recursion too deep when resolving group element %d",
2441 group_element - EL_GROUP_START + 1);
2443 // replace element which caused too deep recursion by question mark
2444 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2449 if (recursion_depth == 0) // initialization
2451 group = actual_group;
2452 group_nr = GROUP_NR(group_element);
2454 group->num_elements_resolved = 0;
2455 group->choice_pos = 0;
2457 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2458 element_info[i].in_group[group_nr] = FALSE;
2461 for (i = 0; i < actual_group->num_elements; i++)
2463 int element = actual_group->element[i];
2465 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2468 if (IS_GROUP_ELEMENT(element))
2469 ResolveGroupElementExt(element, recursion_depth + 1);
2472 group->element_resolved[group->num_elements_resolved++] = element;
2473 element_info[element].in_group[group_nr] = TRUE;
2478 void ResolveGroupElement(int group_element)
2480 ResolveGroupElementExt(group_element, 0);
2483 void InitElementPropertiesStatic(void)
2485 static boolean clipboard_elements_initialized = FALSE;
2487 static int ep_diggable[] =
2492 EL_SP_BUGGY_BASE_ACTIVATING,
2495 EL_INVISIBLE_SAND_ACTIVE,
2498 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2499 // (if amoeba can grow into anything diggable, maybe keep these out)
2504 EL_SP_BUGGY_BASE_ACTIVE,
2511 static int ep_collectible_only[] =
2533 EL_DYNABOMB_INCREASE_NUMBER,
2534 EL_DYNABOMB_INCREASE_SIZE,
2535 EL_DYNABOMB_INCREASE_POWER,
2553 // !!! handle separately !!!
2554 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2560 static int ep_dont_run_into[] =
2562 // same elements as in 'ep_dont_touch'
2568 // same elements as in 'ep_dont_collide_with'
2580 // !!! maybe this should better be handled by 'ep_diggable' !!!
2585 EL_SP_BUGGY_BASE_ACTIVE,
2592 static int ep_dont_collide_with[] =
2594 // same elements as in 'ep_dont_touch'
2611 static int ep_dont_touch[] =
2621 static int ep_indestructible[] =
2625 EL_ACID_POOL_TOPLEFT,
2626 EL_ACID_POOL_TOPRIGHT,
2627 EL_ACID_POOL_BOTTOMLEFT,
2628 EL_ACID_POOL_BOTTOM,
2629 EL_ACID_POOL_BOTTOMRIGHT,
2630 EL_SP_HARDWARE_GRAY,
2631 EL_SP_HARDWARE_GREEN,
2632 EL_SP_HARDWARE_BLUE,
2634 EL_SP_HARDWARE_YELLOW,
2635 EL_SP_HARDWARE_BASE_1,
2636 EL_SP_HARDWARE_BASE_2,
2637 EL_SP_HARDWARE_BASE_3,
2638 EL_SP_HARDWARE_BASE_4,
2639 EL_SP_HARDWARE_BASE_5,
2640 EL_SP_HARDWARE_BASE_6,
2641 EL_INVISIBLE_STEELWALL,
2642 EL_INVISIBLE_STEELWALL_ACTIVE,
2643 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2644 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2645 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2646 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2647 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2648 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2649 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2650 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2651 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2652 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2653 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2654 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2656 EL_LIGHT_SWITCH_ACTIVE,
2657 EL_SIGN_EXCLAMATION,
2658 EL_SIGN_RADIOACTIVITY,
2665 EL_SIGN_ENTRY_FORBIDDEN,
2666 EL_SIGN_EMERGENCY_EXIT,
2674 EL_STEEL_EXIT_CLOSED,
2676 EL_STEEL_EXIT_OPENING,
2677 EL_STEEL_EXIT_CLOSING,
2678 EL_EM_STEEL_EXIT_CLOSED,
2679 EL_EM_STEEL_EXIT_OPEN,
2680 EL_EM_STEEL_EXIT_OPENING,
2681 EL_EM_STEEL_EXIT_CLOSING,
2682 EL_DC_STEELWALL_1_LEFT,
2683 EL_DC_STEELWALL_1_RIGHT,
2684 EL_DC_STEELWALL_1_TOP,
2685 EL_DC_STEELWALL_1_BOTTOM,
2686 EL_DC_STEELWALL_1_HORIZONTAL,
2687 EL_DC_STEELWALL_1_VERTICAL,
2688 EL_DC_STEELWALL_1_TOPLEFT,
2689 EL_DC_STEELWALL_1_TOPRIGHT,
2690 EL_DC_STEELWALL_1_BOTTOMLEFT,
2691 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2692 EL_DC_STEELWALL_1_TOPLEFT_2,
2693 EL_DC_STEELWALL_1_TOPRIGHT_2,
2694 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2695 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2696 EL_DC_STEELWALL_2_LEFT,
2697 EL_DC_STEELWALL_2_RIGHT,
2698 EL_DC_STEELWALL_2_TOP,
2699 EL_DC_STEELWALL_2_BOTTOM,
2700 EL_DC_STEELWALL_2_HORIZONTAL,
2701 EL_DC_STEELWALL_2_VERTICAL,
2702 EL_DC_STEELWALL_2_MIDDLE,
2703 EL_DC_STEELWALL_2_SINGLE,
2704 EL_STEELWALL_SLIPPERY,
2718 EL_GATE_1_GRAY_ACTIVE,
2719 EL_GATE_2_GRAY_ACTIVE,
2720 EL_GATE_3_GRAY_ACTIVE,
2721 EL_GATE_4_GRAY_ACTIVE,
2730 EL_EM_GATE_1_GRAY_ACTIVE,
2731 EL_EM_GATE_2_GRAY_ACTIVE,
2732 EL_EM_GATE_3_GRAY_ACTIVE,
2733 EL_EM_GATE_4_GRAY_ACTIVE,
2742 EL_EMC_GATE_5_GRAY_ACTIVE,
2743 EL_EMC_GATE_6_GRAY_ACTIVE,
2744 EL_EMC_GATE_7_GRAY_ACTIVE,
2745 EL_EMC_GATE_8_GRAY_ACTIVE,
2747 EL_DC_GATE_WHITE_GRAY,
2748 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2749 EL_DC_GATE_FAKE_GRAY,
2751 EL_SWITCHGATE_OPENING,
2752 EL_SWITCHGATE_CLOSED,
2753 EL_SWITCHGATE_CLOSING,
2754 EL_DC_SWITCHGATE_SWITCH_UP,
2755 EL_DC_SWITCHGATE_SWITCH_DOWN,
2757 EL_TIMEGATE_OPENING,
2759 EL_TIMEGATE_CLOSING,
2760 EL_DC_TIMEGATE_SWITCH,
2761 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2765 EL_TUBE_VERTICAL_LEFT,
2766 EL_TUBE_VERTICAL_RIGHT,
2767 EL_TUBE_HORIZONTAL_UP,
2768 EL_TUBE_HORIZONTAL_DOWN,
2773 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2774 EL_EXPANDABLE_STEELWALL_VERTICAL,
2775 EL_EXPANDABLE_STEELWALL_ANY,
2780 static int ep_slippery[] =
2794 EL_ROBOT_WHEEL_ACTIVE,
2800 EL_ACID_POOL_TOPLEFT,
2801 EL_ACID_POOL_TOPRIGHT,
2811 EL_STEELWALL_SLIPPERY,
2814 EL_EMC_WALL_SLIPPERY_1,
2815 EL_EMC_WALL_SLIPPERY_2,
2816 EL_EMC_WALL_SLIPPERY_3,
2817 EL_EMC_WALL_SLIPPERY_4,
2819 EL_EMC_MAGIC_BALL_ACTIVE,
2824 static int ep_can_change[] =
2829 static int ep_can_move[] =
2831 // same elements as in 'pb_can_move_into_acid'
2854 static int ep_can_fall[] =
2869 EL_QUICKSAND_FAST_FULL,
2871 EL_BD_MAGIC_WALL_FULL,
2872 EL_DC_MAGIC_WALL_FULL,
2886 static int ep_can_smash_player[] =
2912 static int ep_can_smash_enemies[] =
2921 static int ep_can_smash_everything[] =
2930 static int ep_explodes_by_fire[] =
2932 // same elements as in 'ep_explodes_impact'
2937 // same elements as in 'ep_explodes_smashed'
2947 EL_EM_DYNAMITE_ACTIVE,
2948 EL_DYNABOMB_PLAYER_1_ACTIVE,
2949 EL_DYNABOMB_PLAYER_2_ACTIVE,
2950 EL_DYNABOMB_PLAYER_3_ACTIVE,
2951 EL_DYNABOMB_PLAYER_4_ACTIVE,
2952 EL_DYNABOMB_INCREASE_NUMBER,
2953 EL_DYNABOMB_INCREASE_SIZE,
2954 EL_DYNABOMB_INCREASE_POWER,
2955 EL_SP_DISK_RED_ACTIVE,
2969 static int ep_explodes_smashed[] =
2971 // same elements as in 'ep_explodes_impact'
2985 static int ep_explodes_impact[] =
2994 static int ep_walkable_over[] =
2998 EL_SOKOBAN_FIELD_EMPTY,
3005 EL_EM_STEEL_EXIT_OPEN,
3006 EL_EM_STEEL_EXIT_OPENING,
3015 EL_GATE_1_GRAY_ACTIVE,
3016 EL_GATE_2_GRAY_ACTIVE,
3017 EL_GATE_3_GRAY_ACTIVE,
3018 EL_GATE_4_GRAY_ACTIVE,
3026 static int ep_walkable_inside[] =
3031 EL_TUBE_VERTICAL_LEFT,
3032 EL_TUBE_VERTICAL_RIGHT,
3033 EL_TUBE_HORIZONTAL_UP,
3034 EL_TUBE_HORIZONTAL_DOWN,
3043 static int ep_walkable_under[] =
3048 static int ep_passable_over[] =
3058 EL_EM_GATE_1_GRAY_ACTIVE,
3059 EL_EM_GATE_2_GRAY_ACTIVE,
3060 EL_EM_GATE_3_GRAY_ACTIVE,
3061 EL_EM_GATE_4_GRAY_ACTIVE,
3070 EL_EMC_GATE_5_GRAY_ACTIVE,
3071 EL_EMC_GATE_6_GRAY_ACTIVE,
3072 EL_EMC_GATE_7_GRAY_ACTIVE,
3073 EL_EMC_GATE_8_GRAY_ACTIVE,
3075 EL_DC_GATE_WHITE_GRAY,
3076 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3083 static int ep_passable_inside[] =
3089 EL_SP_PORT_HORIZONTAL,
3090 EL_SP_PORT_VERTICAL,
3092 EL_SP_GRAVITY_PORT_LEFT,
3093 EL_SP_GRAVITY_PORT_RIGHT,
3094 EL_SP_GRAVITY_PORT_UP,
3095 EL_SP_GRAVITY_PORT_DOWN,
3096 EL_SP_GRAVITY_ON_PORT_LEFT,
3097 EL_SP_GRAVITY_ON_PORT_RIGHT,
3098 EL_SP_GRAVITY_ON_PORT_UP,
3099 EL_SP_GRAVITY_ON_PORT_DOWN,
3100 EL_SP_GRAVITY_OFF_PORT_LEFT,
3101 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3102 EL_SP_GRAVITY_OFF_PORT_UP,
3103 EL_SP_GRAVITY_OFF_PORT_DOWN,
3108 static int ep_passable_under[] =
3113 static int ep_droppable[] =
3118 static int ep_explodes_1x1_old[] =
3123 static int ep_pushable[] =
3135 EL_SOKOBAN_FIELD_FULL,
3144 static int ep_explodes_cross_old[] =
3149 static int ep_protected[] =
3151 // same elements as in 'ep_walkable_inside'
3155 EL_TUBE_VERTICAL_LEFT,
3156 EL_TUBE_VERTICAL_RIGHT,
3157 EL_TUBE_HORIZONTAL_UP,
3158 EL_TUBE_HORIZONTAL_DOWN,
3164 // same elements as in 'ep_passable_over'
3173 EL_EM_GATE_1_GRAY_ACTIVE,
3174 EL_EM_GATE_2_GRAY_ACTIVE,
3175 EL_EM_GATE_3_GRAY_ACTIVE,
3176 EL_EM_GATE_4_GRAY_ACTIVE,
3185 EL_EMC_GATE_5_GRAY_ACTIVE,
3186 EL_EMC_GATE_6_GRAY_ACTIVE,
3187 EL_EMC_GATE_7_GRAY_ACTIVE,
3188 EL_EMC_GATE_8_GRAY_ACTIVE,
3190 EL_DC_GATE_WHITE_GRAY,
3191 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3195 // same elements as in 'ep_passable_inside'
3200 EL_SP_PORT_HORIZONTAL,
3201 EL_SP_PORT_VERTICAL,
3203 EL_SP_GRAVITY_PORT_LEFT,
3204 EL_SP_GRAVITY_PORT_RIGHT,
3205 EL_SP_GRAVITY_PORT_UP,
3206 EL_SP_GRAVITY_PORT_DOWN,
3207 EL_SP_GRAVITY_ON_PORT_LEFT,
3208 EL_SP_GRAVITY_ON_PORT_RIGHT,
3209 EL_SP_GRAVITY_ON_PORT_UP,
3210 EL_SP_GRAVITY_ON_PORT_DOWN,
3211 EL_SP_GRAVITY_OFF_PORT_LEFT,
3212 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3213 EL_SP_GRAVITY_OFF_PORT_UP,
3214 EL_SP_GRAVITY_OFF_PORT_DOWN,
3219 static int ep_throwable[] =
3224 static int ep_can_explode[] =
3226 // same elements as in 'ep_explodes_impact'
3231 // same elements as in 'ep_explodes_smashed'
3237 // elements that can explode by explosion or by dragonfire
3241 EL_EM_DYNAMITE_ACTIVE,
3242 EL_DYNABOMB_PLAYER_1_ACTIVE,
3243 EL_DYNABOMB_PLAYER_2_ACTIVE,
3244 EL_DYNABOMB_PLAYER_3_ACTIVE,
3245 EL_DYNABOMB_PLAYER_4_ACTIVE,
3246 EL_DYNABOMB_INCREASE_NUMBER,
3247 EL_DYNABOMB_INCREASE_SIZE,
3248 EL_DYNABOMB_INCREASE_POWER,
3249 EL_SP_DISK_RED_ACTIVE,
3257 // elements that can explode only by explosion
3263 static int ep_gravity_reachable[] =
3269 EL_INVISIBLE_SAND_ACTIVE,
3274 EL_SP_PORT_HORIZONTAL,
3275 EL_SP_PORT_VERTICAL,
3277 EL_SP_GRAVITY_PORT_LEFT,
3278 EL_SP_GRAVITY_PORT_RIGHT,
3279 EL_SP_GRAVITY_PORT_UP,
3280 EL_SP_GRAVITY_PORT_DOWN,
3281 EL_SP_GRAVITY_ON_PORT_LEFT,
3282 EL_SP_GRAVITY_ON_PORT_RIGHT,
3283 EL_SP_GRAVITY_ON_PORT_UP,
3284 EL_SP_GRAVITY_ON_PORT_DOWN,
3285 EL_SP_GRAVITY_OFF_PORT_LEFT,
3286 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3287 EL_SP_GRAVITY_OFF_PORT_UP,
3288 EL_SP_GRAVITY_OFF_PORT_DOWN,
3294 static int ep_player[] =
3301 EL_SOKOBAN_FIELD_PLAYER,
3307 static int ep_can_pass_magic_wall[] =
3321 static int ep_can_pass_dc_magic_wall[] =
3337 static int ep_switchable[] =
3341 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3342 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3343 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3344 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3345 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3346 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3347 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3348 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3349 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3350 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3351 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3352 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3353 EL_SWITCHGATE_SWITCH_UP,
3354 EL_SWITCHGATE_SWITCH_DOWN,
3355 EL_DC_SWITCHGATE_SWITCH_UP,
3356 EL_DC_SWITCHGATE_SWITCH_DOWN,
3358 EL_LIGHT_SWITCH_ACTIVE,
3360 EL_DC_TIMEGATE_SWITCH,
3361 EL_BALLOON_SWITCH_LEFT,
3362 EL_BALLOON_SWITCH_RIGHT,
3363 EL_BALLOON_SWITCH_UP,
3364 EL_BALLOON_SWITCH_DOWN,
3365 EL_BALLOON_SWITCH_ANY,
3366 EL_BALLOON_SWITCH_NONE,
3369 EL_EMC_MAGIC_BALL_SWITCH,
3370 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3375 static int ep_bd_element[] =
3409 static int ep_sp_element[] =
3411 // should always be valid
3414 // standard classic Supaplex elements
3421 EL_SP_HARDWARE_GRAY,
3429 EL_SP_GRAVITY_PORT_RIGHT,
3430 EL_SP_GRAVITY_PORT_DOWN,
3431 EL_SP_GRAVITY_PORT_LEFT,
3432 EL_SP_GRAVITY_PORT_UP,
3437 EL_SP_PORT_VERTICAL,
3438 EL_SP_PORT_HORIZONTAL,
3444 EL_SP_HARDWARE_BASE_1,
3445 EL_SP_HARDWARE_GREEN,
3446 EL_SP_HARDWARE_BLUE,
3448 EL_SP_HARDWARE_YELLOW,
3449 EL_SP_HARDWARE_BASE_2,
3450 EL_SP_HARDWARE_BASE_3,
3451 EL_SP_HARDWARE_BASE_4,
3452 EL_SP_HARDWARE_BASE_5,
3453 EL_SP_HARDWARE_BASE_6,
3457 // additional elements that appeared in newer Supaplex levels
3460 // additional gravity port elements (not switching, but setting gravity)
3461 EL_SP_GRAVITY_ON_PORT_LEFT,
3462 EL_SP_GRAVITY_ON_PORT_RIGHT,
3463 EL_SP_GRAVITY_ON_PORT_UP,
3464 EL_SP_GRAVITY_ON_PORT_DOWN,
3465 EL_SP_GRAVITY_OFF_PORT_LEFT,
3466 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3467 EL_SP_GRAVITY_OFF_PORT_UP,
3468 EL_SP_GRAVITY_OFF_PORT_DOWN,
3470 // more than one Murphy in a level results in an inactive clone
3473 // runtime Supaplex elements
3474 EL_SP_DISK_RED_ACTIVE,
3475 EL_SP_TERMINAL_ACTIVE,
3476 EL_SP_BUGGY_BASE_ACTIVATING,
3477 EL_SP_BUGGY_BASE_ACTIVE,
3484 static int ep_sb_element[] =
3489 EL_SOKOBAN_FIELD_EMPTY,
3490 EL_SOKOBAN_FIELD_FULL,
3491 EL_SOKOBAN_FIELD_PLAYER,
3496 EL_INVISIBLE_STEELWALL,
3501 static int ep_gem[] =
3513 static int ep_food_dark_yamyam[] =
3541 static int ep_food_penguin[] =
3555 static int ep_food_pig[] =
3567 static int ep_historic_wall[] =
3578 EL_GATE_1_GRAY_ACTIVE,
3579 EL_GATE_2_GRAY_ACTIVE,
3580 EL_GATE_3_GRAY_ACTIVE,
3581 EL_GATE_4_GRAY_ACTIVE,
3590 EL_EM_GATE_1_GRAY_ACTIVE,
3591 EL_EM_GATE_2_GRAY_ACTIVE,
3592 EL_EM_GATE_3_GRAY_ACTIVE,
3593 EL_EM_GATE_4_GRAY_ACTIVE,
3600 EL_EXPANDABLE_WALL_HORIZONTAL,
3601 EL_EXPANDABLE_WALL_VERTICAL,
3602 EL_EXPANDABLE_WALL_ANY,
3603 EL_EXPANDABLE_WALL_GROWING,
3604 EL_BD_EXPANDABLE_WALL,
3611 EL_SP_HARDWARE_GRAY,
3612 EL_SP_HARDWARE_GREEN,
3613 EL_SP_HARDWARE_BLUE,
3615 EL_SP_HARDWARE_YELLOW,
3616 EL_SP_HARDWARE_BASE_1,
3617 EL_SP_HARDWARE_BASE_2,
3618 EL_SP_HARDWARE_BASE_3,
3619 EL_SP_HARDWARE_BASE_4,
3620 EL_SP_HARDWARE_BASE_5,
3621 EL_SP_HARDWARE_BASE_6,
3623 EL_SP_TERMINAL_ACTIVE,
3626 EL_INVISIBLE_STEELWALL,
3627 EL_INVISIBLE_STEELWALL_ACTIVE,
3629 EL_INVISIBLE_WALL_ACTIVE,
3630 EL_STEELWALL_SLIPPERY,
3647 static int ep_historic_solid[] =
3651 EL_EXPANDABLE_WALL_HORIZONTAL,
3652 EL_EXPANDABLE_WALL_VERTICAL,
3653 EL_EXPANDABLE_WALL_ANY,
3654 EL_BD_EXPANDABLE_WALL,
3667 EL_QUICKSAND_FILLING,
3668 EL_QUICKSAND_EMPTYING,
3670 EL_MAGIC_WALL_ACTIVE,
3671 EL_MAGIC_WALL_EMPTYING,
3672 EL_MAGIC_WALL_FILLING,
3676 EL_BD_MAGIC_WALL_ACTIVE,
3677 EL_BD_MAGIC_WALL_EMPTYING,
3678 EL_BD_MAGIC_WALL_FULL,
3679 EL_BD_MAGIC_WALL_FILLING,
3680 EL_BD_MAGIC_WALL_DEAD,
3689 EL_SP_TERMINAL_ACTIVE,
3693 EL_INVISIBLE_WALL_ACTIVE,
3694 EL_SWITCHGATE_SWITCH_UP,
3695 EL_SWITCHGATE_SWITCH_DOWN,
3697 EL_TIMEGATE_SWITCH_ACTIVE,
3709 // the following elements are a direct copy of "indestructible" elements,
3710 // except "EL_ACID", which is "indestructible", but not "solid"!
3715 EL_ACID_POOL_TOPLEFT,
3716 EL_ACID_POOL_TOPRIGHT,
3717 EL_ACID_POOL_BOTTOMLEFT,
3718 EL_ACID_POOL_BOTTOM,
3719 EL_ACID_POOL_BOTTOMRIGHT,
3720 EL_SP_HARDWARE_GRAY,
3721 EL_SP_HARDWARE_GREEN,
3722 EL_SP_HARDWARE_BLUE,
3724 EL_SP_HARDWARE_YELLOW,
3725 EL_SP_HARDWARE_BASE_1,
3726 EL_SP_HARDWARE_BASE_2,
3727 EL_SP_HARDWARE_BASE_3,
3728 EL_SP_HARDWARE_BASE_4,
3729 EL_SP_HARDWARE_BASE_5,
3730 EL_SP_HARDWARE_BASE_6,
3731 EL_INVISIBLE_STEELWALL,
3732 EL_INVISIBLE_STEELWALL_ACTIVE,
3733 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3734 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3735 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3736 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3737 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3738 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3739 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3740 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3741 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3742 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3743 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3744 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3746 EL_LIGHT_SWITCH_ACTIVE,
3747 EL_SIGN_EXCLAMATION,
3748 EL_SIGN_RADIOACTIVITY,
3755 EL_SIGN_ENTRY_FORBIDDEN,
3756 EL_SIGN_EMERGENCY_EXIT,
3764 EL_STEEL_EXIT_CLOSED,
3766 EL_STEEL_EXIT_OPENING,
3767 EL_STEEL_EXIT_CLOSING,
3768 EL_EM_STEEL_EXIT_CLOSED,
3769 EL_EM_STEEL_EXIT_OPEN,
3770 EL_EM_STEEL_EXIT_OPENING,
3771 EL_EM_STEEL_EXIT_CLOSING,
3772 EL_DC_STEELWALL_1_LEFT,
3773 EL_DC_STEELWALL_1_RIGHT,
3774 EL_DC_STEELWALL_1_TOP,
3775 EL_DC_STEELWALL_1_BOTTOM,
3776 EL_DC_STEELWALL_1_HORIZONTAL,
3777 EL_DC_STEELWALL_1_VERTICAL,
3778 EL_DC_STEELWALL_1_TOPLEFT,
3779 EL_DC_STEELWALL_1_TOPRIGHT,
3780 EL_DC_STEELWALL_1_BOTTOMLEFT,
3781 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3782 EL_DC_STEELWALL_1_TOPLEFT_2,
3783 EL_DC_STEELWALL_1_TOPRIGHT_2,
3784 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3785 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3786 EL_DC_STEELWALL_2_LEFT,
3787 EL_DC_STEELWALL_2_RIGHT,
3788 EL_DC_STEELWALL_2_TOP,
3789 EL_DC_STEELWALL_2_BOTTOM,
3790 EL_DC_STEELWALL_2_HORIZONTAL,
3791 EL_DC_STEELWALL_2_VERTICAL,
3792 EL_DC_STEELWALL_2_MIDDLE,
3793 EL_DC_STEELWALL_2_SINGLE,
3794 EL_STEELWALL_SLIPPERY,
3808 EL_GATE_1_GRAY_ACTIVE,
3809 EL_GATE_2_GRAY_ACTIVE,
3810 EL_GATE_3_GRAY_ACTIVE,
3811 EL_GATE_4_GRAY_ACTIVE,
3820 EL_EM_GATE_1_GRAY_ACTIVE,
3821 EL_EM_GATE_2_GRAY_ACTIVE,
3822 EL_EM_GATE_3_GRAY_ACTIVE,
3823 EL_EM_GATE_4_GRAY_ACTIVE,
3832 EL_EMC_GATE_5_GRAY_ACTIVE,
3833 EL_EMC_GATE_6_GRAY_ACTIVE,
3834 EL_EMC_GATE_7_GRAY_ACTIVE,
3835 EL_EMC_GATE_8_GRAY_ACTIVE,
3837 EL_DC_GATE_WHITE_GRAY,
3838 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3839 EL_DC_GATE_FAKE_GRAY,
3841 EL_SWITCHGATE_OPENING,
3842 EL_SWITCHGATE_CLOSED,
3843 EL_SWITCHGATE_CLOSING,
3844 EL_DC_SWITCHGATE_SWITCH_UP,
3845 EL_DC_SWITCHGATE_SWITCH_DOWN,
3847 EL_TIMEGATE_OPENING,
3849 EL_TIMEGATE_CLOSING,
3850 EL_DC_TIMEGATE_SWITCH,
3851 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3855 EL_TUBE_VERTICAL_LEFT,
3856 EL_TUBE_VERTICAL_RIGHT,
3857 EL_TUBE_HORIZONTAL_UP,
3858 EL_TUBE_HORIZONTAL_DOWN,
3863 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3864 EL_EXPANDABLE_STEELWALL_VERTICAL,
3865 EL_EXPANDABLE_STEELWALL_ANY,
3870 static int ep_classic_enemy[] =
3887 static int ep_belt[] =
3889 EL_CONVEYOR_BELT_1_LEFT,
3890 EL_CONVEYOR_BELT_1_MIDDLE,
3891 EL_CONVEYOR_BELT_1_RIGHT,
3892 EL_CONVEYOR_BELT_2_LEFT,
3893 EL_CONVEYOR_BELT_2_MIDDLE,
3894 EL_CONVEYOR_BELT_2_RIGHT,
3895 EL_CONVEYOR_BELT_3_LEFT,
3896 EL_CONVEYOR_BELT_3_MIDDLE,
3897 EL_CONVEYOR_BELT_3_RIGHT,
3898 EL_CONVEYOR_BELT_4_LEFT,
3899 EL_CONVEYOR_BELT_4_MIDDLE,
3900 EL_CONVEYOR_BELT_4_RIGHT,
3905 static int ep_belt_active[] =
3907 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3908 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3909 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3910 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3911 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3912 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3913 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3914 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3915 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3916 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3917 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3918 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3923 static int ep_belt_switch[] =
3925 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3926 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3927 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3928 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3929 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3930 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3931 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3932 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3933 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3934 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3935 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3936 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3941 static int ep_tube[] =
3948 EL_TUBE_HORIZONTAL_UP,
3949 EL_TUBE_HORIZONTAL_DOWN,
3951 EL_TUBE_VERTICAL_LEFT,
3952 EL_TUBE_VERTICAL_RIGHT,
3958 static int ep_acid_pool[] =
3960 EL_ACID_POOL_TOPLEFT,
3961 EL_ACID_POOL_TOPRIGHT,
3962 EL_ACID_POOL_BOTTOMLEFT,
3963 EL_ACID_POOL_BOTTOM,
3964 EL_ACID_POOL_BOTTOMRIGHT,
3969 static int ep_keygate[] =
3979 EL_GATE_1_GRAY_ACTIVE,
3980 EL_GATE_2_GRAY_ACTIVE,
3981 EL_GATE_3_GRAY_ACTIVE,
3982 EL_GATE_4_GRAY_ACTIVE,
3991 EL_EM_GATE_1_GRAY_ACTIVE,
3992 EL_EM_GATE_2_GRAY_ACTIVE,
3993 EL_EM_GATE_3_GRAY_ACTIVE,
3994 EL_EM_GATE_4_GRAY_ACTIVE,
4003 EL_EMC_GATE_5_GRAY_ACTIVE,
4004 EL_EMC_GATE_6_GRAY_ACTIVE,
4005 EL_EMC_GATE_7_GRAY_ACTIVE,
4006 EL_EMC_GATE_8_GRAY_ACTIVE,
4008 EL_DC_GATE_WHITE_GRAY,
4009 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4014 static int ep_amoeboid[] =
4026 static int ep_amoebalive[] =
4037 static int ep_has_editor_content[] =
4043 EL_SOKOBAN_FIELD_PLAYER,
4060 static int ep_can_turn_each_move[] =
4062 // !!! do something with this one !!!
4066 static int ep_can_grow[] =
4080 static int ep_active_bomb[] =
4083 EL_EM_DYNAMITE_ACTIVE,
4084 EL_DYNABOMB_PLAYER_1_ACTIVE,
4085 EL_DYNABOMB_PLAYER_2_ACTIVE,
4086 EL_DYNABOMB_PLAYER_3_ACTIVE,
4087 EL_DYNABOMB_PLAYER_4_ACTIVE,
4088 EL_SP_DISK_RED_ACTIVE,
4093 static int ep_inactive[] =
4103 EL_QUICKSAND_FAST_EMPTY,
4126 EL_GATE_1_GRAY_ACTIVE,
4127 EL_GATE_2_GRAY_ACTIVE,
4128 EL_GATE_3_GRAY_ACTIVE,
4129 EL_GATE_4_GRAY_ACTIVE,
4138 EL_EM_GATE_1_GRAY_ACTIVE,
4139 EL_EM_GATE_2_GRAY_ACTIVE,
4140 EL_EM_GATE_3_GRAY_ACTIVE,
4141 EL_EM_GATE_4_GRAY_ACTIVE,
4150 EL_EMC_GATE_5_GRAY_ACTIVE,
4151 EL_EMC_GATE_6_GRAY_ACTIVE,
4152 EL_EMC_GATE_7_GRAY_ACTIVE,
4153 EL_EMC_GATE_8_GRAY_ACTIVE,
4155 EL_DC_GATE_WHITE_GRAY,
4156 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4157 EL_DC_GATE_FAKE_GRAY,
4160 EL_INVISIBLE_STEELWALL,
4168 EL_WALL_EMERALD_YELLOW,
4169 EL_DYNABOMB_INCREASE_NUMBER,
4170 EL_DYNABOMB_INCREASE_SIZE,
4171 EL_DYNABOMB_INCREASE_POWER,
4175 EL_SOKOBAN_FIELD_EMPTY,
4176 EL_SOKOBAN_FIELD_FULL,
4177 EL_WALL_EMERALD_RED,
4178 EL_WALL_EMERALD_PURPLE,
4179 EL_ACID_POOL_TOPLEFT,
4180 EL_ACID_POOL_TOPRIGHT,
4181 EL_ACID_POOL_BOTTOMLEFT,
4182 EL_ACID_POOL_BOTTOM,
4183 EL_ACID_POOL_BOTTOMRIGHT,
4187 EL_BD_MAGIC_WALL_DEAD,
4189 EL_DC_MAGIC_WALL_DEAD,
4190 EL_AMOEBA_TO_DIAMOND,
4198 EL_SP_GRAVITY_PORT_RIGHT,
4199 EL_SP_GRAVITY_PORT_DOWN,
4200 EL_SP_GRAVITY_PORT_LEFT,
4201 EL_SP_GRAVITY_PORT_UP,
4202 EL_SP_PORT_HORIZONTAL,
4203 EL_SP_PORT_VERTICAL,
4214 EL_SP_HARDWARE_GRAY,
4215 EL_SP_HARDWARE_GREEN,
4216 EL_SP_HARDWARE_BLUE,
4218 EL_SP_HARDWARE_YELLOW,
4219 EL_SP_HARDWARE_BASE_1,
4220 EL_SP_HARDWARE_BASE_2,
4221 EL_SP_HARDWARE_BASE_3,
4222 EL_SP_HARDWARE_BASE_4,
4223 EL_SP_HARDWARE_BASE_5,
4224 EL_SP_HARDWARE_BASE_6,
4225 EL_SP_GRAVITY_ON_PORT_LEFT,
4226 EL_SP_GRAVITY_ON_PORT_RIGHT,
4227 EL_SP_GRAVITY_ON_PORT_UP,
4228 EL_SP_GRAVITY_ON_PORT_DOWN,
4229 EL_SP_GRAVITY_OFF_PORT_LEFT,
4230 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4231 EL_SP_GRAVITY_OFF_PORT_UP,
4232 EL_SP_GRAVITY_OFF_PORT_DOWN,
4233 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4234 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4235 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4236 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4237 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4238 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4239 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4240 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4241 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4242 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4243 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4244 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4245 EL_SIGN_EXCLAMATION,
4246 EL_SIGN_RADIOACTIVITY,
4253 EL_SIGN_ENTRY_FORBIDDEN,
4254 EL_SIGN_EMERGENCY_EXIT,
4262 EL_DC_STEELWALL_1_LEFT,
4263 EL_DC_STEELWALL_1_RIGHT,
4264 EL_DC_STEELWALL_1_TOP,
4265 EL_DC_STEELWALL_1_BOTTOM,
4266 EL_DC_STEELWALL_1_HORIZONTAL,
4267 EL_DC_STEELWALL_1_VERTICAL,
4268 EL_DC_STEELWALL_1_TOPLEFT,
4269 EL_DC_STEELWALL_1_TOPRIGHT,
4270 EL_DC_STEELWALL_1_BOTTOMLEFT,
4271 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4272 EL_DC_STEELWALL_1_TOPLEFT_2,
4273 EL_DC_STEELWALL_1_TOPRIGHT_2,
4274 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4275 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4276 EL_DC_STEELWALL_2_LEFT,
4277 EL_DC_STEELWALL_2_RIGHT,
4278 EL_DC_STEELWALL_2_TOP,
4279 EL_DC_STEELWALL_2_BOTTOM,
4280 EL_DC_STEELWALL_2_HORIZONTAL,
4281 EL_DC_STEELWALL_2_VERTICAL,
4282 EL_DC_STEELWALL_2_MIDDLE,
4283 EL_DC_STEELWALL_2_SINGLE,
4284 EL_STEELWALL_SLIPPERY,
4289 EL_EMC_WALL_SLIPPERY_1,
4290 EL_EMC_WALL_SLIPPERY_2,
4291 EL_EMC_WALL_SLIPPERY_3,
4292 EL_EMC_WALL_SLIPPERY_4,
4313 static int ep_em_slippery_wall[] =
4318 static int ep_gfx_crumbled[] =
4329 static int ep_editor_cascade_active[] =
4331 EL_INTERNAL_CASCADE_BD_ACTIVE,
4332 EL_INTERNAL_CASCADE_EM_ACTIVE,
4333 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4334 EL_INTERNAL_CASCADE_RND_ACTIVE,
4335 EL_INTERNAL_CASCADE_SB_ACTIVE,
4336 EL_INTERNAL_CASCADE_SP_ACTIVE,
4337 EL_INTERNAL_CASCADE_DC_ACTIVE,
4338 EL_INTERNAL_CASCADE_DX_ACTIVE,
4339 EL_INTERNAL_CASCADE_MM_ACTIVE,
4340 EL_INTERNAL_CASCADE_DF_ACTIVE,
4341 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4342 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4343 EL_INTERNAL_CASCADE_CE_ACTIVE,
4344 EL_INTERNAL_CASCADE_GE_ACTIVE,
4345 EL_INTERNAL_CASCADE_REF_ACTIVE,
4346 EL_INTERNAL_CASCADE_USER_ACTIVE,
4347 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4352 static int ep_editor_cascade_inactive[] =
4354 EL_INTERNAL_CASCADE_BD,
4355 EL_INTERNAL_CASCADE_EM,
4356 EL_INTERNAL_CASCADE_EMC,
4357 EL_INTERNAL_CASCADE_RND,
4358 EL_INTERNAL_CASCADE_SB,
4359 EL_INTERNAL_CASCADE_SP,
4360 EL_INTERNAL_CASCADE_DC,
4361 EL_INTERNAL_CASCADE_DX,
4362 EL_INTERNAL_CASCADE_MM,
4363 EL_INTERNAL_CASCADE_DF,
4364 EL_INTERNAL_CASCADE_CHARS,
4365 EL_INTERNAL_CASCADE_STEEL_CHARS,
4366 EL_INTERNAL_CASCADE_CE,
4367 EL_INTERNAL_CASCADE_GE,
4368 EL_INTERNAL_CASCADE_REF,
4369 EL_INTERNAL_CASCADE_USER,
4370 EL_INTERNAL_CASCADE_DYNAMIC,
4375 static int ep_obsolete[] =
4379 EL_EM_KEY_1_FILE_OBSOLETE,
4380 EL_EM_KEY_2_FILE_OBSOLETE,
4381 EL_EM_KEY_3_FILE_OBSOLETE,
4382 EL_EM_KEY_4_FILE_OBSOLETE,
4383 EL_ENVELOPE_OBSOLETE,
4392 } element_properties[] =
4394 { ep_diggable, EP_DIGGABLE },
4395 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4396 { ep_dont_run_into, EP_DONT_RUN_INTO },
4397 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4398 { ep_dont_touch, EP_DONT_TOUCH },
4399 { ep_indestructible, EP_INDESTRUCTIBLE },
4400 { ep_slippery, EP_SLIPPERY },
4401 { ep_can_change, EP_CAN_CHANGE },
4402 { ep_can_move, EP_CAN_MOVE },
4403 { ep_can_fall, EP_CAN_FALL },
4404 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4405 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4406 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4407 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4408 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4409 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4410 { ep_walkable_over, EP_WALKABLE_OVER },
4411 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4412 { ep_walkable_under, EP_WALKABLE_UNDER },
4413 { ep_passable_over, EP_PASSABLE_OVER },
4414 { ep_passable_inside, EP_PASSABLE_INSIDE },
4415 { ep_passable_under, EP_PASSABLE_UNDER },
4416 { ep_droppable, EP_DROPPABLE },
4417 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4418 { ep_pushable, EP_PUSHABLE },
4419 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4420 { ep_protected, EP_PROTECTED },
4421 { ep_throwable, EP_THROWABLE },
4422 { ep_can_explode, EP_CAN_EXPLODE },
4423 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4425 { ep_player, EP_PLAYER },
4426 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4427 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4428 { ep_switchable, EP_SWITCHABLE },
4429 { ep_bd_element, EP_BD_ELEMENT },
4430 { ep_sp_element, EP_SP_ELEMENT },
4431 { ep_sb_element, EP_SB_ELEMENT },
4433 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4434 { ep_food_penguin, EP_FOOD_PENGUIN },
4435 { ep_food_pig, EP_FOOD_PIG },
4436 { ep_historic_wall, EP_HISTORIC_WALL },
4437 { ep_historic_solid, EP_HISTORIC_SOLID },
4438 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4439 { ep_belt, EP_BELT },
4440 { ep_belt_active, EP_BELT_ACTIVE },
4441 { ep_belt_switch, EP_BELT_SWITCH },
4442 { ep_tube, EP_TUBE },
4443 { ep_acid_pool, EP_ACID_POOL },
4444 { ep_keygate, EP_KEYGATE },
4445 { ep_amoeboid, EP_AMOEBOID },
4446 { ep_amoebalive, EP_AMOEBALIVE },
4447 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4448 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4449 { ep_can_grow, EP_CAN_GROW },
4450 { ep_active_bomb, EP_ACTIVE_BOMB },
4451 { ep_inactive, EP_INACTIVE },
4453 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4455 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4457 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4458 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4460 { ep_obsolete, EP_OBSOLETE },
4467 // always start with reliable default values (element has no properties)
4468 // (but never initialize clipboard elements after the very first time)
4469 // (to be able to use clipboard elements between several levels)
4470 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4471 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4472 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4473 SET_PROPERTY(i, j, FALSE);
4475 // set all base element properties from above array definitions
4476 for (i = 0; element_properties[i].elements != NULL; i++)
4477 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4478 SET_PROPERTY((element_properties[i].elements)[j],
4479 element_properties[i].property, TRUE);
4481 // copy properties to some elements that are only stored in level file
4482 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4483 for (j = 0; copy_properties[j][0] != -1; j++)
4484 if (HAS_PROPERTY(copy_properties[j][0], i))
4485 for (k = 1; k <= 4; k++)
4486 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4488 // set static element properties that are not listed in array definitions
4489 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4490 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4492 clipboard_elements_initialized = TRUE;
4495 void InitElementPropertiesEngine(int engine_version)
4497 static int no_wall_properties[] =
4500 EP_COLLECTIBLE_ONLY,
4502 EP_DONT_COLLIDE_WITH,
4505 EP_CAN_SMASH_PLAYER,
4506 EP_CAN_SMASH_ENEMIES,
4507 EP_CAN_SMASH_EVERYTHING,
4512 EP_FOOD_DARK_YAMYAM,
4528 /* important: after initialization in InitElementPropertiesStatic(), the
4529 elements are not again initialized to a default value; therefore all
4530 changes have to make sure that they leave the element with a defined
4531 property (which means that conditional property changes must be set to
4532 a reliable default value before) */
4534 // resolve group elements
4535 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4536 ResolveGroupElement(EL_GROUP_START + i);
4538 // set all special, combined or engine dependent element properties
4539 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4541 // do not change (already initialized) clipboard elements here
4542 if (IS_CLIPBOARD_ELEMENT(i))
4545 // ---------- INACTIVE ----------------------------------------------------
4546 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4547 i <= EL_CHAR_END) ||
4548 (i >= EL_STEEL_CHAR_START &&
4549 i <= EL_STEEL_CHAR_END)));
4551 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4552 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4553 IS_WALKABLE_INSIDE(i) ||
4554 IS_WALKABLE_UNDER(i)));
4556 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4557 IS_PASSABLE_INSIDE(i) ||
4558 IS_PASSABLE_UNDER(i)));
4560 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4561 IS_PASSABLE_OVER(i)));
4563 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4564 IS_PASSABLE_INSIDE(i)));
4566 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4567 IS_PASSABLE_UNDER(i)));
4569 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4572 // ---------- COLLECTIBLE -------------------------------------------------
4573 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4577 // ---------- SNAPPABLE ---------------------------------------------------
4578 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4579 IS_COLLECTIBLE(i) ||
4583 // ---------- WALL --------------------------------------------------------
4584 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4586 for (j = 0; no_wall_properties[j] != -1; j++)
4587 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4588 i >= EL_FIRST_RUNTIME_UNREAL)
4589 SET_PROPERTY(i, EP_WALL, FALSE);
4591 if (IS_HISTORIC_WALL(i))
4592 SET_PROPERTY(i, EP_WALL, TRUE);
4594 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4595 if (engine_version < VERSION_IDENT(2,2,0,0))
4596 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4598 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4600 !IS_COLLECTIBLE(i)));
4602 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4603 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4604 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4606 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4609 // ---------- EXPLOSION_PROOF ---------------------------------------------
4611 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4612 else if (engine_version < VERSION_IDENT(2,2,0,0))
4613 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4615 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4619 if (IS_CUSTOM_ELEMENT(i))
4621 // these are additional properties which are initially false when set
4623 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4625 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4626 if (DONT_COLLIDE_WITH(i))
4627 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4629 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4630 if (CAN_SMASH_EVERYTHING(i))
4631 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4632 if (CAN_SMASH_ENEMIES(i))
4633 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4636 // ---------- CAN_SMASH ---------------------------------------------------
4637 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4638 CAN_SMASH_ENEMIES(i) ||
4639 CAN_SMASH_EVERYTHING(i)));
4641 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4642 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4643 EXPLODES_BY_FIRE(i)));
4645 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4646 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4647 EXPLODES_SMASHED(i)));
4649 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4650 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4651 EXPLODES_IMPACT(i)));
4653 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4654 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4656 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4657 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4658 i == EL_BLACK_ORB));
4660 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4661 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4663 IS_CUSTOM_ELEMENT(i)));
4665 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4666 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4667 i == EL_SP_ELECTRON));
4669 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4670 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4671 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4672 getMoveIntoAcidProperty(&level, i));
4674 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4675 if (MAYBE_DONT_COLLIDE_WITH(i))
4676 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4677 getDontCollideWithProperty(&level, i));
4679 // ---------- SP_PORT -----------------------------------------------------
4680 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4681 IS_PASSABLE_INSIDE(i)));
4683 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4684 for (j = 0; j < level.num_android_clone_elements; j++)
4685 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4687 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4689 // ---------- CAN_CHANGE --------------------------------------------------
4690 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4691 for (j = 0; j < element_info[i].num_change_pages; j++)
4692 if (element_info[i].change_page[j].can_change)
4693 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4695 // ---------- HAS_ACTION --------------------------------------------------
4696 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4697 for (j = 0; j < element_info[i].num_change_pages; j++)
4698 if (element_info[i].change_page[j].has_action)
4699 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4701 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4702 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4705 // ---------- GFX_CRUMBLED ------------------------------------------------
4706 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4707 element_info[i].crumbled[ACTION_DEFAULT] !=
4708 element_info[i].graphic[ACTION_DEFAULT]);
4710 // ---------- EDITOR_CASCADE ----------------------------------------------
4711 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4712 IS_EDITOR_CASCADE_INACTIVE(i)));
4715 // dynamically adjust element properties according to game engine version
4717 static int ep_em_slippery_wall[] =
4722 EL_EXPANDABLE_WALL_HORIZONTAL,
4723 EL_EXPANDABLE_WALL_VERTICAL,
4724 EL_EXPANDABLE_WALL_ANY,
4725 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4726 EL_EXPANDABLE_STEELWALL_VERTICAL,
4727 EL_EXPANDABLE_STEELWALL_ANY,
4728 EL_EXPANDABLE_STEELWALL_GROWING,
4732 static int ep_em_explodes_by_fire[] =
4735 EL_EM_DYNAMITE_ACTIVE,
4740 // special EM style gems behaviour
4741 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4742 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4743 level.em_slippery_gems);
4745 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4746 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4747 (level.em_slippery_gems &&
4748 engine_version > VERSION_IDENT(2,0,1,0)));
4750 // special EM style explosion behaviour regarding chain reactions
4751 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4752 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4753 level.em_explodes_by_fire);
4756 // this is needed because some graphics depend on element properties
4757 if (game_status == GAME_MODE_PLAYING)
4758 InitElementGraphicInfo();
4761 void InitElementPropertiesGfxElement(void)
4765 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4767 struct ElementInfo *ei = &element_info[i];
4769 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4773 static void InitGlobal(void)
4778 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4780 // check if element_name_info entry defined for each element in "main.h"
4781 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4782 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4784 element_info[i].token_name = element_name_info[i].token_name;
4785 element_info[i].class_name = element_name_info[i].class_name;
4786 element_info[i].editor_description= element_name_info[i].editor_description;
4789 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4791 // check if global_anim_name_info defined for each entry in "main.h"
4792 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4793 global_anim_name_info[i].token_name == NULL)
4794 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4796 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4799 // create hash from image config list
4800 image_config_hash = newSetupFileHash();
4801 for (i = 0; image_config[i].token != NULL; i++)
4802 setHashEntry(image_config_hash,
4803 image_config[i].token,
4804 image_config[i].value);
4806 // create hash from element token list
4807 element_token_hash = newSetupFileHash();
4808 for (i = 0; element_name_info[i].token_name != NULL; i++)
4809 setHashEntry(element_token_hash,
4810 element_name_info[i].token_name,
4813 // create hash from graphic token list
4814 graphic_token_hash = newSetupFileHash();
4815 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4816 if (strSuffix(image_config[i].value, ".png") ||
4817 strSuffix(image_config[i].value, ".pcx") ||
4818 strSuffix(image_config[i].value, ".wav") ||
4819 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4820 setHashEntry(graphic_token_hash,
4821 image_config[i].token,
4822 int2str(graphic++, 0));
4824 // create hash from font token list
4825 font_token_hash = newSetupFileHash();
4826 for (i = 0; font_info[i].token_name != NULL; i++)
4827 setHashEntry(font_token_hash,
4828 font_info[i].token_name,
4831 // set default filenames for all cloned graphics in static configuration
4832 for (i = 0; image_config[i].token != NULL; i++)
4834 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4836 char *token = image_config[i].token;
4837 char *token_clone_from = getStringCat2(token, ".clone_from");
4838 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4840 if (token_cloned != NULL)
4842 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4844 if (value_cloned != NULL)
4846 // set default filename in static configuration
4847 image_config[i].value = value_cloned;
4849 // set default filename in image config hash
4850 setHashEntry(image_config_hash, token, value_cloned);
4854 free(token_clone_from);
4858 // always start with reliable default values (all elements)
4859 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4860 ActiveElement[i] = i;
4862 // now add all entries that have an active state (active elements)
4863 for (i = 0; element_with_active_state[i].element != -1; i++)
4865 int element = element_with_active_state[i].element;
4866 int element_active = element_with_active_state[i].element_active;
4868 ActiveElement[element] = element_active;
4871 // always start with reliable default values (all buttons)
4872 for (i = 0; i < NUM_IMAGE_FILES; i++)
4873 ActiveButton[i] = i;
4875 // now add all entries that have an active state (active buttons)
4876 for (i = 0; button_with_active_state[i].button != -1; i++)
4878 int button = button_with_active_state[i].button;
4879 int button_active = button_with_active_state[i].button_active;
4881 ActiveButton[button] = button_active;
4884 // always start with reliable default values (all fonts)
4885 for (i = 0; i < NUM_FONTS; i++)
4888 // now add all entries that have an active state (active fonts)
4889 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4891 int font = font_with_active_state[i].font_nr;
4892 int font_active = font_with_active_state[i].font_nr_active;
4894 ActiveFont[font] = font_active;
4897 global.autoplay_leveldir = NULL;
4898 global.patchtapes_leveldir = NULL;
4899 global.convert_leveldir = NULL;
4900 global.create_images_dir = NULL;
4902 global.frames_per_second = 0;
4903 global.show_frames_per_second = FALSE;
4905 global.border_status = GAME_MODE_LOADING;
4906 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4908 global.use_envelope_request = FALSE;
4911 static void Execute_Command(char *command)
4915 if (strEqual(command, "print graphicsinfo.conf"))
4917 Print("# You can configure additional/alternative image files here.\n");
4918 Print("# (The entries below are default and therefore commented out.)\n");
4920 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4922 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4925 for (i = 0; image_config[i].token != NULL; i++)
4926 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4927 image_config[i].value));
4931 else if (strEqual(command, "print soundsinfo.conf"))
4933 Print("# You can configure additional/alternative sound files here.\n");
4934 Print("# (The entries below are default and therefore commented out.)\n");
4936 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4938 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4941 for (i = 0; sound_config[i].token != NULL; i++)
4942 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4943 sound_config[i].value));
4947 else if (strEqual(command, "print musicinfo.conf"))
4949 Print("# You can configure additional/alternative music files here.\n");
4950 Print("# (The entries below are default and therefore commented out.)\n");
4952 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4954 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4957 for (i = 0; music_config[i].token != NULL; i++)
4958 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4959 music_config[i].value));
4963 else if (strEqual(command, "print editorsetup.conf"))
4965 Print("# You can configure your personal editor element list here.\n");
4966 Print("# (The entries below are default and therefore commented out.)\n");
4969 // this is needed to be able to check element list for cascade elements
4970 InitElementPropertiesStatic();
4971 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4973 PrintEditorElementList();
4977 else if (strEqual(command, "print helpanim.conf"))
4979 Print("# You can configure different element help animations here.\n");
4980 Print("# (The entries below are default and therefore commented out.)\n");
4983 for (i = 0; helpanim_config[i].token != NULL; i++)
4985 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4986 helpanim_config[i].value));
4988 if (strEqual(helpanim_config[i].token, "end"))
4994 else if (strEqual(command, "print helptext.conf"))
4996 Print("# You can configure different element help text here.\n");
4997 Print("# (The entries below are default and therefore commented out.)\n");
5000 for (i = 0; helptext_config[i].token != NULL; i++)
5001 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5002 helptext_config[i].value));
5006 else if (strPrefix(command, "dump level "))
5008 char *filename = &command[11];
5010 if (!fileExists(filename))
5011 Error(ERR_EXIT, "cannot open file '%s'", filename);
5013 LoadLevelFromFilename(&level, filename);
5018 else if (strPrefix(command, "dump tape "))
5020 char *filename = &command[10];
5022 if (!fileExists(filename))
5023 Error(ERR_EXIT, "cannot open file '%s'", filename);
5025 LoadTapeFromFilename(filename);
5030 else if (strPrefix(command, "autoplay ") ||
5031 strPrefix(command, "autoffwd ") ||
5032 strPrefix(command, "autowarp ") ||
5033 strPrefix(command, "autotest ") ||
5034 strPrefix(command, "autofix "))
5036 char *str_ptr = getStringCopy(&command[8]); // read command parameters
5038 global.autoplay_mode =
5039 (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5040 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5041 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5042 strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5043 strPrefix(command, "autofix") ? AUTOPLAY_MODE_FIX :
5044 AUTOPLAY_MODE_NONE);
5046 while (*str_ptr != '\0') // continue parsing string
5048 // cut leading whitespace from string, replace it by string terminator
5049 while (*str_ptr == ' ' || *str_ptr == '\t')
5052 if (*str_ptr == '\0') // end of string reached
5055 if (global.autoplay_leveldir == NULL) // read level set string
5057 global.autoplay_leveldir = str_ptr;
5058 global.autoplay_all = TRUE; // default: play all tapes
5060 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5061 global.autoplay_level[i] = FALSE;
5063 else // read level number string
5065 int level_nr = atoi(str_ptr); // get level_nr value
5067 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5068 global.autoplay_level[level_nr] = TRUE;
5070 global.autoplay_all = FALSE;
5073 // advance string pointer to the next whitespace (or end of string)
5074 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5078 if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
5079 program.headless = TRUE;
5081 else if (strPrefix(command, "patch tapes "))
5083 char *str_ptr = getStringCopy(&command[12]); // read command parameters
5085 // skip leading whitespace
5086 while (*str_ptr == ' ' || *str_ptr == '\t')
5089 if (*str_ptr == '\0')
5090 Error(ERR_EXIT, "cannot find MODE in command '%s'", command);
5092 global.patchtapes_mode = str_ptr; // store patch mode
5094 // advance to next whitespace (or end of string)
5095 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5098 while (*str_ptr != '\0') // continue parsing string
5100 // cut leading whitespace from string, replace it by string terminator
5101 while (*str_ptr == ' ' || *str_ptr == '\t')
5104 if (*str_ptr == '\0') // end of string reached
5107 if (global.patchtapes_leveldir == NULL) // read level set string
5109 global.patchtapes_leveldir = str_ptr;
5110 global.patchtapes_all = TRUE; // default: patch all tapes
5112 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5113 global.patchtapes_level[i] = FALSE;
5115 else // read level number string
5117 int level_nr = atoi(str_ptr); // get level_nr value
5119 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5120 global.patchtapes_level[level_nr] = TRUE;
5122 global.patchtapes_all = FALSE;
5125 // advance string pointer to the next whitespace (or end of string)
5126 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5130 if (global.patchtapes_leveldir == NULL)
5132 if (strEqual(global.patchtapes_mode, "help"))
5133 global.patchtapes_leveldir = UNDEFINED_LEVELSET;
5135 Error(ERR_EXIT, "cannot find LEVELDIR in command '%s'", command);
5138 program.headless = TRUE;
5140 else if (strPrefix(command, "convert "))
5142 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5143 char *str_ptr = strchr(str_copy, ' ');
5145 global.convert_leveldir = str_copy;
5146 global.convert_level_nr = -1;
5148 if (str_ptr != NULL) // level number follows
5150 *str_ptr++ = '\0'; // terminate leveldir string
5151 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5154 program.headless = TRUE;
5156 else if (strPrefix(command, "create images "))
5158 global.create_images_dir = getStringCopy(&command[14]);
5160 if (access(global.create_images_dir, W_OK) != 0)
5161 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5162 global.create_images_dir);
5164 else if (strPrefix(command, "create CE image "))
5166 CreateCustomElementImages(&command[16]);
5172 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5175 // disable networking if any valid command was recognized
5176 options.network = setup.network_mode = FALSE;
5179 static void InitSetup(void)
5181 LoadSetup(); // global setup info
5182 LoadSetup_AutoSetup(); // global auto setup info
5184 // set some options from setup file
5186 if (setup.options.verbose)
5187 options.verbose = TRUE;
5189 if (setup.debug.show_frames_per_second)
5190 global.show_frames_per_second = TRUE;
5193 static void InitGameInfo(void)
5195 game.restart_level = FALSE;
5196 game.restart_game_message = NULL;
5197 game.request_active = FALSE;
5200 static void InitPlayerInfo(void)
5204 // choose default local player
5205 local_player = &stored_player[0];
5207 for (i = 0; i < MAX_PLAYERS; i++)
5209 stored_player[i].connected_locally = FALSE;
5210 stored_player[i].connected_network = FALSE;
5213 local_player->connected_locally = TRUE;
5216 static void InitArtworkInfo(void)
5221 static char *get_string_in_brackets(char *string)
5223 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5225 sprintf(string_in_brackets, "[%s]", string);
5227 return string_in_brackets;
5230 static char *get_level_id_suffix(int id_nr)
5232 char *id_suffix = checked_malloc(1 + 3 + 1);
5234 if (id_nr < 0 || id_nr > 999)
5237 sprintf(id_suffix, ".%03d", id_nr);
5242 static void InitArtworkConfig(void)
5244 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5246 NUM_GLOBAL_ANIM_TOKENS + 1];
5247 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5248 NUM_GLOBAL_ANIM_TOKENS + 1];
5249 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5250 NUM_GLOBAL_ANIM_TOKENS + 1];
5251 static char *action_id_suffix[NUM_ACTIONS + 1];
5252 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5253 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5254 static char *level_id_suffix[MAX_LEVELS + 1];
5255 static char *dummy[1] = { NULL };
5256 static char *ignore_generic_tokens[] =
5261 "program_copyright",
5266 static char **ignore_image_tokens;
5267 static char **ignore_sound_tokens;
5268 static char **ignore_music_tokens;
5269 int num_ignore_generic_tokens;
5270 int num_ignore_image_tokens;
5271 int num_ignore_sound_tokens;
5272 int num_ignore_music_tokens;
5275 // dynamically determine list of generic tokens to be ignored
5276 num_ignore_generic_tokens = 0;
5277 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5278 num_ignore_generic_tokens++;
5280 // dynamically determine list of image tokens to be ignored
5281 num_ignore_image_tokens = num_ignore_generic_tokens;
5282 for (i = 0; image_config_vars[i].token != NULL; i++)
5283 num_ignore_image_tokens++;
5284 ignore_image_tokens =
5285 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5286 for (i = 0; i < num_ignore_generic_tokens; i++)
5287 ignore_image_tokens[i] = ignore_generic_tokens[i];
5288 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5289 ignore_image_tokens[num_ignore_generic_tokens + i] =
5290 image_config_vars[i].token;
5291 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5293 // dynamically determine list of sound tokens to be ignored
5294 num_ignore_sound_tokens = num_ignore_generic_tokens;
5295 ignore_sound_tokens =
5296 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5297 for (i = 0; i < num_ignore_generic_tokens; i++)
5298 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5299 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5301 // dynamically determine list of music tokens to be ignored
5302 num_ignore_music_tokens = num_ignore_generic_tokens;
5303 ignore_music_tokens =
5304 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5305 for (i = 0; i < num_ignore_generic_tokens; i++)
5306 ignore_music_tokens[i] = ignore_generic_tokens[i];
5307 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5309 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5310 image_id_prefix[i] = element_info[i].token_name;
5311 for (i = 0; i < NUM_FONTS; i++)
5312 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5313 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5314 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5315 global_anim_info[i].token_name;
5316 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5318 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5319 sound_id_prefix[i] = element_info[i].token_name;
5320 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5321 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5322 get_string_in_brackets(element_info[i].class_name);
5323 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5324 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5325 global_anim_info[i].token_name;
5326 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5328 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5329 music_id_prefix[i] = music_prefix_info[i].prefix;
5330 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5331 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5332 global_anim_info[i].token_name;
5333 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5335 for (i = 0; i < NUM_ACTIONS; i++)
5336 action_id_suffix[i] = element_action_info[i].suffix;
5337 action_id_suffix[NUM_ACTIONS] = NULL;
5339 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5340 direction_id_suffix[i] = element_direction_info[i].suffix;
5341 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5343 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5344 special_id_suffix[i] = special_suffix_info[i].suffix;
5345 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5347 for (i = 0; i < MAX_LEVELS; i++)
5348 level_id_suffix[i] = get_level_id_suffix(i);
5349 level_id_suffix[MAX_LEVELS] = NULL;
5351 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5352 image_id_prefix, action_id_suffix, direction_id_suffix,
5353 special_id_suffix, ignore_image_tokens);
5354 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5355 sound_id_prefix, action_id_suffix, dummy,
5356 special_id_suffix, ignore_sound_tokens);
5357 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5358 music_id_prefix, action_id_suffix, special_id_suffix,
5359 level_id_suffix, ignore_music_tokens);
5362 static void InitMixer(void)
5369 static void InitVideoOverlay(void)
5371 // if virtual buttons are not loaded from setup file, repeat initializing
5372 // virtual buttons grid with default values now that video is initialized
5373 if (!setup.touch.grid_initialized)
5376 InitTileCursorInfo();
5380 void InitGfxBuffers(void)
5382 static int win_xsize_last = -1;
5383 static int win_ysize_last = -1;
5385 // create additional image buffers for double-buffering and cross-fading
5387 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5389 // used to temporarily store the backbuffer -- only re-create if changed
5390 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5391 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5393 win_xsize_last = WIN_XSIZE;
5394 win_ysize_last = WIN_YSIZE;
5397 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5398 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5399 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5400 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5402 // initialize screen properties
5403 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5404 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5406 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5407 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5408 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5409 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5410 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5411 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5413 // required if door size definitions have changed
5414 InitGraphicCompatibilityInfo_Doors();
5416 InitGfxBuffers_EM();
5417 InitGfxBuffers_SP();
5420 static void InitGfx(void)
5422 struct GraphicInfo *graphic_info_last = graphic_info;
5423 char *filename_font_initial = NULL;
5424 char *filename_anim_initial = NULL;
5425 Bitmap *bitmap_font_initial = NULL;
5428 // determine settings for initial font (for displaying startup messages)
5429 for (i = 0; image_config[i].token != NULL; i++)
5431 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5433 char font_token[128];
5436 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5437 len_font_token = strlen(font_token);
5439 if (strEqual(image_config[i].token, font_token))
5440 filename_font_initial = image_config[i].value;
5441 else if (strlen(image_config[i].token) > len_font_token &&
5442 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5444 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5445 font_initial[j].src_x = atoi(image_config[i].value);
5446 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5447 font_initial[j].src_y = atoi(image_config[i].value);
5448 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5449 font_initial[j].width = atoi(image_config[i].value);
5450 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5451 font_initial[j].height = atoi(image_config[i].value);
5456 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5458 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5459 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5462 if (filename_font_initial == NULL) // should not happen
5463 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5466 InitGfxCustomArtworkInfo();
5467 InitGfxOtherSettings();
5469 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5471 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5472 font_initial[j].bitmap = bitmap_font_initial;
5474 InitFontGraphicInfo();
5478 DrawInitText("Loading graphics", 120, FC_GREEN);
5480 // initialize settings for busy animation with default values
5481 int parameter[NUM_GFX_ARGS];
5482 for (i = 0; i < NUM_GFX_ARGS; i++)
5483 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5484 image_config_suffix[i].token,
5485 image_config_suffix[i].type);
5487 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5488 int len_anim_token = strlen(anim_token);
5490 // read settings for busy animation from default custom artwork config
5491 char *gfx_config_filename = getPath3(options.graphics_directory,
5493 GRAPHICSINFO_FILENAME);
5495 if (fileExists(gfx_config_filename))
5497 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5499 if (setup_file_hash)
5501 char *filename = getHashEntry(setup_file_hash, anim_token);
5505 filename_anim_initial = getStringCopy(filename);
5507 for (j = 0; image_config_suffix[j].token != NULL; j++)
5509 int type = image_config_suffix[j].type;
5510 char *suffix = image_config_suffix[j].token;
5511 char *token = getStringCat2(anim_token, suffix);
5512 char *value = getHashEntry(setup_file_hash, token);
5514 checked_free(token);
5517 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5521 freeSetupFileHash(setup_file_hash);
5525 if (filename_anim_initial == NULL)
5527 // read settings for busy animation from static default artwork config
5528 for (i = 0; image_config[i].token != NULL; i++)
5530 if (strEqual(image_config[i].token, anim_token))
5531 filename_anim_initial = getStringCopy(image_config[i].value);
5532 else if (strlen(image_config[i].token) > len_anim_token &&
5533 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5535 for (j = 0; image_config_suffix[j].token != NULL; j++)
5537 if (strEqual(&image_config[i].token[len_anim_token],
5538 image_config_suffix[j].token))
5540 get_graphic_parameter_value(image_config[i].value,
5541 image_config_suffix[j].token,
5542 image_config_suffix[j].type);
5548 if (filename_anim_initial == NULL) // should not happen
5549 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5551 anim_initial.bitmaps =
5552 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5554 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5555 LoadCustomImage(filename_anim_initial);
5557 checked_free(filename_anim_initial);
5559 graphic_info = &anim_initial; // graphic == 0 => anim_initial
5561 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5563 graphic_info = graphic_info_last;
5565 init.busy.width = anim_initial.width;
5566 init.busy.height = anim_initial.height;
5568 InitMenuDesignSettings_Static();
5570 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5571 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5572 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5573 InitGfxDrawTileCursorFunction(DrawTileCursor);
5575 gfx.fade_border_source_status = global.border_status;
5576 gfx.fade_border_target_status = global.border_status;
5577 gfx.masked_border_bitmap_ptr = backbuffer;
5579 // use copy of busy animation to prevent change while reloading artwork
5583 static void InitGfxBackground(void)
5585 fieldbuffer = bitmap_db_field;
5586 SetDrawtoField(DRAW_TO_BACKBUFFER);
5588 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5590 redraw_mask = REDRAW_ALL;
5593 static void InitLevelInfo(void)
5595 LoadLevelInfo(); // global level info
5596 LoadLevelSetup_LastSeries(); // last played series info
5597 LoadLevelSetup_SeriesInfo(); // last played level info
5599 if (global.autoplay_leveldir &&
5600 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5602 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5603 global.autoplay_leveldir);
5604 if (leveldir_current == NULL)
5605 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5608 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5611 static void InitLevelArtworkInfo(void)
5613 LoadLevelArtworkInfo();
5616 static void InitImages(void)
5618 print_timestamp_init("InitImages");
5621 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5622 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5623 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5624 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5625 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5626 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5627 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5628 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5631 setLevelArtworkDir(artwork.gfx_first);
5634 Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5635 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5636 Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5637 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5638 Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5639 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5640 Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5641 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5645 Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
5646 leveldir_current->identifier,
5647 artwork.gfx_current_identifier,
5648 artwork.gfx_current->identifier,
5649 leveldir_current->graphics_set,
5650 leveldir_current->graphics_path);
5653 UPDATE_BUSY_STATE();
5655 ReloadCustomImages();
5656 print_timestamp_time("ReloadCustomImages");
5658 UPDATE_BUSY_STATE();
5660 LoadCustomElementDescriptions();
5661 print_timestamp_time("LoadCustomElementDescriptions");
5663 UPDATE_BUSY_STATE();
5665 LoadMenuDesignSettings();
5666 print_timestamp_time("LoadMenuDesignSettings");
5668 UPDATE_BUSY_STATE();
5670 ReinitializeGraphics();
5671 print_timestamp_time("ReinitializeGraphics");
5673 LoadMenuDesignSettings_AfterGraphics();
5674 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5676 UPDATE_BUSY_STATE();
5678 print_timestamp_done("InitImages");
5681 static void InitSound(char *identifier)
5683 print_timestamp_init("InitSound");
5685 if (identifier == NULL)
5686 identifier = artwork.snd_current->identifier;
5688 // set artwork path to send it to the sound server process
5689 setLevelArtworkDir(artwork.snd_first);
5691 InitReloadCustomSounds(identifier);
5692 print_timestamp_time("InitReloadCustomSounds");
5694 ReinitializeSounds();
5695 print_timestamp_time("ReinitializeSounds");
5697 print_timestamp_done("InitSound");
5700 static void InitMusic(char *identifier)
5702 print_timestamp_init("InitMusic");
5704 if (identifier == NULL)
5705 identifier = artwork.mus_current->identifier;
5707 // set artwork path to send it to the sound server process
5708 setLevelArtworkDir(artwork.mus_first);
5710 InitReloadCustomMusic(identifier);
5711 print_timestamp_time("InitReloadCustomMusic");
5713 ReinitializeMusic();
5714 print_timestamp_time("ReinitializeMusic");
5716 print_timestamp_done("InitMusic");
5719 static void InitArtworkDone(void)
5721 if (program.headless)
5724 InitGlobalAnimations();
5727 static void InitNetworkSettings(void)
5729 boolean network_enabled = (options.network || setup.network_mode);
5730 char *network_server = (options.server_host != NULL ? options.server_host :
5731 setup.network_server_hostname);
5733 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5734 network_server = NULL;
5736 InitNetworkInfo(network_enabled,
5740 options.server_port);
5743 void InitNetworkServer(void)
5745 if (!network.enabled || network.connected)
5748 LimitScreenUpdates(FALSE);
5750 if (game_status == GAME_MODE_LOADING)
5753 if (!ConnectToServer(network.server_host, network.server_port))
5755 network.enabled = FALSE;
5757 setup.network_mode = FALSE;
5761 SendToServer_ProtocolVersion();
5762 SendToServer_PlayerName(setup.player_name);
5763 SendToServer_NrWanted(setup.network_player_nr + 1);
5765 network.connected = TRUE;
5768 // short time to recognize result of network initialization
5769 if (game_status == GAME_MODE_LOADING)
5770 Delay_WithScreenUpdates(1000);
5773 static boolean CheckArtworkConfigForCustomElements(char *filename)
5775 SetupFileHash *setup_file_hash;
5776 boolean redefined_ce_found = FALSE;
5778 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5780 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5782 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5784 char *token = HASH_ITERATION_TOKEN(itr);
5786 if (strPrefix(token, "custom_"))
5788 redefined_ce_found = TRUE;
5793 END_HASH_ITERATION(setup_file_hash, itr)
5795 freeSetupFileHash(setup_file_hash);
5798 return redefined_ce_found;
5801 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5803 char *filename_base, *filename_local;
5804 boolean redefined_ce_found = FALSE;
5806 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5809 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5810 "leveldir_current->identifier == '%s'",
5811 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5812 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5813 "leveldir_current->graphics_path == '%s'",
5814 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5815 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5816 "leveldir_current->graphics_set == '%s'",
5817 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5818 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5819 "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5820 leveldir_current == NULL ? "[NULL]" :
5821 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5824 // first look for special artwork configured in level series config
5825 filename_base = getCustomArtworkLevelConfigFilename(type);
5828 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5829 "filename_base == '%s'", filename_base);
5832 if (fileExists(filename_base))
5833 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5835 filename_local = getCustomArtworkConfigFilename(type);
5838 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5839 "filename_local == '%s'", filename_local);
5842 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5843 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5846 Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5847 "redefined_ce_found == %d", redefined_ce_found);
5850 return redefined_ce_found;
5853 static void InitOverrideArtwork(void)
5855 boolean redefined_ce_found = FALSE;
5857 // to check if this level set redefines any CEs, do not use overriding
5858 gfx.override_level_graphics = FALSE;
5859 gfx.override_level_sounds = FALSE;
5860 gfx.override_level_music = FALSE;
5862 // now check if this level set has definitions for custom elements
5863 if (setup.override_level_graphics == AUTO ||
5864 setup.override_level_sounds == AUTO ||
5865 setup.override_level_music == AUTO)
5866 redefined_ce_found =
5867 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5868 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5869 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5872 Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
5873 redefined_ce_found);
5876 if (redefined_ce_found)
5878 // this level set has CE definitions: change "AUTO" to "FALSE"
5879 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5880 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5881 gfx.override_level_music = (setup.override_level_music == TRUE);
5885 // this level set has no CE definitions: change "AUTO" to "TRUE"
5886 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5887 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5888 gfx.override_level_music = (setup.override_level_music != FALSE);
5892 Debug("init:InitOverrideArtwork", "%d, %d, %d",
5893 gfx.override_level_graphics,
5894 gfx.override_level_sounds,
5895 gfx.override_level_music);
5899 static char *getNewArtworkIdentifier(int type)
5901 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5902 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5903 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5904 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5905 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5906 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5907 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5908 char *leveldir_identifier = leveldir_current->identifier;
5909 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
5910 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5911 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5912 char *artwork_current_identifier;
5913 char *artwork_new_identifier = NULL; // default: nothing has changed
5915 // leveldir_current may be invalid (level group, parent link)
5916 if (!validLevelSeries(leveldir_current))
5919 /* 1st step: determine artwork set to be activated in descending order:
5920 --------------------------------------------------------------------
5921 1. setup artwork (when configured to override everything else)
5922 2. artwork set configured in "levelinfo.conf" of current level set
5923 (artwork in level directory will have priority when loading later)
5924 3. artwork in level directory (stored in artwork sub-directory)
5925 4. setup artwork (currently configured in setup menu) */
5927 if (setup_override_artwork)
5928 artwork_current_identifier = setup_artwork_set;
5929 else if (leveldir_artwork_set != NULL)
5930 artwork_current_identifier = leveldir_artwork_set;
5931 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5932 artwork_current_identifier = leveldir_identifier;
5934 artwork_current_identifier = setup_artwork_set;
5937 /* 2nd step: check if it is really needed to reload artwork set
5938 ------------------------------------------------------------ */
5940 // ---------- reload if level set and also artwork set has changed ----------
5941 if (leveldir_current_identifier[type] != leveldir_identifier &&
5942 (last_has_level_artwork_set[type] || has_level_artwork_set))
5943 artwork_new_identifier = artwork_current_identifier;
5945 leveldir_current_identifier[type] = leveldir_identifier;
5946 last_has_level_artwork_set[type] = has_level_artwork_set;
5948 // ---------- reload if "override artwork" setting has changed --------------
5949 if (last_override_level_artwork[type] != setup_override_artwork)
5950 artwork_new_identifier = artwork_current_identifier;
5952 last_override_level_artwork[type] = setup_override_artwork;
5954 // ---------- reload if current artwork identifier has changed --------------
5955 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5956 artwork_current_identifier))
5957 artwork_new_identifier = artwork_current_identifier;
5959 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5961 // ---------- do not reload directly after starting -------------------------
5962 if (!initialized[type])
5963 artwork_new_identifier = NULL;
5965 initialized[type] = TRUE;
5967 return artwork_new_identifier;
5970 void ReloadCustomArtwork(int force_reload)
5972 int last_game_status = game_status; // save current game status
5973 char *gfx_new_identifier;
5974 char *snd_new_identifier;
5975 char *mus_new_identifier;
5976 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5977 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5978 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5979 boolean reload_needed;
5981 InitOverrideArtwork();
5983 force_reload_gfx |= AdjustGraphicsForEMC();
5984 force_reload_snd |= AdjustSoundsForEMC();
5986 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5987 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5988 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5990 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5991 snd_new_identifier != NULL || force_reload_snd ||
5992 mus_new_identifier != NULL || force_reload_mus);
5997 print_timestamp_init("ReloadCustomArtwork");
5999 SetGameStatus(GAME_MODE_LOADING);
6001 FadeOut(REDRAW_ALL);
6003 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6004 print_timestamp_time("ClearRectangle");
6008 if (gfx_new_identifier != NULL || force_reload_gfx)
6011 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6012 artwork.gfx_current_identifier,
6014 artwork.gfx_current->identifier,
6015 leveldir_current->graphics_set);
6019 print_timestamp_time("InitImages");
6022 if (snd_new_identifier != NULL || force_reload_snd)
6024 InitSound(snd_new_identifier);
6025 print_timestamp_time("InitSound");
6028 if (mus_new_identifier != NULL || force_reload_mus)
6030 InitMusic(mus_new_identifier);
6031 print_timestamp_time("InitMusic");
6036 SetGameStatus(last_game_status); // restore current game status
6038 init_last = init; // switch to new busy animation
6040 FadeOut(REDRAW_ALL);
6042 RedrawGlobalBorder();
6044 // force redraw of (open or closed) door graphics
6045 SetDoorState(DOOR_OPEN_ALL);
6046 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6048 FadeSetEnterScreen();
6049 FadeSkipNextFadeOut();
6051 print_timestamp_done("ReloadCustomArtwork");
6053 LimitScreenUpdates(FALSE);
6056 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6058 if (global.autoplay_leveldir == NULL)
6059 KeyboardAutoRepeatOff();
6062 void DisplayExitMessage(char *format, va_list ap)
6064 // also check for initialized video (headless flag may be temporarily unset)
6065 if (program.headless || !video.initialized)
6068 // check if draw buffer and fonts for exit message are already available
6069 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6072 int font_1 = FC_RED;
6073 int font_2 = FC_YELLOW;
6074 int font_3 = FC_BLUE;
6075 int font_width = getFontWidth(font_2);
6076 int font_height = getFontHeight(font_2);
6079 int sxsize = WIN_XSIZE - 2 * sx;
6080 int sysize = WIN_YSIZE - 2 * sy;
6081 int line_length = sxsize / font_width;
6082 int max_lines = sysize / font_height;
6083 int num_lines_printed;
6087 gfx.sxsize = sxsize;
6088 gfx.sysize = sysize;
6092 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6094 DrawTextSCentered(sy, font_1, "Fatal error:");
6095 sy += 3 * font_height;;
6098 DrawTextBufferVA(sx, sy, format, ap, font_2,
6099 line_length, line_length, max_lines,
6100 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6101 sy += (num_lines_printed + 3) * font_height;
6103 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6104 sy += 3 * font_height;
6107 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6108 line_length, line_length, max_lines,
6109 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6111 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6113 redraw_mask = REDRAW_ALL;
6115 // force drawing exit message even if screen updates are currently limited
6116 LimitScreenUpdates(FALSE);
6120 // deactivate toons on error message screen
6121 setup.toons = FALSE;
6123 WaitForEventToContinue();
6127 // ============================================================================
6129 // ============================================================================
6133 print_timestamp_init("OpenAll");
6135 SetGameStatus(GAME_MODE_LOADING);
6139 InitGlobal(); // initialize some global variables
6141 print_timestamp_time("[init global stuff]");
6145 print_timestamp_time("[init setup/config stuff (1)]");
6149 if (options.execute_command)
6150 Execute_Command(options.execute_command);
6152 InitNetworkSettings();
6156 if (network.serveronly)
6158 #if defined(PLATFORM_UNIX)
6159 NetworkServer(network.server_port, TRUE);
6161 Warn("networking only supported in Unix version");
6164 exit(0); // never reached, server loops forever
6168 print_timestamp_time("[init setup/config stuff (2)]");
6170 print_timestamp_time("[init setup/config stuff (3)]");
6171 InitArtworkInfo(); // needed before loading gfx, sound & music
6172 print_timestamp_time("[init setup/config stuff (4)]");
6173 InitArtworkConfig(); // needed before forking sound child process
6174 print_timestamp_time("[init setup/config stuff (5)]");
6176 print_timestamp_time("[init setup/config stuff (6)]");
6178 InitRND(NEW_RANDOMIZE);
6179 InitSimpleRandom(NEW_RANDOMIZE);
6183 print_timestamp_time("[init setup/config stuff]");
6185 InitVideoDefaults();
6187 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6190 InitEventFilter(FilterMouseMotionEvents);
6192 print_timestamp_time("[init video stuff]");
6194 InitElementPropertiesStatic();
6195 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6196 InitElementPropertiesGfxElement();
6198 print_timestamp_time("[init element properties stuff]");
6202 print_timestamp_time("InitGfx");
6205 print_timestamp_time("InitLevelInfo");
6207 InitLevelArtworkInfo();
6208 print_timestamp_time("InitLevelArtworkInfo");
6210 InitOverrideArtwork(); // needs to know current level directory
6211 print_timestamp_time("InitOverrideArtwork");
6213 InitImages(); // needs to know current level directory
6214 print_timestamp_time("InitImages");
6216 InitSound(NULL); // needs to know current level directory
6217 print_timestamp_time("InitSound");
6219 InitMusic(NULL); // needs to know current level directory
6220 print_timestamp_time("InitMusic");
6224 InitGfxBackground();
6230 if (global.autoplay_leveldir)
6235 else if (global.patchtapes_leveldir)
6240 else if (global.convert_leveldir)
6245 else if (global.create_images_dir)
6247 CreateLevelSketchImages();
6251 InitNetworkServer();
6253 SetGameStatus(GAME_MODE_MAIN);
6255 FadeSetEnterScreen();
6256 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6257 FadeSkipNextFadeOut();
6259 print_timestamp_time("[post-artwork]");
6261 print_timestamp_done("OpenAll");
6266 Debug("internal:path", "SDL_GetBasePath() == '%s'",
6268 Debug("internal:path", "SDL_GetPrefPath() == '%s'",
6269 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6270 #if defined(PLATFORM_ANDROID)
6271 Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
6272 SDL_AndroidGetInternalStoragePath());
6273 Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
6274 SDL_AndroidGetExternalStoragePath());
6275 Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
6276 (SDL_AndroidGetExternalStorageState() &
6277 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6278 SDL_AndroidGetExternalStorageState() &
6279 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6284 void CloseAllAndExit(int exit_value)
6289 CloseAudio(); // called after freeing sounds (needed for SDL)
6297 // set a flag to tell the network server thread to quit and wait for it
6298 // using SDL_WaitThread()
6300 // Code used with SDL 1.2:
6301 // if (network_server) // terminate network server
6302 // SDL_KillThread(server_thread);
6304 CloseVideoDisplay();
6305 ClosePlatformDependentStuff();
6307 if (exit_value != 0 && !options.execute_command)
6309 // fall back to default level set (current set may have caused an error)
6310 SaveLevelSetup_LastSeries_Deactivate();
6312 // tell user where to find error log file which may contain more details
6313 // (error notification now directly displayed on screen inside R'n'D
6314 // NotifyUserAboutErrorFile(); // currently only works for Windows