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 printf("::: InitGlobalAnimGraphicInfo\n");
655 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
656 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
657 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
658 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
659 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
660 printf("::: - anim %d, part %d, mode %d => %d\n",
661 i, j, k, global_anim_info[i].graphic[j][k]);
665 static void InitGlobalAnimSoundInfo(void)
667 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
668 int num_property_mappings = getSoundListPropertyMappingSize();
671 // always start with reliable default values (no global animation sounds)
672 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
673 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
674 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
675 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
677 // initialize global animation sound definitions from dynamic configuration
678 for (i = 0; i < num_property_mappings; i++)
680 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
681 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
682 int special = property_mapping[i].ext3_index;
683 int sound = property_mapping[i].artwork_index;
685 // sound uses control definition; map it to position of graphic (artwork)
686 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
688 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
691 // set animation part to base part, if not specified
692 if (!IS_GLOBAL_ANIM_PART(part_nr))
693 part_nr = GLOBAL_ANIM_ID_PART_BASE;
695 // set animation screen to default, if not specified
696 if (!IS_SPECIAL_GFX_ARG(special))
697 special = GFX_SPECIAL_ARG_DEFAULT;
699 global_anim_info[anim_nr].sound[part_nr][special] = sound;
703 printf("::: InitGlobalAnimSoundInfo\n");
705 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
706 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
707 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
708 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
709 printf("::: - anim %d, part %d, mode %d => %d\n",
710 i, j, k, global_anim_info[i].sound[j][k]);
714 static void InitGlobalAnimMusicInfo(void)
716 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
717 int num_property_mappings = getMusicListPropertyMappingSize();
720 // always start with reliable default values (no global animation music)
721 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
722 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
723 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
724 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
726 // initialize global animation music definitions from dynamic configuration
727 for (i = 0; i < num_property_mappings; i++)
729 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
730 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
731 int special = property_mapping[i].ext2_index;
732 int music = property_mapping[i].artwork_index;
734 // music uses control definition; map it to position of graphic (artwork)
735 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
737 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
740 // set animation part to base part, if not specified
741 if (!IS_GLOBAL_ANIM_PART(part_nr))
742 part_nr = GLOBAL_ANIM_ID_PART_BASE;
744 // set animation screen to default, if not specified
745 if (!IS_SPECIAL_GFX_ARG(special))
746 special = GFX_SPECIAL_ARG_DEFAULT;
748 global_anim_info[anim_nr].music[part_nr][special] = music;
752 printf("::: InitGlobalAnimMusicInfo\n");
754 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
755 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
756 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
757 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
758 printf("::: - anim %d, part %d, mode %d => %d\n",
759 i, j, k, global_anim_info[i].music[j][k]);
763 static void InitElementGraphicInfo(void)
765 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
766 int num_property_mappings = getImageListPropertyMappingSize();
769 if (graphic_info == NULL) // still at startup phase
772 // set values to -1 to identify later as "uninitialized" values
773 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
775 for (act = 0; act < NUM_ACTIONS; act++)
777 element_info[i].graphic[act] = -1;
778 element_info[i].crumbled[act] = -1;
780 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
782 element_info[i].direction_graphic[act][dir] = -1;
783 element_info[i].direction_crumbled[act][dir] = -1;
790 // initialize normal element/graphic mapping from static configuration
791 for (i = 0; element_to_graphic[i].element > -1; i++)
793 int element = element_to_graphic[i].element;
794 int action = element_to_graphic[i].action;
795 int direction = element_to_graphic[i].direction;
796 boolean crumbled = element_to_graphic[i].crumbled;
797 int graphic = element_to_graphic[i].graphic;
798 int base_graphic = el2baseimg(element);
800 if (graphic_info[graphic].bitmap == NULL)
803 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
806 boolean base_redefined =
807 getImageListEntryFromImageID(base_graphic)->redefined;
808 boolean act_dir_redefined =
809 getImageListEntryFromImageID(graphic)->redefined;
811 /* if the base graphic ("emerald", for example) has been redefined,
812 but not the action graphic ("emerald.falling", for example), do not
813 use an existing (in this case considered obsolete) action graphic
814 anymore, but use the automatically determined default graphic */
815 if (base_redefined && !act_dir_redefined)
820 action = ACTION_DEFAULT;
825 element_info[element].direction_crumbled[action][direction] = graphic;
827 element_info[element].crumbled[action] = graphic;
832 element_info[element].direction_graphic[action][direction] = graphic;
834 element_info[element].graphic[action] = graphic;
838 // initialize normal element/graphic mapping from dynamic configuration
839 for (i = 0; i < num_property_mappings; i++)
841 int element = property_mapping[i].base_index;
842 int action = property_mapping[i].ext1_index;
843 int direction = property_mapping[i].ext2_index;
844 int special = property_mapping[i].ext3_index;
845 int graphic = property_mapping[i].artwork_index;
846 boolean crumbled = FALSE;
848 if (special == GFX_SPECIAL_ARG_CRUMBLED)
854 if (graphic_info[graphic].bitmap == NULL)
857 if (element >= MAX_NUM_ELEMENTS || special != -1)
861 action = ACTION_DEFAULT;
866 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
867 element_info[element].direction_crumbled[action][dir] = -1;
870 element_info[element].direction_crumbled[action][direction] = graphic;
872 element_info[element].crumbled[action] = graphic;
877 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
878 element_info[element].direction_graphic[action][dir] = -1;
881 element_info[element].direction_graphic[action][direction] = graphic;
883 element_info[element].graphic[action] = graphic;
887 // now copy all graphics that are defined to be cloned from other graphics
888 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
890 int graphic = element_info[i].graphic[ACTION_DEFAULT];
891 int crumbled_like, diggable_like;
896 crumbled_like = graphic_info[graphic].crumbled_like;
897 diggable_like = graphic_info[graphic].diggable_like;
899 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
901 for (act = 0; act < NUM_ACTIONS; act++)
902 element_info[i].crumbled[act] =
903 element_info[crumbled_like].crumbled[act];
904 for (act = 0; act < NUM_ACTIONS; act++)
905 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
906 element_info[i].direction_crumbled[act][dir] =
907 element_info[crumbled_like].direction_crumbled[act][dir];
910 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
912 element_info[i].graphic[ACTION_DIGGING] =
913 element_info[diggable_like].graphic[ACTION_DIGGING];
914 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
915 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
916 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
920 // set hardcoded definitions for some runtime elements without graphic
921 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
923 // set hardcoded definitions for some internal elements without graphic
924 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
926 if (IS_EDITOR_CASCADE_INACTIVE(i))
927 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
928 else if (IS_EDITOR_CASCADE_ACTIVE(i))
929 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
932 // now set all undefined/invalid graphics to -1 to set to default after it
933 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
935 for (act = 0; act < NUM_ACTIONS; act++)
939 graphic = element_info[i].graphic[act];
940 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
941 element_info[i].graphic[act] = -1;
943 graphic = element_info[i].crumbled[act];
944 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
945 element_info[i].crumbled[act] = -1;
947 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
949 graphic = element_info[i].direction_graphic[act][dir];
950 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
951 element_info[i].direction_graphic[act][dir] = -1;
953 graphic = element_info[i].direction_crumbled[act][dir];
954 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
955 element_info[i].direction_crumbled[act][dir] = -1;
962 // adjust graphics with 2nd tile for movement according to direction
963 // (do this before correcting '-1' values to minimize calculations)
964 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
966 for (act = 0; act < NUM_ACTIONS; act++)
968 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
970 int graphic = element_info[i].direction_graphic[act][dir];
971 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
973 if (act == ACTION_FALLING) // special case
974 graphic = element_info[i].graphic[act];
977 graphic_info[graphic].double_movement &&
978 graphic_info[graphic].swap_double_tiles != 0)
980 struct GraphicInfo *g = &graphic_info[graphic];
981 int src_x_front = g->src_x;
982 int src_y_front = g->src_y;
983 int src_x_back = g->src_x + g->offset2_x;
984 int src_y_back = g->src_y + g->offset2_y;
985 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
987 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
988 src_y_front < src_y_back);
989 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
990 boolean swap_movement_tiles_autodetected =
991 (!frames_are_ordered_diagonally &&
992 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
993 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
994 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
995 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
997 // swap frontside and backside graphic tile coordinates, if needed
998 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
1000 // get current (wrong) backside tile coordinates
1001 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1003 // set frontside tile coordinates to backside tile coordinates
1004 g->src_x = src_x_back;
1005 g->src_y = src_y_back;
1007 // invert tile offset to point to new backside tile coordinates
1011 // do not swap front and backside tiles again after correction
1012 g->swap_double_tiles = 0;
1019 UPDATE_BUSY_STATE();
1021 // now set all '-1' values to element specific default values
1022 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1024 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1025 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1026 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1027 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1029 if (default_graphic == -1)
1030 default_graphic = IMG_UNKNOWN;
1032 if (default_crumbled == -1)
1033 default_crumbled = default_graphic;
1035 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1037 default_direction_graphic[dir] =
1038 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1039 default_direction_crumbled[dir] =
1040 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1042 if (default_direction_graphic[dir] == -1)
1043 default_direction_graphic[dir] = default_graphic;
1045 if (default_direction_crumbled[dir] == -1)
1046 default_direction_crumbled[dir] = default_direction_graphic[dir];
1049 for (act = 0; act < NUM_ACTIONS; act++)
1051 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1052 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1053 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1054 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1055 act == ACTION_TURNING_FROM_RIGHT ||
1056 act == ACTION_TURNING_FROM_UP ||
1057 act == ACTION_TURNING_FROM_DOWN);
1059 // generic default action graphic (defined by "[default]" directive)
1060 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1061 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1062 int default_remove_graphic = IMG_EMPTY;
1064 if (act_remove && default_action_graphic != -1)
1065 default_remove_graphic = default_action_graphic;
1067 // look for special default action graphic (classic game specific)
1068 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1069 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1070 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1071 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1072 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1073 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1074 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1075 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1077 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1078 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1079 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1080 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1081 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1082 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1083 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1084 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1086 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1087 // !!! make this better !!!
1088 if (i == EL_EMPTY_SPACE)
1090 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1091 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1094 if (default_action_graphic == -1)
1095 default_action_graphic = default_graphic;
1097 if (default_action_crumbled == -1)
1098 default_action_crumbled = default_action_graphic;
1100 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1102 // use action graphic as the default direction graphic, if undefined
1103 int default_action_direction_graphic = element_info[i].graphic[act];
1104 int default_action_direction_crumbled = element_info[i].crumbled[act];
1106 // no graphic for current action -- use default direction graphic
1107 if (default_action_direction_graphic == -1)
1108 default_action_direction_graphic =
1109 (act_remove ? default_remove_graphic :
1111 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1112 default_action_graphic != default_graphic ?
1113 default_action_graphic :
1114 default_direction_graphic[dir]);
1116 if (element_info[i].direction_graphic[act][dir] == -1)
1117 element_info[i].direction_graphic[act][dir] =
1118 default_action_direction_graphic;
1120 if (default_action_direction_crumbled == -1)
1121 default_action_direction_crumbled =
1122 element_info[i].direction_graphic[act][dir];
1124 if (element_info[i].direction_crumbled[act][dir] == -1)
1125 element_info[i].direction_crumbled[act][dir] =
1126 default_action_direction_crumbled;
1129 // no graphic for this specific action -- use default action graphic
1130 if (element_info[i].graphic[act] == -1)
1131 element_info[i].graphic[act] =
1132 (act_remove ? default_remove_graphic :
1133 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1134 default_action_graphic);
1136 if (element_info[i].crumbled[act] == -1)
1137 element_info[i].crumbled[act] = element_info[i].graphic[act];
1141 UPDATE_BUSY_STATE();
1144 static void InitElementSpecialGraphicInfo(void)
1146 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1147 int num_property_mappings = getImageListPropertyMappingSize();
1150 // always start with reliable default values
1151 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1152 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1153 element_info[i].special_graphic[j] =
1154 element_info[i].graphic[ACTION_DEFAULT];
1156 // initialize special element/graphic mapping from static configuration
1157 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1159 int element = element_to_special_graphic[i].element;
1160 int special = element_to_special_graphic[i].special;
1161 int graphic = element_to_special_graphic[i].graphic;
1162 int base_graphic = el2baseimg(element);
1163 boolean base_redefined =
1164 getImageListEntryFromImageID(base_graphic)->redefined;
1165 boolean special_redefined =
1166 getImageListEntryFromImageID(graphic)->redefined;
1168 /* if the base graphic ("emerald", for example) has been redefined,
1169 but not the special graphic ("emerald.EDITOR", for example), do not
1170 use an existing (in this case considered obsolete) special graphic
1171 anymore, but use the automatically created (down-scaled) graphic */
1172 if (base_redefined && !special_redefined)
1175 element_info[element].special_graphic[special] = graphic;
1178 // initialize special element/graphic mapping from dynamic configuration
1179 for (i = 0; i < num_property_mappings; i++)
1181 int element = property_mapping[i].base_index;
1182 int action = property_mapping[i].ext1_index;
1183 int direction = property_mapping[i].ext2_index;
1184 int special = property_mapping[i].ext3_index;
1185 int graphic = property_mapping[i].artwork_index;
1187 // for action ".active", replace element with active element, if exists
1188 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1190 element = ELEMENT_ACTIVE(element);
1194 if (element >= MAX_NUM_ELEMENTS)
1197 // do not change special graphic if action or direction was specified
1198 if (action != -1 || direction != -1)
1201 if (IS_SPECIAL_GFX_ARG(special))
1202 element_info[element].special_graphic[special] = graphic;
1205 // now set all undefined/invalid graphics to default
1206 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1207 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1208 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1209 element_info[i].special_graphic[j] =
1210 element_info[i].graphic[ACTION_DEFAULT];
1213 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1215 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1216 return get_parameter_value(value_raw, suffix, type);
1218 if (strEqual(value_raw, ARG_UNDEFINED))
1219 return ARG_UNDEFINED_VALUE;
1221 if (type == TYPE_ELEMENT)
1223 char *value = getHashEntry(element_token_hash, value_raw);
1227 Error(ERR_INFO_LINE, "-");
1228 Error(ERR_INFO, "warning: error found in config file:");
1229 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1230 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1231 Error(ERR_INFO, "custom graphic rejected for this element/action");
1232 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1233 Error(ERR_INFO_LINE, "-");
1236 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1238 else if (type == TYPE_GRAPHIC)
1240 char *value = getHashEntry(graphic_token_hash, value_raw);
1241 int fallback_graphic = IMG_CHAR_EXCLAM;
1245 Error(ERR_INFO_LINE, "-");
1246 Error(ERR_INFO, "warning: error found in config file:");
1247 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1248 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1249 Error(ERR_INFO, "custom graphic rejected for this element/action");
1250 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1251 Error(ERR_INFO_LINE, "-");
1254 return (value != NULL ? atoi(value) : fallback_graphic);
1260 static int get_scaled_graphic_width(int graphic)
1262 int original_width = getOriginalImageWidthFromImageID(graphic);
1263 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1265 return original_width * scale_up_factor;
1268 static int get_scaled_graphic_height(int graphic)
1270 int original_height = getOriginalImageHeightFromImageID(graphic);
1271 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1273 return original_height * scale_up_factor;
1276 static void set_graphic_parameters_ext(int graphic, int *parameter,
1277 Bitmap **src_bitmaps)
1279 struct GraphicInfo *g = &graphic_info[graphic];
1280 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1281 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1282 int anim_frames_per_line = 1;
1284 // always start with reliable default values
1285 g->src_image_width = 0;
1286 g->src_image_height = 0;
1289 g->width = TILEX; // default for element graphics
1290 g->height = TILEY; // default for element graphics
1291 g->offset_x = 0; // one or both of these values ...
1292 g->offset_y = 0; // ... will be corrected later
1293 g->offset2_x = 0; // one or both of these values ...
1294 g->offset2_y = 0; // ... will be corrected later
1295 g->swap_double_tiles = -1; // auto-detect tile swapping
1296 g->crumbled_like = -1; // do not use clone element
1297 g->diggable_like = -1; // do not use clone element
1298 g->border_size = TILEX / 8; // "CRUMBLED" border size
1299 g->scale_up_factor = 1; // default: no scaling up
1300 g->tile_size = TILESIZE; // default: standard tile size
1301 g->clone_from = -1; // do not use clone graphic
1302 g->init_delay_fixed = 0;
1303 g->init_delay_random = 0;
1304 g->init_delay_action = -1;
1305 g->anim_delay_fixed = 0;
1306 g->anim_delay_random = 0;
1307 g->anim_delay_action = -1;
1308 g->post_delay_fixed = 0;
1309 g->post_delay_random = 0;
1310 g->post_delay_action = -1;
1311 g->init_event = ANIM_EVENT_UNDEFINED;
1312 g->anim_event = ANIM_EVENT_UNDEFINED;
1313 g->init_event_action = -1;
1314 g->anim_event_action = -1;
1315 g->draw_masked = FALSE;
1317 g->fade_mode = FADE_MODE_DEFAULT;
1321 g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1322 g->align = ALIGN_CENTER; // default for title screens
1323 g->valign = VALIGN_MIDDLE; // default for title screens
1324 g->sort_priority = 0; // default for title screens
1326 g->style = STYLE_DEFAULT;
1328 g->bitmaps = src_bitmaps;
1329 g->bitmap = src_bitmap;
1331 // optional zoom factor for scaling up the image to a larger size
1332 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1333 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1334 if (g->scale_up_factor < 1)
1335 g->scale_up_factor = 1; // no scaling
1337 // optional tile size for using non-standard image size
1338 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1340 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1343 // CHECK: should tile sizes less than standard tile size be allowed?
1344 if (g->tile_size < TILESIZE)
1345 g->tile_size = TILESIZE; // standard tile size
1348 // when setting tile size, also set width and height accordingly
1349 g->width = g->tile_size;
1350 g->height = g->tile_size;
1353 if (g->use_image_size)
1355 // set new default bitmap size (with scaling, but without small images)
1356 g->width = get_scaled_graphic_width(graphic);
1357 g->height = get_scaled_graphic_height(graphic);
1360 // optional width and height of each animation frame
1361 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1362 g->width = parameter[GFX_ARG_WIDTH];
1363 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1364 g->height = parameter[GFX_ARG_HEIGHT];
1366 // optional x and y tile position of animation frame sequence
1367 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1368 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1369 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1370 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1372 // optional x and y pixel position of animation frame sequence
1373 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1374 g->src_x = parameter[GFX_ARG_X];
1375 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1376 g->src_y = parameter[GFX_ARG_Y];
1382 Error(ERR_INFO_LINE, "-");
1383 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1384 g->width, getTokenFromImageID(graphic), TILEX);
1385 Error(ERR_INFO_LINE, "-");
1387 g->width = TILEX; // will be checked to be inside bitmap later
1392 Error(ERR_INFO_LINE, "-");
1393 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1394 g->height, getTokenFromImageID(graphic), TILEY);
1395 Error(ERR_INFO_LINE, "-");
1397 g->height = TILEY; // will be checked to be inside bitmap later
1403 // get final bitmap size (with scaling, but without small images)
1404 int src_image_width = get_scaled_graphic_width(graphic);
1405 int src_image_height = get_scaled_graphic_height(graphic);
1407 if (src_image_width == 0 || src_image_height == 0)
1409 // only happens when loaded outside artwork system (like "global.busy")
1410 src_image_width = src_bitmap->width;
1411 src_image_height = src_bitmap->height;
1414 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1416 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1417 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1421 anim_frames_per_row = MAX(1, src_image_width / g->width);
1422 anim_frames_per_col = MAX(1, src_image_height / g->height);
1425 g->src_image_width = src_image_width;
1426 g->src_image_height = src_image_height;
1429 // correct x or y offset dependent of vertical or horizontal frame order
1430 if (parameter[GFX_ARG_VERTICAL]) // frames are ordered vertically
1432 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1433 parameter[GFX_ARG_OFFSET] : g->height);
1434 anim_frames_per_line = anim_frames_per_col;
1436 else // frames are ordered horizontally
1438 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1439 parameter[GFX_ARG_OFFSET] : g->width);
1440 anim_frames_per_line = anim_frames_per_row;
1443 // optionally, the x and y offset of frames can be specified directly
1444 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1445 g->offset_x = parameter[GFX_ARG_XOFFSET];
1446 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1447 g->offset_y = parameter[GFX_ARG_YOFFSET];
1449 // optionally, moving animations may have separate start and end graphics
1450 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1452 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1453 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1455 // correct x or y offset2 dependent of vertical or horizontal frame order
1456 if (parameter[GFX_ARG_2ND_VERTICAL]) // frames are ordered vertically
1457 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1458 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1459 else // frames are ordered horizontally
1460 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1461 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1463 // optionally, the x and y offset of 2nd graphic can be specified directly
1464 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1465 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1466 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1467 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1469 // optionally, the second movement tile can be specified as start tile
1470 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1471 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1473 // automatically determine correct number of frames, if not defined
1474 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1475 g->anim_frames = parameter[GFX_ARG_FRAMES];
1476 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1477 g->anim_frames = anim_frames_per_row;
1478 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1479 g->anim_frames = anim_frames_per_col;
1483 if (g->anim_frames < 1) // frames must be at least 1
1486 g->anim_frames_per_line =
1487 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1488 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1490 g->anim_delay = parameter[GFX_ARG_DELAY];
1491 if (g->anim_delay < 1) // delay must be at least 1
1494 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1496 // automatically determine correct start frame, if not defined
1497 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1498 g->anim_start_frame = 0;
1499 else if (g->anim_mode & ANIM_REVERSE)
1500 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1502 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1504 // animation synchronized with global frame counter, not move position
1505 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1507 // optional element for cloning crumble graphics
1508 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1509 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1511 // optional element for cloning digging graphics
1512 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1513 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1515 // optional border size for "crumbling" diggable graphics
1516 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1517 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1519 // used for global animations and player "boring" and "sleeping" actions
1520 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1521 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1522 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1523 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1524 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1525 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1526 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1527 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1528 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1529 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1530 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1531 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1533 // used for global animations
1534 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1535 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1536 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1537 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1538 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1539 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1540 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1541 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1542 if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1543 g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1544 if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1545 g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1546 if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1547 g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1549 // used for toon animations and global animations
1550 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1551 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1552 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1553 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1554 g->direction = parameter[GFX_ARG_DIRECTION];
1555 g->position = parameter[GFX_ARG_POSITION];
1556 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1557 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1559 if (g->step_delay < 1) // delay must be at least 1
1562 // this is only used for drawing font characters
1563 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1564 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1566 // use a different default value for global animations and toons
1567 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1568 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1569 g->draw_masked = TRUE;
1571 // this is used for drawing envelopes, global animations and toons
1572 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1573 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1575 // used for toon animations and global animations
1576 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1577 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1579 // optional graphic for cloning all graphics settings
1580 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1581 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1583 // optional settings for drawing title screens and title messages
1584 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1585 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1586 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1587 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1588 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1589 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1590 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1591 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1592 if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1593 g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1594 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1595 g->align = parameter[GFX_ARG_ALIGN];
1596 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1597 g->valign = parameter[GFX_ARG_VALIGN];
1598 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1599 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1601 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1602 g->class = parameter[GFX_ARG_CLASS];
1603 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1604 g->style = parameter[GFX_ARG_STYLE];
1606 // this is only used for drawing menu buttons and text
1607 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1608 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1609 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1610 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1613 static void set_graphic_parameters(int graphic)
1615 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1616 char **parameter_raw = image->parameter;
1617 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1618 int parameter[NUM_GFX_ARGS];
1621 // if fallback to default artwork is done, also use the default parameters
1622 if (image->fallback_to_default)
1623 parameter_raw = image->default_parameter;
1625 // get integer values from string parameters
1626 for (i = 0; i < NUM_GFX_ARGS; i++)
1627 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1628 image_config_suffix[i].token,
1629 image_config_suffix[i].type);
1631 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1633 UPDATE_BUSY_STATE();
1636 static void set_cloned_graphic_parameters(int graphic)
1638 int fallback_graphic = IMG_CHAR_EXCLAM;
1639 int max_num_images = getImageListSize();
1640 int clone_graphic = graphic_info[graphic].clone_from;
1641 int num_references_followed = 1;
1643 while (graphic_info[clone_graphic].clone_from != -1 &&
1644 num_references_followed < max_num_images)
1646 clone_graphic = graphic_info[clone_graphic].clone_from;
1648 num_references_followed++;
1651 if (num_references_followed >= max_num_images)
1653 Error(ERR_INFO_LINE, "-");
1654 Error(ERR_INFO, "warning: error found in config file:");
1655 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1656 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1657 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1658 Error(ERR_INFO, "custom graphic rejected for this element/action");
1660 if (graphic == fallback_graphic)
1661 Error(ERR_EXIT, "no fallback graphic available");
1663 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1664 Error(ERR_INFO_LINE, "-");
1666 graphic_info[graphic] = graphic_info[fallback_graphic];
1670 graphic_info[graphic] = graphic_info[clone_graphic];
1671 graphic_info[graphic].clone_from = clone_graphic;
1675 static void InitGraphicInfo(void)
1677 int fallback_graphic = IMG_CHAR_EXCLAM;
1678 int num_images = getImageListSize();
1681 // use image size as default values for width and height for these images
1682 static int full_size_graphics[] =
1685 IMG_GLOBAL_BORDER_MAIN,
1686 IMG_GLOBAL_BORDER_SCORES,
1687 IMG_GLOBAL_BORDER_EDITOR,
1688 IMG_GLOBAL_BORDER_PLAYING,
1691 IMG_BACKGROUND_ENVELOPE_1,
1692 IMG_BACKGROUND_ENVELOPE_2,
1693 IMG_BACKGROUND_ENVELOPE_3,
1694 IMG_BACKGROUND_ENVELOPE_4,
1695 IMG_BACKGROUND_REQUEST,
1698 IMG_BACKGROUND_TITLE_INITIAL,
1699 IMG_BACKGROUND_TITLE,
1700 IMG_BACKGROUND_MAIN,
1701 IMG_BACKGROUND_LEVELS,
1702 IMG_BACKGROUND_LEVELNR,
1703 IMG_BACKGROUND_SCORES,
1704 IMG_BACKGROUND_EDITOR,
1705 IMG_BACKGROUND_INFO,
1706 IMG_BACKGROUND_INFO_ELEMENTS,
1707 IMG_BACKGROUND_INFO_MUSIC,
1708 IMG_BACKGROUND_INFO_CREDITS,
1709 IMG_BACKGROUND_INFO_PROGRAM,
1710 IMG_BACKGROUND_INFO_VERSION,
1711 IMG_BACKGROUND_INFO_LEVELSET,
1712 IMG_BACKGROUND_SETUP,
1713 IMG_BACKGROUND_PLAYING,
1714 IMG_BACKGROUND_DOOR,
1715 IMG_BACKGROUND_TAPE,
1716 IMG_BACKGROUND_PANEL,
1717 IMG_BACKGROUND_PALETTE,
1718 IMG_BACKGROUND_TOOLBOX,
1720 IMG_TITLESCREEN_INITIAL_1,
1721 IMG_TITLESCREEN_INITIAL_2,
1722 IMG_TITLESCREEN_INITIAL_3,
1723 IMG_TITLESCREEN_INITIAL_4,
1724 IMG_TITLESCREEN_INITIAL_5,
1731 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1732 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1733 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1734 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1735 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1736 IMG_BACKGROUND_TITLEMESSAGE_1,
1737 IMG_BACKGROUND_TITLEMESSAGE_2,
1738 IMG_BACKGROUND_TITLEMESSAGE_3,
1739 IMG_BACKGROUND_TITLEMESSAGE_4,
1740 IMG_BACKGROUND_TITLEMESSAGE_5,
1745 FreeGlobalAnimEventInfo();
1747 checked_free(graphic_info);
1749 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1751 // initialize "use_image_size" flag with default value
1752 for (i = 0; i < num_images; i++)
1753 graphic_info[i].use_image_size = FALSE;
1755 // initialize "use_image_size" flag from static configuration above
1756 for (i = 0; full_size_graphics[i] != -1; i++)
1757 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1759 // first set all graphic paramaters ...
1760 for (i = 0; i < num_images; i++)
1761 set_graphic_parameters(i);
1763 // ... then copy these parameters for cloned graphics
1764 for (i = 0; i < num_images; i++)
1765 if (graphic_info[i].clone_from != -1)
1766 set_cloned_graphic_parameters(i);
1768 for (i = 0; i < num_images; i++)
1770 Bitmap *src_bitmap = graphic_info[i].bitmap;
1774 int src_bitmap_width, src_bitmap_height;
1776 // now check if no animation frames are outside of the loaded image
1778 if (graphic_info[i].bitmap == NULL)
1779 continue; // skip check for optional images that are undefined
1781 // get image size (this can differ from the standard element tile size!)
1782 width = graphic_info[i].width;
1783 height = graphic_info[i].height;
1785 // get final bitmap size (with scaling, but without small images)
1786 src_bitmap_width = graphic_info[i].src_image_width;
1787 src_bitmap_height = graphic_info[i].src_image_height;
1789 // check if first animation frame is inside specified bitmap
1791 // do not use getGraphicSourceXY() here to get position of first frame;
1792 // this avoids calculating wrong start position for out-of-bounds frame
1793 src_x = graphic_info[i].src_x;
1794 src_y = graphic_info[i].src_y;
1796 if (program.headless)
1799 if (src_x < 0 || src_y < 0 ||
1800 src_x + width > src_bitmap_width ||
1801 src_y + height > src_bitmap_height)
1803 Error(ERR_INFO_LINE, "-");
1804 Error(ERR_INFO, "warning: error found in config file:");
1805 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1806 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1807 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1808 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1810 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1811 src_x, src_y, src_bitmap_width, src_bitmap_height);
1812 Error(ERR_INFO, "custom graphic rejected for this element/action");
1814 if (i == fallback_graphic)
1815 Error(ERR_EXIT, "no fallback graphic available");
1817 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1818 Error(ERR_INFO_LINE, "-");
1820 graphic_info[i] = graphic_info[fallback_graphic];
1822 // if first frame out of bounds, do not check last frame anymore
1826 // check if last animation frame is inside specified bitmap
1828 last_frame = graphic_info[i].anim_frames - 1;
1829 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1831 if (src_x < 0 || src_y < 0 ||
1832 src_x + width > src_bitmap_width ||
1833 src_y + height > src_bitmap_height)
1835 Error(ERR_INFO_LINE, "-");
1836 Error(ERR_INFO, "warning: error found in config file:");
1837 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1838 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1839 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1840 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1842 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1843 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1844 Error(ERR_INFO, "custom graphic rejected for this element/action");
1846 if (i == fallback_graphic)
1847 Error(ERR_EXIT, "no fallback graphic available");
1849 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1850 Error(ERR_INFO_LINE, "-");
1852 graphic_info[i] = graphic_info[fallback_graphic];
1857 static void InitGraphicCompatibilityInfo(void)
1859 struct FileInfo *fi_global_door =
1860 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1861 int num_images = getImageListSize();
1864 /* the following compatibility handling is needed for the following case:
1865 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1866 graphics mainly used for door and panel graphics, like editor, tape and
1867 in-game buttons with hard-coded bitmap positions and button sizes; as
1868 these graphics now have individual definitions, redefining "global.door"
1869 to change all these graphics at once like before does not work anymore
1870 (because all those individual definitions still have their default values);
1871 to solve this, remap all those individual definitions that are not
1872 redefined to the new bitmap of "global.door" if it was redefined */
1874 // special compatibility handling if image "global.door" was redefined
1875 if (fi_global_door->redefined)
1877 for (i = 0; i < num_images; i++)
1879 struct FileInfo *fi = getImageListEntryFromImageID(i);
1881 // process only those images that still use the default settings
1884 // process all images which default to same image as "global.door"
1885 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1887 // printf("::: special treatment needed for token '%s'\n", fi->token);
1889 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1890 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1896 InitGraphicCompatibilityInfo_Doors();
1899 static void InitElementSoundInfo(void)
1901 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1902 int num_property_mappings = getSoundListPropertyMappingSize();
1905 // set values to -1 to identify later as "uninitialized" values
1906 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1907 for (act = 0; act < NUM_ACTIONS; act++)
1908 element_info[i].sound[act] = -1;
1910 // initialize element/sound mapping from static configuration
1911 for (i = 0; element_to_sound[i].element > -1; i++)
1913 int element = element_to_sound[i].element;
1914 int action = element_to_sound[i].action;
1915 int sound = element_to_sound[i].sound;
1916 boolean is_class = element_to_sound[i].is_class;
1919 action = ACTION_DEFAULT;
1922 element_info[element].sound[action] = sound;
1924 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1925 if (strEqual(element_info[j].class_name,
1926 element_info[element].class_name))
1927 element_info[j].sound[action] = sound;
1930 // initialize element class/sound mapping from dynamic configuration
1931 for (i = 0; i < num_property_mappings; i++)
1933 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1934 int action = property_mapping[i].ext1_index;
1935 int sound = property_mapping[i].artwork_index;
1937 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1941 action = ACTION_DEFAULT;
1943 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1944 if (strEqual(element_info[j].class_name,
1945 element_info[element_class].class_name))
1946 element_info[j].sound[action] = sound;
1949 // initialize element/sound mapping from dynamic configuration
1950 for (i = 0; i < num_property_mappings; i++)
1952 int element = property_mapping[i].base_index;
1953 int action = property_mapping[i].ext1_index;
1954 int sound = property_mapping[i].artwork_index;
1956 if (element >= MAX_NUM_ELEMENTS)
1960 action = ACTION_DEFAULT;
1962 element_info[element].sound[action] = sound;
1965 // now set all '-1' values to element specific default values
1966 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1968 for (act = 0; act < NUM_ACTIONS; act++)
1970 // generic default action sound (defined by "[default]" directive)
1971 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1973 // look for special default action sound (classic game specific)
1974 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1975 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1976 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1977 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1978 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1979 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1980 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1981 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1983 // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1984 // !!! make this better !!!
1985 if (i == EL_EMPTY_SPACE)
1986 default_action_sound = element_info[EL_DEFAULT].sound[act];
1988 // no sound for this specific action -- use default action sound
1989 if (element_info[i].sound[act] == -1)
1990 element_info[i].sound[act] = default_action_sound;
1994 // copy sound settings to some elements that are only stored in level file
1995 // in native R'n'D levels, but are used by game engine in native EM levels
1996 for (i = 0; copy_properties[i][0] != -1; i++)
1997 for (j = 1; j <= 4; j++)
1998 for (act = 0; act < NUM_ACTIONS; act++)
1999 element_info[copy_properties[i][j]].sound[act] =
2000 element_info[copy_properties[i][0]].sound[act];
2003 static void InitGameModeSoundInfo(void)
2007 // set values to -1 to identify later as "uninitialized" values
2008 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2011 // initialize gamemode/sound mapping from static configuration
2012 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2014 int gamemode = gamemode_to_sound[i].gamemode;
2015 int sound = gamemode_to_sound[i].sound;
2018 gamemode = GAME_MODE_DEFAULT;
2020 menu.sound[gamemode] = sound;
2023 // now set all '-1' values to levelset specific default values
2024 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2025 if (menu.sound[i] == -1)
2026 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2029 static void set_sound_parameters(int sound, char **parameter_raw)
2031 int parameter[NUM_SND_ARGS];
2034 // get integer values from string parameters
2035 for (i = 0; i < NUM_SND_ARGS; i++)
2037 get_parameter_value(parameter_raw[i],
2038 sound_config_suffix[i].token,
2039 sound_config_suffix[i].type);
2041 // explicit loop mode setting in configuration overrides default value
2042 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2043 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2045 // sound volume to change the original volume when loading the sound file
2046 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2048 // sound priority to give certain sounds a higher or lower priority
2049 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2052 static void InitSoundInfo(void)
2054 int *sound_effect_properties;
2055 int num_sounds = getSoundListSize();
2058 checked_free(sound_info);
2060 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2061 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2063 // initialize sound effect for all elements to "no sound"
2064 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2065 for (j = 0; j < NUM_ACTIONS; j++)
2066 element_info[i].sound[j] = SND_UNDEFINED;
2068 for (i = 0; i < num_sounds; i++)
2070 struct FileInfo *sound = getSoundListEntry(i);
2071 int len_effect_text = strlen(sound->token);
2073 sound_effect_properties[i] = ACTION_OTHER;
2074 sound_info[i].loop = FALSE; // default: play sound only once
2076 // determine all loop sounds and identify certain sound classes
2078 for (j = 0; element_action_info[j].suffix; j++)
2080 int len_action_text = strlen(element_action_info[j].suffix);
2082 if (len_action_text < len_effect_text &&
2083 strEqual(&sound->token[len_effect_text - len_action_text],
2084 element_action_info[j].suffix))
2086 sound_effect_properties[i] = element_action_info[j].value;
2087 sound_info[i].loop = element_action_info[j].is_loop_sound;
2093 // associate elements and some selected sound actions
2095 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2097 if (element_info[j].class_name)
2099 int len_class_text = strlen(element_info[j].class_name);
2101 if (len_class_text + 1 < len_effect_text &&
2102 strncmp(sound->token,
2103 element_info[j].class_name, len_class_text) == 0 &&
2104 sound->token[len_class_text] == '.')
2106 int sound_action_value = sound_effect_properties[i];
2108 element_info[j].sound[sound_action_value] = i;
2113 set_sound_parameters(i, sound->parameter);
2116 free(sound_effect_properties);
2119 static void InitGameModeMusicInfo(void)
2121 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2122 int num_property_mappings = getMusicListPropertyMappingSize();
2123 int default_levelset_music = -1;
2126 // set values to -1 to identify later as "uninitialized" values
2127 for (i = 0; i < MAX_LEVELS; i++)
2128 levelset.music[i] = -1;
2129 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2132 // initialize gamemode/music mapping from static configuration
2133 for (i = 0; gamemode_to_music[i].music > -1; i++)
2135 int gamemode = gamemode_to_music[i].gamemode;
2136 int music = gamemode_to_music[i].music;
2139 gamemode = GAME_MODE_DEFAULT;
2141 menu.music[gamemode] = music;
2144 // initialize gamemode/music mapping from dynamic configuration
2145 for (i = 0; i < num_property_mappings; i++)
2147 int prefix = property_mapping[i].base_index;
2148 int gamemode = property_mapping[i].ext2_index;
2149 int level = property_mapping[i].ext3_index;
2150 int music = property_mapping[i].artwork_index;
2152 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2156 gamemode = GAME_MODE_DEFAULT;
2158 // level specific music only allowed for in-game music
2159 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2160 gamemode = GAME_MODE_PLAYING;
2165 default_levelset_music = music;
2168 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2169 levelset.music[level] = music;
2170 if (gamemode != GAME_MODE_PLAYING)
2171 menu.music[gamemode] = music;
2174 // now set all '-1' values to menu specific default values
2175 // (undefined values of "levelset.music[]" might stay at "-1" to
2176 // allow dynamic selection of music files from music directory!)
2177 for (i = 0; i < MAX_LEVELS; i++)
2178 if (levelset.music[i] == -1)
2179 levelset.music[i] = default_levelset_music;
2180 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2181 if (menu.music[i] == -1)
2182 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2185 static void set_music_parameters(int music, char **parameter_raw)
2187 int parameter[NUM_MUS_ARGS];
2190 // get integer values from string parameters
2191 for (i = 0; i < NUM_MUS_ARGS; i++)
2193 get_parameter_value(parameter_raw[i],
2194 music_config_suffix[i].token,
2195 music_config_suffix[i].type);
2197 // explicit loop mode setting in configuration overrides default value
2198 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2199 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2202 static void InitMusicInfo(void)
2204 int num_music = getMusicListSize();
2207 checked_free(music_info);
2209 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2211 for (i = 0; i < num_music; i++)
2213 struct FileInfo *music = getMusicListEntry(i);
2214 int len_music_text = strlen(music->token);
2216 music_info[i].loop = TRUE; // default: play music in loop mode
2218 // determine all loop music
2220 for (j = 0; music_prefix_info[j].prefix; j++)
2222 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2224 if (len_prefix_text < len_music_text &&
2225 strncmp(music->token,
2226 music_prefix_info[j].prefix, len_prefix_text) == 0)
2228 music_info[i].loop = music_prefix_info[j].is_loop_music;
2234 set_music_parameters(i, music->parameter);
2238 static void ReinitializeGraphics(void)
2240 print_timestamp_init("ReinitializeGraphics");
2242 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2244 InitGraphicInfo(); // graphic properties mapping
2245 print_timestamp_time("InitGraphicInfo");
2246 InitElementGraphicInfo(); // element game graphic mapping
2247 print_timestamp_time("InitElementGraphicInfo");
2248 InitElementSpecialGraphicInfo(); // element special graphic mapping
2249 print_timestamp_time("InitElementSpecialGraphicInfo");
2251 InitElementSmallImages(); // scale elements to all needed sizes
2252 print_timestamp_time("InitElementSmallImages");
2253 InitScaledImages(); // scale all other images, if needed
2254 print_timestamp_time("InitScaledImages");
2255 InitBitmapPointers(); // set standard size bitmap pointers
2256 print_timestamp_time("InitBitmapPointers");
2257 InitFontGraphicInfo(); // initialize text drawing functions
2258 print_timestamp_time("InitFontGraphicInfo");
2259 InitGlobalAnimGraphicInfo(); // initialize global animation config
2260 print_timestamp_time("InitGlobalAnimGraphicInfo");
2262 InitImageTextures(); // create textures for certain images
2263 print_timestamp_time("InitImageTextures");
2265 InitGraphicInfo_EM(); // graphic mapping for EM engine
2266 print_timestamp_time("InitGraphicInfo_EM");
2268 InitGraphicCompatibilityInfo();
2269 print_timestamp_time("InitGraphicCompatibilityInfo");
2271 SetMainBackgroundImage(IMG_BACKGROUND);
2272 print_timestamp_time("SetMainBackgroundImage");
2273 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2274 print_timestamp_time("SetDoorBackgroundImage");
2277 print_timestamp_time("InitGadgets");
2279 print_timestamp_time("InitDoors");
2281 print_timestamp_done("ReinitializeGraphics");
2284 static void ReinitializeSounds(void)
2286 InitSoundInfo(); // sound properties mapping
2287 InitElementSoundInfo(); // element game sound mapping
2288 InitGameModeSoundInfo(); // game mode sound mapping
2289 InitGlobalAnimSoundInfo(); // global animation sound settings
2291 InitPlayLevelSound(); // internal game sound settings
2294 static void ReinitializeMusic(void)
2296 InitMusicInfo(); // music properties mapping
2297 InitGameModeMusicInfo(); // game mode music mapping
2298 InitGlobalAnimMusicInfo(); // global animation music settings
2301 static int get_special_property_bit(int element, int property_bit_nr)
2303 struct PropertyBitInfo
2309 static struct PropertyBitInfo pb_can_move_into_acid[] =
2311 // the player may be able fall into acid when gravity is activated
2316 { EL_SP_MURPHY, 0 },
2317 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2319 // all elements that can move may be able to also move into acid
2322 { EL_BUG_RIGHT, 1 },
2325 { EL_SPACESHIP, 2 },
2326 { EL_SPACESHIP_LEFT, 2 },
2327 { EL_SPACESHIP_RIGHT, 2 },
2328 { EL_SPACESHIP_UP, 2 },
2329 { EL_SPACESHIP_DOWN, 2 },
2330 { EL_BD_BUTTERFLY, 3 },
2331 { EL_BD_BUTTERFLY_LEFT, 3 },
2332 { EL_BD_BUTTERFLY_RIGHT, 3 },
2333 { EL_BD_BUTTERFLY_UP, 3 },
2334 { EL_BD_BUTTERFLY_DOWN, 3 },
2335 { EL_BD_FIREFLY, 4 },
2336 { EL_BD_FIREFLY_LEFT, 4 },
2337 { EL_BD_FIREFLY_RIGHT, 4 },
2338 { EL_BD_FIREFLY_UP, 4 },
2339 { EL_BD_FIREFLY_DOWN, 4 },
2341 { EL_YAMYAM_LEFT, 5 },
2342 { EL_YAMYAM_RIGHT, 5 },
2343 { EL_YAMYAM_UP, 5 },
2344 { EL_YAMYAM_DOWN, 5 },
2345 { EL_DARK_YAMYAM, 6 },
2348 { EL_PACMAN_LEFT, 8 },
2349 { EL_PACMAN_RIGHT, 8 },
2350 { EL_PACMAN_UP, 8 },
2351 { EL_PACMAN_DOWN, 8 },
2353 { EL_MOLE_LEFT, 9 },
2354 { EL_MOLE_RIGHT, 9 },
2356 { EL_MOLE_DOWN, 9 },
2360 { EL_SATELLITE, 13 },
2361 { EL_SP_SNIKSNAK, 14 },
2362 { EL_SP_ELECTRON, 15 },
2365 { EL_SPRING_LEFT, 17 },
2366 { EL_SPRING_RIGHT, 17 },
2367 { EL_EMC_ANDROID, 18 },
2372 static struct PropertyBitInfo pb_dont_collide_with[] =
2374 { EL_SP_SNIKSNAK, 0 },
2375 { EL_SP_ELECTRON, 1 },
2383 struct PropertyBitInfo *pb_info;
2386 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2387 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2392 struct PropertyBitInfo *pb_info = NULL;
2395 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2396 if (pb_definition[i].bit_nr == property_bit_nr)
2397 pb_info = pb_definition[i].pb_info;
2399 if (pb_info == NULL)
2402 for (i = 0; pb_info[i].element != -1; i++)
2403 if (pb_info[i].element == element)
2404 return pb_info[i].bit_nr;
2409 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2410 boolean property_value)
2412 int bit_nr = get_special_property_bit(element, property_bit_nr);
2417 *bitfield |= (1 << bit_nr);
2419 *bitfield &= ~(1 << bit_nr);
2423 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2425 int bit_nr = get_special_property_bit(element, property_bit_nr);
2428 return ((*bitfield & (1 << bit_nr)) != 0);
2433 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2435 static int group_nr;
2436 static struct ElementGroupInfo *group;
2437 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2440 if (actual_group == NULL) // not yet initialized
2443 if (recursion_depth > NUM_GROUP_ELEMENTS) // recursion too deep
2445 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2446 group_element - EL_GROUP_START + 1);
2448 // replace element which caused too deep recursion by question mark
2449 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2454 if (recursion_depth == 0) // initialization
2456 group = actual_group;
2457 group_nr = GROUP_NR(group_element);
2459 group->num_elements_resolved = 0;
2460 group->choice_pos = 0;
2462 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2463 element_info[i].in_group[group_nr] = FALSE;
2466 for (i = 0; i < actual_group->num_elements; i++)
2468 int element = actual_group->element[i];
2470 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2473 if (IS_GROUP_ELEMENT(element))
2474 ResolveGroupElementExt(element, recursion_depth + 1);
2477 group->element_resolved[group->num_elements_resolved++] = element;
2478 element_info[element].in_group[group_nr] = TRUE;
2483 void ResolveGroupElement(int group_element)
2485 ResolveGroupElementExt(group_element, 0);
2488 void InitElementPropertiesStatic(void)
2490 static boolean clipboard_elements_initialized = FALSE;
2492 static int ep_diggable[] =
2497 EL_SP_BUGGY_BASE_ACTIVATING,
2500 EL_INVISIBLE_SAND_ACTIVE,
2503 // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2504 // (if amoeba can grow into anything diggable, maybe keep these out)
2509 EL_SP_BUGGY_BASE_ACTIVE,
2516 static int ep_collectible_only[] =
2538 EL_DYNABOMB_INCREASE_NUMBER,
2539 EL_DYNABOMB_INCREASE_SIZE,
2540 EL_DYNABOMB_INCREASE_POWER,
2558 // !!! handle separately !!!
2559 EL_DC_LANDMINE, // deadly when running into, but can be snapped
2565 static int ep_dont_run_into[] =
2567 // same elements as in 'ep_dont_touch'
2573 // same elements as in 'ep_dont_collide_with'
2585 // !!! maybe this should better be handled by 'ep_diggable' !!!
2590 EL_SP_BUGGY_BASE_ACTIVE,
2597 static int ep_dont_collide_with[] =
2599 // same elements as in 'ep_dont_touch'
2616 static int ep_dont_touch[] =
2626 static int ep_indestructible[] =
2630 EL_ACID_POOL_TOPLEFT,
2631 EL_ACID_POOL_TOPRIGHT,
2632 EL_ACID_POOL_BOTTOMLEFT,
2633 EL_ACID_POOL_BOTTOM,
2634 EL_ACID_POOL_BOTTOMRIGHT,
2635 EL_SP_HARDWARE_GRAY,
2636 EL_SP_HARDWARE_GREEN,
2637 EL_SP_HARDWARE_BLUE,
2639 EL_SP_HARDWARE_YELLOW,
2640 EL_SP_HARDWARE_BASE_1,
2641 EL_SP_HARDWARE_BASE_2,
2642 EL_SP_HARDWARE_BASE_3,
2643 EL_SP_HARDWARE_BASE_4,
2644 EL_SP_HARDWARE_BASE_5,
2645 EL_SP_HARDWARE_BASE_6,
2646 EL_INVISIBLE_STEELWALL,
2647 EL_INVISIBLE_STEELWALL_ACTIVE,
2648 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2649 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2650 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2651 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2652 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2653 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2654 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2655 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2656 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2657 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2658 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2659 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2661 EL_LIGHT_SWITCH_ACTIVE,
2662 EL_SIGN_EXCLAMATION,
2663 EL_SIGN_RADIOACTIVITY,
2670 EL_SIGN_ENTRY_FORBIDDEN,
2671 EL_SIGN_EMERGENCY_EXIT,
2679 EL_STEEL_EXIT_CLOSED,
2681 EL_STEEL_EXIT_OPENING,
2682 EL_STEEL_EXIT_CLOSING,
2683 EL_EM_STEEL_EXIT_CLOSED,
2684 EL_EM_STEEL_EXIT_OPEN,
2685 EL_EM_STEEL_EXIT_OPENING,
2686 EL_EM_STEEL_EXIT_CLOSING,
2687 EL_DC_STEELWALL_1_LEFT,
2688 EL_DC_STEELWALL_1_RIGHT,
2689 EL_DC_STEELWALL_1_TOP,
2690 EL_DC_STEELWALL_1_BOTTOM,
2691 EL_DC_STEELWALL_1_HORIZONTAL,
2692 EL_DC_STEELWALL_1_VERTICAL,
2693 EL_DC_STEELWALL_1_TOPLEFT,
2694 EL_DC_STEELWALL_1_TOPRIGHT,
2695 EL_DC_STEELWALL_1_BOTTOMLEFT,
2696 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2697 EL_DC_STEELWALL_1_TOPLEFT_2,
2698 EL_DC_STEELWALL_1_TOPRIGHT_2,
2699 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2700 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2701 EL_DC_STEELWALL_2_LEFT,
2702 EL_DC_STEELWALL_2_RIGHT,
2703 EL_DC_STEELWALL_2_TOP,
2704 EL_DC_STEELWALL_2_BOTTOM,
2705 EL_DC_STEELWALL_2_HORIZONTAL,
2706 EL_DC_STEELWALL_2_VERTICAL,
2707 EL_DC_STEELWALL_2_MIDDLE,
2708 EL_DC_STEELWALL_2_SINGLE,
2709 EL_STEELWALL_SLIPPERY,
2723 EL_GATE_1_GRAY_ACTIVE,
2724 EL_GATE_2_GRAY_ACTIVE,
2725 EL_GATE_3_GRAY_ACTIVE,
2726 EL_GATE_4_GRAY_ACTIVE,
2735 EL_EM_GATE_1_GRAY_ACTIVE,
2736 EL_EM_GATE_2_GRAY_ACTIVE,
2737 EL_EM_GATE_3_GRAY_ACTIVE,
2738 EL_EM_GATE_4_GRAY_ACTIVE,
2747 EL_EMC_GATE_5_GRAY_ACTIVE,
2748 EL_EMC_GATE_6_GRAY_ACTIVE,
2749 EL_EMC_GATE_7_GRAY_ACTIVE,
2750 EL_EMC_GATE_8_GRAY_ACTIVE,
2752 EL_DC_GATE_WHITE_GRAY,
2753 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2754 EL_DC_GATE_FAKE_GRAY,
2756 EL_SWITCHGATE_OPENING,
2757 EL_SWITCHGATE_CLOSED,
2758 EL_SWITCHGATE_CLOSING,
2759 EL_DC_SWITCHGATE_SWITCH_UP,
2760 EL_DC_SWITCHGATE_SWITCH_DOWN,
2762 EL_TIMEGATE_OPENING,
2764 EL_TIMEGATE_CLOSING,
2765 EL_DC_TIMEGATE_SWITCH,
2766 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2770 EL_TUBE_VERTICAL_LEFT,
2771 EL_TUBE_VERTICAL_RIGHT,
2772 EL_TUBE_HORIZONTAL_UP,
2773 EL_TUBE_HORIZONTAL_DOWN,
2778 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2779 EL_EXPANDABLE_STEELWALL_VERTICAL,
2780 EL_EXPANDABLE_STEELWALL_ANY,
2785 static int ep_slippery[] =
2799 EL_ROBOT_WHEEL_ACTIVE,
2805 EL_ACID_POOL_TOPLEFT,
2806 EL_ACID_POOL_TOPRIGHT,
2816 EL_STEELWALL_SLIPPERY,
2819 EL_EMC_WALL_SLIPPERY_1,
2820 EL_EMC_WALL_SLIPPERY_2,
2821 EL_EMC_WALL_SLIPPERY_3,
2822 EL_EMC_WALL_SLIPPERY_4,
2824 EL_EMC_MAGIC_BALL_ACTIVE,
2829 static int ep_can_change[] =
2834 static int ep_can_move[] =
2836 // same elements as in 'pb_can_move_into_acid'
2859 static int ep_can_fall[] =
2874 EL_QUICKSAND_FAST_FULL,
2876 EL_BD_MAGIC_WALL_FULL,
2877 EL_DC_MAGIC_WALL_FULL,
2891 static int ep_can_smash_player[] =
2917 static int ep_can_smash_enemies[] =
2926 static int ep_can_smash_everything[] =
2935 static int ep_explodes_by_fire[] =
2937 // same elements as in 'ep_explodes_impact'
2942 // same elements as in 'ep_explodes_smashed'
2952 EL_EM_DYNAMITE_ACTIVE,
2953 EL_DYNABOMB_PLAYER_1_ACTIVE,
2954 EL_DYNABOMB_PLAYER_2_ACTIVE,
2955 EL_DYNABOMB_PLAYER_3_ACTIVE,
2956 EL_DYNABOMB_PLAYER_4_ACTIVE,
2957 EL_DYNABOMB_INCREASE_NUMBER,
2958 EL_DYNABOMB_INCREASE_SIZE,
2959 EL_DYNABOMB_INCREASE_POWER,
2960 EL_SP_DISK_RED_ACTIVE,
2974 static int ep_explodes_smashed[] =
2976 // same elements as in 'ep_explodes_impact'
2990 static int ep_explodes_impact[] =
2999 static int ep_walkable_over[] =
3003 EL_SOKOBAN_FIELD_EMPTY,
3010 EL_EM_STEEL_EXIT_OPEN,
3011 EL_EM_STEEL_EXIT_OPENING,
3020 EL_GATE_1_GRAY_ACTIVE,
3021 EL_GATE_2_GRAY_ACTIVE,
3022 EL_GATE_3_GRAY_ACTIVE,
3023 EL_GATE_4_GRAY_ACTIVE,
3031 static int ep_walkable_inside[] =
3036 EL_TUBE_VERTICAL_LEFT,
3037 EL_TUBE_VERTICAL_RIGHT,
3038 EL_TUBE_HORIZONTAL_UP,
3039 EL_TUBE_HORIZONTAL_DOWN,
3048 static int ep_walkable_under[] =
3053 static int ep_passable_over[] =
3063 EL_EM_GATE_1_GRAY_ACTIVE,
3064 EL_EM_GATE_2_GRAY_ACTIVE,
3065 EL_EM_GATE_3_GRAY_ACTIVE,
3066 EL_EM_GATE_4_GRAY_ACTIVE,
3075 EL_EMC_GATE_5_GRAY_ACTIVE,
3076 EL_EMC_GATE_6_GRAY_ACTIVE,
3077 EL_EMC_GATE_7_GRAY_ACTIVE,
3078 EL_EMC_GATE_8_GRAY_ACTIVE,
3080 EL_DC_GATE_WHITE_GRAY,
3081 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3088 static int ep_passable_inside[] =
3094 EL_SP_PORT_HORIZONTAL,
3095 EL_SP_PORT_VERTICAL,
3097 EL_SP_GRAVITY_PORT_LEFT,
3098 EL_SP_GRAVITY_PORT_RIGHT,
3099 EL_SP_GRAVITY_PORT_UP,
3100 EL_SP_GRAVITY_PORT_DOWN,
3101 EL_SP_GRAVITY_ON_PORT_LEFT,
3102 EL_SP_GRAVITY_ON_PORT_RIGHT,
3103 EL_SP_GRAVITY_ON_PORT_UP,
3104 EL_SP_GRAVITY_ON_PORT_DOWN,
3105 EL_SP_GRAVITY_OFF_PORT_LEFT,
3106 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3107 EL_SP_GRAVITY_OFF_PORT_UP,
3108 EL_SP_GRAVITY_OFF_PORT_DOWN,
3113 static int ep_passable_under[] =
3118 static int ep_droppable[] =
3123 static int ep_explodes_1x1_old[] =
3128 static int ep_pushable[] =
3140 EL_SOKOBAN_FIELD_FULL,
3149 static int ep_explodes_cross_old[] =
3154 static int ep_protected[] =
3156 // same elements as in 'ep_walkable_inside'
3160 EL_TUBE_VERTICAL_LEFT,
3161 EL_TUBE_VERTICAL_RIGHT,
3162 EL_TUBE_HORIZONTAL_UP,
3163 EL_TUBE_HORIZONTAL_DOWN,
3169 // same elements as in 'ep_passable_over'
3178 EL_EM_GATE_1_GRAY_ACTIVE,
3179 EL_EM_GATE_2_GRAY_ACTIVE,
3180 EL_EM_GATE_3_GRAY_ACTIVE,
3181 EL_EM_GATE_4_GRAY_ACTIVE,
3190 EL_EMC_GATE_5_GRAY_ACTIVE,
3191 EL_EMC_GATE_6_GRAY_ACTIVE,
3192 EL_EMC_GATE_7_GRAY_ACTIVE,
3193 EL_EMC_GATE_8_GRAY_ACTIVE,
3195 EL_DC_GATE_WHITE_GRAY,
3196 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3200 // same elements as in 'ep_passable_inside'
3205 EL_SP_PORT_HORIZONTAL,
3206 EL_SP_PORT_VERTICAL,
3208 EL_SP_GRAVITY_PORT_LEFT,
3209 EL_SP_GRAVITY_PORT_RIGHT,
3210 EL_SP_GRAVITY_PORT_UP,
3211 EL_SP_GRAVITY_PORT_DOWN,
3212 EL_SP_GRAVITY_ON_PORT_LEFT,
3213 EL_SP_GRAVITY_ON_PORT_RIGHT,
3214 EL_SP_GRAVITY_ON_PORT_UP,
3215 EL_SP_GRAVITY_ON_PORT_DOWN,
3216 EL_SP_GRAVITY_OFF_PORT_LEFT,
3217 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3218 EL_SP_GRAVITY_OFF_PORT_UP,
3219 EL_SP_GRAVITY_OFF_PORT_DOWN,
3224 static int ep_throwable[] =
3229 static int ep_can_explode[] =
3231 // same elements as in 'ep_explodes_impact'
3236 // same elements as in 'ep_explodes_smashed'
3242 // elements that can explode by explosion or by dragonfire
3246 EL_EM_DYNAMITE_ACTIVE,
3247 EL_DYNABOMB_PLAYER_1_ACTIVE,
3248 EL_DYNABOMB_PLAYER_2_ACTIVE,
3249 EL_DYNABOMB_PLAYER_3_ACTIVE,
3250 EL_DYNABOMB_PLAYER_4_ACTIVE,
3251 EL_DYNABOMB_INCREASE_NUMBER,
3252 EL_DYNABOMB_INCREASE_SIZE,
3253 EL_DYNABOMB_INCREASE_POWER,
3254 EL_SP_DISK_RED_ACTIVE,
3262 // elements that can explode only by explosion
3268 static int ep_gravity_reachable[] =
3274 EL_INVISIBLE_SAND_ACTIVE,
3279 EL_SP_PORT_HORIZONTAL,
3280 EL_SP_PORT_VERTICAL,
3282 EL_SP_GRAVITY_PORT_LEFT,
3283 EL_SP_GRAVITY_PORT_RIGHT,
3284 EL_SP_GRAVITY_PORT_UP,
3285 EL_SP_GRAVITY_PORT_DOWN,
3286 EL_SP_GRAVITY_ON_PORT_LEFT,
3287 EL_SP_GRAVITY_ON_PORT_RIGHT,
3288 EL_SP_GRAVITY_ON_PORT_UP,
3289 EL_SP_GRAVITY_ON_PORT_DOWN,
3290 EL_SP_GRAVITY_OFF_PORT_LEFT,
3291 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3292 EL_SP_GRAVITY_OFF_PORT_UP,
3293 EL_SP_GRAVITY_OFF_PORT_DOWN,
3299 static int ep_player[] =
3306 EL_SOKOBAN_FIELD_PLAYER,
3312 static int ep_can_pass_magic_wall[] =
3326 static int ep_can_pass_dc_magic_wall[] =
3342 static int ep_switchable[] =
3346 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3347 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3348 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3349 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3350 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3351 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3352 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3353 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3354 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3355 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3356 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3357 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3358 EL_SWITCHGATE_SWITCH_UP,
3359 EL_SWITCHGATE_SWITCH_DOWN,
3360 EL_DC_SWITCHGATE_SWITCH_UP,
3361 EL_DC_SWITCHGATE_SWITCH_DOWN,
3363 EL_LIGHT_SWITCH_ACTIVE,
3365 EL_DC_TIMEGATE_SWITCH,
3366 EL_BALLOON_SWITCH_LEFT,
3367 EL_BALLOON_SWITCH_RIGHT,
3368 EL_BALLOON_SWITCH_UP,
3369 EL_BALLOON_SWITCH_DOWN,
3370 EL_BALLOON_SWITCH_ANY,
3371 EL_BALLOON_SWITCH_NONE,
3374 EL_EMC_MAGIC_BALL_SWITCH,
3375 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3380 static int ep_bd_element[] =
3414 static int ep_sp_element[] =
3416 // should always be valid
3419 // standard classic Supaplex elements
3426 EL_SP_HARDWARE_GRAY,
3434 EL_SP_GRAVITY_PORT_RIGHT,
3435 EL_SP_GRAVITY_PORT_DOWN,
3436 EL_SP_GRAVITY_PORT_LEFT,
3437 EL_SP_GRAVITY_PORT_UP,
3442 EL_SP_PORT_VERTICAL,
3443 EL_SP_PORT_HORIZONTAL,
3449 EL_SP_HARDWARE_BASE_1,
3450 EL_SP_HARDWARE_GREEN,
3451 EL_SP_HARDWARE_BLUE,
3453 EL_SP_HARDWARE_YELLOW,
3454 EL_SP_HARDWARE_BASE_2,
3455 EL_SP_HARDWARE_BASE_3,
3456 EL_SP_HARDWARE_BASE_4,
3457 EL_SP_HARDWARE_BASE_5,
3458 EL_SP_HARDWARE_BASE_6,
3462 // additional elements that appeared in newer Supaplex levels
3465 // additional gravity port elements (not switching, but setting gravity)
3466 EL_SP_GRAVITY_ON_PORT_LEFT,
3467 EL_SP_GRAVITY_ON_PORT_RIGHT,
3468 EL_SP_GRAVITY_ON_PORT_UP,
3469 EL_SP_GRAVITY_ON_PORT_DOWN,
3470 EL_SP_GRAVITY_OFF_PORT_LEFT,
3471 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3472 EL_SP_GRAVITY_OFF_PORT_UP,
3473 EL_SP_GRAVITY_OFF_PORT_DOWN,
3475 // more than one Murphy in a level results in an inactive clone
3478 // runtime Supaplex elements
3479 EL_SP_DISK_RED_ACTIVE,
3480 EL_SP_TERMINAL_ACTIVE,
3481 EL_SP_BUGGY_BASE_ACTIVATING,
3482 EL_SP_BUGGY_BASE_ACTIVE,
3489 static int ep_sb_element[] =
3494 EL_SOKOBAN_FIELD_EMPTY,
3495 EL_SOKOBAN_FIELD_FULL,
3496 EL_SOKOBAN_FIELD_PLAYER,
3501 EL_INVISIBLE_STEELWALL,
3506 static int ep_gem[] =
3518 static int ep_food_dark_yamyam[] =
3546 static int ep_food_penguin[] =
3560 static int ep_food_pig[] =
3572 static int ep_historic_wall[] =
3583 EL_GATE_1_GRAY_ACTIVE,
3584 EL_GATE_2_GRAY_ACTIVE,
3585 EL_GATE_3_GRAY_ACTIVE,
3586 EL_GATE_4_GRAY_ACTIVE,
3595 EL_EM_GATE_1_GRAY_ACTIVE,
3596 EL_EM_GATE_2_GRAY_ACTIVE,
3597 EL_EM_GATE_3_GRAY_ACTIVE,
3598 EL_EM_GATE_4_GRAY_ACTIVE,
3605 EL_EXPANDABLE_WALL_HORIZONTAL,
3606 EL_EXPANDABLE_WALL_VERTICAL,
3607 EL_EXPANDABLE_WALL_ANY,
3608 EL_EXPANDABLE_WALL_GROWING,
3609 EL_BD_EXPANDABLE_WALL,
3616 EL_SP_HARDWARE_GRAY,
3617 EL_SP_HARDWARE_GREEN,
3618 EL_SP_HARDWARE_BLUE,
3620 EL_SP_HARDWARE_YELLOW,
3621 EL_SP_HARDWARE_BASE_1,
3622 EL_SP_HARDWARE_BASE_2,
3623 EL_SP_HARDWARE_BASE_3,
3624 EL_SP_HARDWARE_BASE_4,
3625 EL_SP_HARDWARE_BASE_5,
3626 EL_SP_HARDWARE_BASE_6,
3628 EL_SP_TERMINAL_ACTIVE,
3631 EL_INVISIBLE_STEELWALL,
3632 EL_INVISIBLE_STEELWALL_ACTIVE,
3634 EL_INVISIBLE_WALL_ACTIVE,
3635 EL_STEELWALL_SLIPPERY,
3652 static int ep_historic_solid[] =
3656 EL_EXPANDABLE_WALL_HORIZONTAL,
3657 EL_EXPANDABLE_WALL_VERTICAL,
3658 EL_EXPANDABLE_WALL_ANY,
3659 EL_BD_EXPANDABLE_WALL,
3672 EL_QUICKSAND_FILLING,
3673 EL_QUICKSAND_EMPTYING,
3675 EL_MAGIC_WALL_ACTIVE,
3676 EL_MAGIC_WALL_EMPTYING,
3677 EL_MAGIC_WALL_FILLING,
3681 EL_BD_MAGIC_WALL_ACTIVE,
3682 EL_BD_MAGIC_WALL_EMPTYING,
3683 EL_BD_MAGIC_WALL_FULL,
3684 EL_BD_MAGIC_WALL_FILLING,
3685 EL_BD_MAGIC_WALL_DEAD,
3694 EL_SP_TERMINAL_ACTIVE,
3698 EL_INVISIBLE_WALL_ACTIVE,
3699 EL_SWITCHGATE_SWITCH_UP,
3700 EL_SWITCHGATE_SWITCH_DOWN,
3702 EL_TIMEGATE_SWITCH_ACTIVE,
3714 // the following elements are a direct copy of "indestructible" elements,
3715 // except "EL_ACID", which is "indestructible", but not "solid"!
3720 EL_ACID_POOL_TOPLEFT,
3721 EL_ACID_POOL_TOPRIGHT,
3722 EL_ACID_POOL_BOTTOMLEFT,
3723 EL_ACID_POOL_BOTTOM,
3724 EL_ACID_POOL_BOTTOMRIGHT,
3725 EL_SP_HARDWARE_GRAY,
3726 EL_SP_HARDWARE_GREEN,
3727 EL_SP_HARDWARE_BLUE,
3729 EL_SP_HARDWARE_YELLOW,
3730 EL_SP_HARDWARE_BASE_1,
3731 EL_SP_HARDWARE_BASE_2,
3732 EL_SP_HARDWARE_BASE_3,
3733 EL_SP_HARDWARE_BASE_4,
3734 EL_SP_HARDWARE_BASE_5,
3735 EL_SP_HARDWARE_BASE_6,
3736 EL_INVISIBLE_STEELWALL,
3737 EL_INVISIBLE_STEELWALL_ACTIVE,
3738 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3739 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3740 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3741 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3742 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3743 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3744 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3745 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3746 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3747 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3748 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3749 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3751 EL_LIGHT_SWITCH_ACTIVE,
3752 EL_SIGN_EXCLAMATION,
3753 EL_SIGN_RADIOACTIVITY,
3760 EL_SIGN_ENTRY_FORBIDDEN,
3761 EL_SIGN_EMERGENCY_EXIT,
3769 EL_STEEL_EXIT_CLOSED,
3771 EL_STEEL_EXIT_OPENING,
3772 EL_STEEL_EXIT_CLOSING,
3773 EL_EM_STEEL_EXIT_CLOSED,
3774 EL_EM_STEEL_EXIT_OPEN,
3775 EL_EM_STEEL_EXIT_OPENING,
3776 EL_EM_STEEL_EXIT_CLOSING,
3777 EL_DC_STEELWALL_1_LEFT,
3778 EL_DC_STEELWALL_1_RIGHT,
3779 EL_DC_STEELWALL_1_TOP,
3780 EL_DC_STEELWALL_1_BOTTOM,
3781 EL_DC_STEELWALL_1_HORIZONTAL,
3782 EL_DC_STEELWALL_1_VERTICAL,
3783 EL_DC_STEELWALL_1_TOPLEFT,
3784 EL_DC_STEELWALL_1_TOPRIGHT,
3785 EL_DC_STEELWALL_1_BOTTOMLEFT,
3786 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3787 EL_DC_STEELWALL_1_TOPLEFT_2,
3788 EL_DC_STEELWALL_1_TOPRIGHT_2,
3789 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3790 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3791 EL_DC_STEELWALL_2_LEFT,
3792 EL_DC_STEELWALL_2_RIGHT,
3793 EL_DC_STEELWALL_2_TOP,
3794 EL_DC_STEELWALL_2_BOTTOM,
3795 EL_DC_STEELWALL_2_HORIZONTAL,
3796 EL_DC_STEELWALL_2_VERTICAL,
3797 EL_DC_STEELWALL_2_MIDDLE,
3798 EL_DC_STEELWALL_2_SINGLE,
3799 EL_STEELWALL_SLIPPERY,
3813 EL_GATE_1_GRAY_ACTIVE,
3814 EL_GATE_2_GRAY_ACTIVE,
3815 EL_GATE_3_GRAY_ACTIVE,
3816 EL_GATE_4_GRAY_ACTIVE,
3825 EL_EM_GATE_1_GRAY_ACTIVE,
3826 EL_EM_GATE_2_GRAY_ACTIVE,
3827 EL_EM_GATE_3_GRAY_ACTIVE,
3828 EL_EM_GATE_4_GRAY_ACTIVE,
3837 EL_EMC_GATE_5_GRAY_ACTIVE,
3838 EL_EMC_GATE_6_GRAY_ACTIVE,
3839 EL_EMC_GATE_7_GRAY_ACTIVE,
3840 EL_EMC_GATE_8_GRAY_ACTIVE,
3842 EL_DC_GATE_WHITE_GRAY,
3843 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3844 EL_DC_GATE_FAKE_GRAY,
3846 EL_SWITCHGATE_OPENING,
3847 EL_SWITCHGATE_CLOSED,
3848 EL_SWITCHGATE_CLOSING,
3849 EL_DC_SWITCHGATE_SWITCH_UP,
3850 EL_DC_SWITCHGATE_SWITCH_DOWN,
3852 EL_TIMEGATE_OPENING,
3854 EL_TIMEGATE_CLOSING,
3855 EL_DC_TIMEGATE_SWITCH,
3856 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3860 EL_TUBE_VERTICAL_LEFT,
3861 EL_TUBE_VERTICAL_RIGHT,
3862 EL_TUBE_HORIZONTAL_UP,
3863 EL_TUBE_HORIZONTAL_DOWN,
3868 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3869 EL_EXPANDABLE_STEELWALL_VERTICAL,
3870 EL_EXPANDABLE_STEELWALL_ANY,
3875 static int ep_classic_enemy[] =
3892 static int ep_belt[] =
3894 EL_CONVEYOR_BELT_1_LEFT,
3895 EL_CONVEYOR_BELT_1_MIDDLE,
3896 EL_CONVEYOR_BELT_1_RIGHT,
3897 EL_CONVEYOR_BELT_2_LEFT,
3898 EL_CONVEYOR_BELT_2_MIDDLE,
3899 EL_CONVEYOR_BELT_2_RIGHT,
3900 EL_CONVEYOR_BELT_3_LEFT,
3901 EL_CONVEYOR_BELT_3_MIDDLE,
3902 EL_CONVEYOR_BELT_3_RIGHT,
3903 EL_CONVEYOR_BELT_4_LEFT,
3904 EL_CONVEYOR_BELT_4_MIDDLE,
3905 EL_CONVEYOR_BELT_4_RIGHT,
3910 static int ep_belt_active[] =
3912 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3913 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3914 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3915 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3916 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3917 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3918 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3919 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3920 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3921 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3922 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3923 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3928 static int ep_belt_switch[] =
3930 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3931 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3932 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3933 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3934 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3935 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3936 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3937 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3938 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3939 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3940 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3941 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3946 static int ep_tube[] =
3953 EL_TUBE_HORIZONTAL_UP,
3954 EL_TUBE_HORIZONTAL_DOWN,
3956 EL_TUBE_VERTICAL_LEFT,
3957 EL_TUBE_VERTICAL_RIGHT,
3963 static int ep_acid_pool[] =
3965 EL_ACID_POOL_TOPLEFT,
3966 EL_ACID_POOL_TOPRIGHT,
3967 EL_ACID_POOL_BOTTOMLEFT,
3968 EL_ACID_POOL_BOTTOM,
3969 EL_ACID_POOL_BOTTOMRIGHT,
3974 static int ep_keygate[] =
3984 EL_GATE_1_GRAY_ACTIVE,
3985 EL_GATE_2_GRAY_ACTIVE,
3986 EL_GATE_3_GRAY_ACTIVE,
3987 EL_GATE_4_GRAY_ACTIVE,
3996 EL_EM_GATE_1_GRAY_ACTIVE,
3997 EL_EM_GATE_2_GRAY_ACTIVE,
3998 EL_EM_GATE_3_GRAY_ACTIVE,
3999 EL_EM_GATE_4_GRAY_ACTIVE,
4008 EL_EMC_GATE_5_GRAY_ACTIVE,
4009 EL_EMC_GATE_6_GRAY_ACTIVE,
4010 EL_EMC_GATE_7_GRAY_ACTIVE,
4011 EL_EMC_GATE_8_GRAY_ACTIVE,
4013 EL_DC_GATE_WHITE_GRAY,
4014 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4019 static int ep_amoeboid[] =
4031 static int ep_amoebalive[] =
4042 static int ep_has_editor_content[] =
4048 EL_SOKOBAN_FIELD_PLAYER,
4065 static int ep_can_turn_each_move[] =
4067 // !!! do something with this one !!!
4071 static int ep_can_grow[] =
4085 static int ep_active_bomb[] =
4088 EL_EM_DYNAMITE_ACTIVE,
4089 EL_DYNABOMB_PLAYER_1_ACTIVE,
4090 EL_DYNABOMB_PLAYER_2_ACTIVE,
4091 EL_DYNABOMB_PLAYER_3_ACTIVE,
4092 EL_DYNABOMB_PLAYER_4_ACTIVE,
4093 EL_SP_DISK_RED_ACTIVE,
4098 static int ep_inactive[] =
4108 EL_QUICKSAND_FAST_EMPTY,
4131 EL_GATE_1_GRAY_ACTIVE,
4132 EL_GATE_2_GRAY_ACTIVE,
4133 EL_GATE_3_GRAY_ACTIVE,
4134 EL_GATE_4_GRAY_ACTIVE,
4143 EL_EM_GATE_1_GRAY_ACTIVE,
4144 EL_EM_GATE_2_GRAY_ACTIVE,
4145 EL_EM_GATE_3_GRAY_ACTIVE,
4146 EL_EM_GATE_4_GRAY_ACTIVE,
4155 EL_EMC_GATE_5_GRAY_ACTIVE,
4156 EL_EMC_GATE_6_GRAY_ACTIVE,
4157 EL_EMC_GATE_7_GRAY_ACTIVE,
4158 EL_EMC_GATE_8_GRAY_ACTIVE,
4160 EL_DC_GATE_WHITE_GRAY,
4161 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4162 EL_DC_GATE_FAKE_GRAY,
4165 EL_INVISIBLE_STEELWALL,
4173 EL_WALL_EMERALD_YELLOW,
4174 EL_DYNABOMB_INCREASE_NUMBER,
4175 EL_DYNABOMB_INCREASE_SIZE,
4176 EL_DYNABOMB_INCREASE_POWER,
4180 EL_SOKOBAN_FIELD_EMPTY,
4181 EL_SOKOBAN_FIELD_FULL,
4182 EL_WALL_EMERALD_RED,
4183 EL_WALL_EMERALD_PURPLE,
4184 EL_ACID_POOL_TOPLEFT,
4185 EL_ACID_POOL_TOPRIGHT,
4186 EL_ACID_POOL_BOTTOMLEFT,
4187 EL_ACID_POOL_BOTTOM,
4188 EL_ACID_POOL_BOTTOMRIGHT,
4192 EL_BD_MAGIC_WALL_DEAD,
4194 EL_DC_MAGIC_WALL_DEAD,
4195 EL_AMOEBA_TO_DIAMOND,
4203 EL_SP_GRAVITY_PORT_RIGHT,
4204 EL_SP_GRAVITY_PORT_DOWN,
4205 EL_SP_GRAVITY_PORT_LEFT,
4206 EL_SP_GRAVITY_PORT_UP,
4207 EL_SP_PORT_HORIZONTAL,
4208 EL_SP_PORT_VERTICAL,
4219 EL_SP_HARDWARE_GRAY,
4220 EL_SP_HARDWARE_GREEN,
4221 EL_SP_HARDWARE_BLUE,
4223 EL_SP_HARDWARE_YELLOW,
4224 EL_SP_HARDWARE_BASE_1,
4225 EL_SP_HARDWARE_BASE_2,
4226 EL_SP_HARDWARE_BASE_3,
4227 EL_SP_HARDWARE_BASE_4,
4228 EL_SP_HARDWARE_BASE_5,
4229 EL_SP_HARDWARE_BASE_6,
4230 EL_SP_GRAVITY_ON_PORT_LEFT,
4231 EL_SP_GRAVITY_ON_PORT_RIGHT,
4232 EL_SP_GRAVITY_ON_PORT_UP,
4233 EL_SP_GRAVITY_ON_PORT_DOWN,
4234 EL_SP_GRAVITY_OFF_PORT_LEFT,
4235 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4236 EL_SP_GRAVITY_OFF_PORT_UP,
4237 EL_SP_GRAVITY_OFF_PORT_DOWN,
4238 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4239 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4240 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4241 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4242 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4243 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4244 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4245 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4246 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4247 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4248 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4249 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4250 EL_SIGN_EXCLAMATION,
4251 EL_SIGN_RADIOACTIVITY,
4258 EL_SIGN_ENTRY_FORBIDDEN,
4259 EL_SIGN_EMERGENCY_EXIT,
4267 EL_DC_STEELWALL_1_LEFT,
4268 EL_DC_STEELWALL_1_RIGHT,
4269 EL_DC_STEELWALL_1_TOP,
4270 EL_DC_STEELWALL_1_BOTTOM,
4271 EL_DC_STEELWALL_1_HORIZONTAL,
4272 EL_DC_STEELWALL_1_VERTICAL,
4273 EL_DC_STEELWALL_1_TOPLEFT,
4274 EL_DC_STEELWALL_1_TOPRIGHT,
4275 EL_DC_STEELWALL_1_BOTTOMLEFT,
4276 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4277 EL_DC_STEELWALL_1_TOPLEFT_2,
4278 EL_DC_STEELWALL_1_TOPRIGHT_2,
4279 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4280 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4281 EL_DC_STEELWALL_2_LEFT,
4282 EL_DC_STEELWALL_2_RIGHT,
4283 EL_DC_STEELWALL_2_TOP,
4284 EL_DC_STEELWALL_2_BOTTOM,
4285 EL_DC_STEELWALL_2_HORIZONTAL,
4286 EL_DC_STEELWALL_2_VERTICAL,
4287 EL_DC_STEELWALL_2_MIDDLE,
4288 EL_DC_STEELWALL_2_SINGLE,
4289 EL_STEELWALL_SLIPPERY,
4294 EL_EMC_WALL_SLIPPERY_1,
4295 EL_EMC_WALL_SLIPPERY_2,
4296 EL_EMC_WALL_SLIPPERY_3,
4297 EL_EMC_WALL_SLIPPERY_4,
4318 static int ep_em_slippery_wall[] =
4323 static int ep_gfx_crumbled[] =
4334 static int ep_editor_cascade_active[] =
4336 EL_INTERNAL_CASCADE_BD_ACTIVE,
4337 EL_INTERNAL_CASCADE_EM_ACTIVE,
4338 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4339 EL_INTERNAL_CASCADE_RND_ACTIVE,
4340 EL_INTERNAL_CASCADE_SB_ACTIVE,
4341 EL_INTERNAL_CASCADE_SP_ACTIVE,
4342 EL_INTERNAL_CASCADE_DC_ACTIVE,
4343 EL_INTERNAL_CASCADE_DX_ACTIVE,
4344 EL_INTERNAL_CASCADE_MM_ACTIVE,
4345 EL_INTERNAL_CASCADE_DF_ACTIVE,
4346 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4347 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4348 EL_INTERNAL_CASCADE_CE_ACTIVE,
4349 EL_INTERNAL_CASCADE_GE_ACTIVE,
4350 EL_INTERNAL_CASCADE_REF_ACTIVE,
4351 EL_INTERNAL_CASCADE_USER_ACTIVE,
4352 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4357 static int ep_editor_cascade_inactive[] =
4359 EL_INTERNAL_CASCADE_BD,
4360 EL_INTERNAL_CASCADE_EM,
4361 EL_INTERNAL_CASCADE_EMC,
4362 EL_INTERNAL_CASCADE_RND,
4363 EL_INTERNAL_CASCADE_SB,
4364 EL_INTERNAL_CASCADE_SP,
4365 EL_INTERNAL_CASCADE_DC,
4366 EL_INTERNAL_CASCADE_DX,
4367 EL_INTERNAL_CASCADE_MM,
4368 EL_INTERNAL_CASCADE_DF,
4369 EL_INTERNAL_CASCADE_CHARS,
4370 EL_INTERNAL_CASCADE_STEEL_CHARS,
4371 EL_INTERNAL_CASCADE_CE,
4372 EL_INTERNAL_CASCADE_GE,
4373 EL_INTERNAL_CASCADE_REF,
4374 EL_INTERNAL_CASCADE_USER,
4375 EL_INTERNAL_CASCADE_DYNAMIC,
4380 static int ep_obsolete[] =
4384 EL_EM_KEY_1_FILE_OBSOLETE,
4385 EL_EM_KEY_2_FILE_OBSOLETE,
4386 EL_EM_KEY_3_FILE_OBSOLETE,
4387 EL_EM_KEY_4_FILE_OBSOLETE,
4388 EL_ENVELOPE_OBSOLETE,
4397 } element_properties[] =
4399 { ep_diggable, EP_DIGGABLE },
4400 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4401 { ep_dont_run_into, EP_DONT_RUN_INTO },
4402 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4403 { ep_dont_touch, EP_DONT_TOUCH },
4404 { ep_indestructible, EP_INDESTRUCTIBLE },
4405 { ep_slippery, EP_SLIPPERY },
4406 { ep_can_change, EP_CAN_CHANGE },
4407 { ep_can_move, EP_CAN_MOVE },
4408 { ep_can_fall, EP_CAN_FALL },
4409 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4410 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4411 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4412 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4413 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4414 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4415 { ep_walkable_over, EP_WALKABLE_OVER },
4416 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4417 { ep_walkable_under, EP_WALKABLE_UNDER },
4418 { ep_passable_over, EP_PASSABLE_OVER },
4419 { ep_passable_inside, EP_PASSABLE_INSIDE },
4420 { ep_passable_under, EP_PASSABLE_UNDER },
4421 { ep_droppable, EP_DROPPABLE },
4422 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4423 { ep_pushable, EP_PUSHABLE },
4424 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4425 { ep_protected, EP_PROTECTED },
4426 { ep_throwable, EP_THROWABLE },
4427 { ep_can_explode, EP_CAN_EXPLODE },
4428 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4430 { ep_player, EP_PLAYER },
4431 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4432 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4433 { ep_switchable, EP_SWITCHABLE },
4434 { ep_bd_element, EP_BD_ELEMENT },
4435 { ep_sp_element, EP_SP_ELEMENT },
4436 { ep_sb_element, EP_SB_ELEMENT },
4438 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4439 { ep_food_penguin, EP_FOOD_PENGUIN },
4440 { ep_food_pig, EP_FOOD_PIG },
4441 { ep_historic_wall, EP_HISTORIC_WALL },
4442 { ep_historic_solid, EP_HISTORIC_SOLID },
4443 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4444 { ep_belt, EP_BELT },
4445 { ep_belt_active, EP_BELT_ACTIVE },
4446 { ep_belt_switch, EP_BELT_SWITCH },
4447 { ep_tube, EP_TUBE },
4448 { ep_acid_pool, EP_ACID_POOL },
4449 { ep_keygate, EP_KEYGATE },
4450 { ep_amoeboid, EP_AMOEBOID },
4451 { ep_amoebalive, EP_AMOEBALIVE },
4452 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4453 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4454 { ep_can_grow, EP_CAN_GROW },
4455 { ep_active_bomb, EP_ACTIVE_BOMB },
4456 { ep_inactive, EP_INACTIVE },
4458 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4460 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4462 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4463 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4465 { ep_obsolete, EP_OBSOLETE },
4472 // always start with reliable default values (element has no properties)
4473 // (but never initialize clipboard elements after the very first time)
4474 // (to be able to use clipboard elements between several levels)
4475 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4476 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4477 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4478 SET_PROPERTY(i, j, FALSE);
4480 // set all base element properties from above array definitions
4481 for (i = 0; element_properties[i].elements != NULL; i++)
4482 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4483 SET_PROPERTY((element_properties[i].elements)[j],
4484 element_properties[i].property, TRUE);
4486 // copy properties to some elements that are only stored in level file
4487 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4488 for (j = 0; copy_properties[j][0] != -1; j++)
4489 if (HAS_PROPERTY(copy_properties[j][0], i))
4490 for (k = 1; k <= 4; k++)
4491 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4493 // set static element properties that are not listed in array definitions
4494 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4495 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4497 clipboard_elements_initialized = TRUE;
4500 void InitElementPropertiesEngine(int engine_version)
4502 static int no_wall_properties[] =
4505 EP_COLLECTIBLE_ONLY,
4507 EP_DONT_COLLIDE_WITH,
4510 EP_CAN_SMASH_PLAYER,
4511 EP_CAN_SMASH_ENEMIES,
4512 EP_CAN_SMASH_EVERYTHING,
4517 EP_FOOD_DARK_YAMYAM,
4533 /* important: after initialization in InitElementPropertiesStatic(), the
4534 elements are not again initialized to a default value; therefore all
4535 changes have to make sure that they leave the element with a defined
4536 property (which means that conditional property changes must be set to
4537 a reliable default value before) */
4539 // resolve group elements
4540 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4541 ResolveGroupElement(EL_GROUP_START + i);
4543 // set all special, combined or engine dependent element properties
4544 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4546 // do not change (already initialized) clipboard elements here
4547 if (IS_CLIPBOARD_ELEMENT(i))
4550 // ---------- INACTIVE ----------------------------------------------------
4551 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4552 i <= EL_CHAR_END) ||
4553 (i >= EL_STEEL_CHAR_START &&
4554 i <= EL_STEEL_CHAR_END)));
4556 // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4557 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4558 IS_WALKABLE_INSIDE(i) ||
4559 IS_WALKABLE_UNDER(i)));
4561 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4562 IS_PASSABLE_INSIDE(i) ||
4563 IS_PASSABLE_UNDER(i)));
4565 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4566 IS_PASSABLE_OVER(i)));
4568 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4569 IS_PASSABLE_INSIDE(i)));
4571 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4572 IS_PASSABLE_UNDER(i)));
4574 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4577 // ---------- COLLECTIBLE -------------------------------------------------
4578 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4582 // ---------- SNAPPABLE ---------------------------------------------------
4583 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4584 IS_COLLECTIBLE(i) ||
4588 // ---------- WALL --------------------------------------------------------
4589 SET_PROPERTY(i, EP_WALL, TRUE); // default: element is wall
4591 for (j = 0; no_wall_properties[j] != -1; j++)
4592 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4593 i >= EL_FIRST_RUNTIME_UNREAL)
4594 SET_PROPERTY(i, EP_WALL, FALSE);
4596 if (IS_HISTORIC_WALL(i))
4597 SET_PROPERTY(i, EP_WALL, TRUE);
4599 // ---------- SOLID_FOR_PUSHING -------------------------------------------
4600 if (engine_version < VERSION_IDENT(2,2,0,0))
4601 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4603 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4605 !IS_COLLECTIBLE(i)));
4607 // ---------- DRAGONFIRE_PROOF --------------------------------------------
4608 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4609 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4611 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4614 // ---------- EXPLOSION_PROOF ---------------------------------------------
4616 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4617 else if (engine_version < VERSION_IDENT(2,2,0,0))
4618 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4620 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4624 if (IS_CUSTOM_ELEMENT(i))
4626 // these are additional properties which are initially false when set
4628 // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4630 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4631 if (DONT_COLLIDE_WITH(i))
4632 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4634 // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4635 if (CAN_SMASH_EVERYTHING(i))
4636 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4637 if (CAN_SMASH_ENEMIES(i))
4638 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4641 // ---------- CAN_SMASH ---------------------------------------------------
4642 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4643 CAN_SMASH_ENEMIES(i) ||
4644 CAN_SMASH_EVERYTHING(i)));
4646 // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4647 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4648 EXPLODES_BY_FIRE(i)));
4650 // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4651 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4652 EXPLODES_SMASHED(i)));
4654 // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4655 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4656 EXPLODES_IMPACT(i)));
4658 // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4659 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4661 // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4662 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4663 i == EL_BLACK_ORB));
4665 // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4666 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4668 IS_CUSTOM_ELEMENT(i)));
4670 // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4671 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4672 i == EL_SP_ELECTRON));
4674 // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4675 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4676 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4677 getMoveIntoAcidProperty(&level, i));
4679 // ---------- DONT_COLLIDE_WITH -------------------------------------------
4680 if (MAYBE_DONT_COLLIDE_WITH(i))
4681 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4682 getDontCollideWithProperty(&level, i));
4684 // ---------- SP_PORT -----------------------------------------------------
4685 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4686 IS_PASSABLE_INSIDE(i)));
4688 // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4689 for (j = 0; j < level.num_android_clone_elements; j++)
4690 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4692 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4694 // ---------- CAN_CHANGE --------------------------------------------------
4695 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); // default: cannot change
4696 for (j = 0; j < element_info[i].num_change_pages; j++)
4697 if (element_info[i].change_page[j].can_change)
4698 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4700 // ---------- HAS_ACTION --------------------------------------------------
4701 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); // default: has no action
4702 for (j = 0; j < element_info[i].num_change_pages; j++)
4703 if (element_info[i].change_page[j].has_action)
4704 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4706 // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4707 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4710 // ---------- GFX_CRUMBLED ------------------------------------------------
4711 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4712 element_info[i].crumbled[ACTION_DEFAULT] !=
4713 element_info[i].graphic[ACTION_DEFAULT]);
4715 // ---------- EDITOR_CASCADE ----------------------------------------------
4716 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4717 IS_EDITOR_CASCADE_INACTIVE(i)));
4720 // dynamically adjust element properties according to game engine version
4722 static int ep_em_slippery_wall[] =
4727 EL_EXPANDABLE_WALL_HORIZONTAL,
4728 EL_EXPANDABLE_WALL_VERTICAL,
4729 EL_EXPANDABLE_WALL_ANY,
4730 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4731 EL_EXPANDABLE_STEELWALL_VERTICAL,
4732 EL_EXPANDABLE_STEELWALL_ANY,
4733 EL_EXPANDABLE_STEELWALL_GROWING,
4737 static int ep_em_explodes_by_fire[] =
4740 EL_EM_DYNAMITE_ACTIVE,
4745 // special EM style gems behaviour
4746 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4747 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4748 level.em_slippery_gems);
4750 // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4751 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4752 (level.em_slippery_gems &&
4753 engine_version > VERSION_IDENT(2,0,1,0)));
4755 // special EM style explosion behaviour regarding chain reactions
4756 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4757 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4758 level.em_explodes_by_fire);
4761 // this is needed because some graphics depend on element properties
4762 if (game_status == GAME_MODE_PLAYING)
4763 InitElementGraphicInfo();
4766 void InitElementPropertiesGfxElement(void)
4770 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4772 struct ElementInfo *ei = &element_info[i];
4774 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4778 static void InitGlobal(void)
4783 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4785 // check if element_name_info entry defined for each element in "main.h"
4786 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4787 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4789 element_info[i].token_name = element_name_info[i].token_name;
4790 element_info[i].class_name = element_name_info[i].class_name;
4791 element_info[i].editor_description= element_name_info[i].editor_description;
4794 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4796 // check if global_anim_name_info defined for each entry in "main.h"
4797 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4798 global_anim_name_info[i].token_name == NULL)
4799 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4801 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4804 // create hash from image config list
4805 image_config_hash = newSetupFileHash();
4806 for (i = 0; image_config[i].token != NULL; i++)
4807 setHashEntry(image_config_hash,
4808 image_config[i].token,
4809 image_config[i].value);
4811 // create hash from element token list
4812 element_token_hash = newSetupFileHash();
4813 for (i = 0; element_name_info[i].token_name != NULL; i++)
4814 setHashEntry(element_token_hash,
4815 element_name_info[i].token_name,
4818 // create hash from graphic token list
4819 graphic_token_hash = newSetupFileHash();
4820 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4821 if (strSuffix(image_config[i].value, ".png") ||
4822 strSuffix(image_config[i].value, ".pcx") ||
4823 strSuffix(image_config[i].value, ".wav") ||
4824 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4825 setHashEntry(graphic_token_hash,
4826 image_config[i].token,
4827 int2str(graphic++, 0));
4829 // create hash from font token list
4830 font_token_hash = newSetupFileHash();
4831 for (i = 0; font_info[i].token_name != NULL; i++)
4832 setHashEntry(font_token_hash,
4833 font_info[i].token_name,
4836 // set default filenames for all cloned graphics in static configuration
4837 for (i = 0; image_config[i].token != NULL; i++)
4839 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4841 char *token = image_config[i].token;
4842 char *token_clone_from = getStringCat2(token, ".clone_from");
4843 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4845 if (token_cloned != NULL)
4847 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4849 if (value_cloned != NULL)
4851 // set default filename in static configuration
4852 image_config[i].value = value_cloned;
4854 // set default filename in image config hash
4855 setHashEntry(image_config_hash, token, value_cloned);
4859 free(token_clone_from);
4863 // always start with reliable default values (all elements)
4864 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4865 ActiveElement[i] = i;
4867 // now add all entries that have an active state (active elements)
4868 for (i = 0; element_with_active_state[i].element != -1; i++)
4870 int element = element_with_active_state[i].element;
4871 int element_active = element_with_active_state[i].element_active;
4873 ActiveElement[element] = element_active;
4876 // always start with reliable default values (all buttons)
4877 for (i = 0; i < NUM_IMAGE_FILES; i++)
4878 ActiveButton[i] = i;
4880 // now add all entries that have an active state (active buttons)
4881 for (i = 0; button_with_active_state[i].button != -1; i++)
4883 int button = button_with_active_state[i].button;
4884 int button_active = button_with_active_state[i].button_active;
4886 ActiveButton[button] = button_active;
4889 // always start with reliable default values (all fonts)
4890 for (i = 0; i < NUM_FONTS; i++)
4893 // now add all entries that have an active state (active fonts)
4894 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4896 int font = font_with_active_state[i].font_nr;
4897 int font_active = font_with_active_state[i].font_nr_active;
4899 ActiveFont[font] = font_active;
4902 global.autoplay_leveldir = NULL;
4903 global.patchtapes_leveldir = NULL;
4904 global.convert_leveldir = NULL;
4905 global.create_images_dir = NULL;
4907 global.frames_per_second = 0;
4908 global.show_frames_per_second = FALSE;
4910 global.border_status = GAME_MODE_LOADING;
4911 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4913 global.use_envelope_request = FALSE;
4916 static void Execute_Command(char *command)
4920 if (strEqual(command, "print graphicsinfo.conf"))
4922 Print("# You can configure additional/alternative image files here.\n");
4923 Print("# (The entries below are default and therefore commented out.)\n");
4925 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4927 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4930 for (i = 0; image_config[i].token != NULL; i++)
4931 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4932 image_config[i].value));
4936 else if (strEqual(command, "print soundsinfo.conf"))
4938 Print("# You can configure additional/alternative sound files here.\n");
4939 Print("# (The entries below are default and therefore commented out.)\n");
4941 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4943 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4946 for (i = 0; sound_config[i].token != NULL; i++)
4947 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4948 sound_config[i].value));
4952 else if (strEqual(command, "print musicinfo.conf"))
4954 Print("# You can configure additional/alternative music files here.\n");
4955 Print("# (The entries below are default and therefore commented out.)\n");
4957 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4959 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4962 for (i = 0; music_config[i].token != NULL; i++)
4963 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4964 music_config[i].value));
4968 else if (strEqual(command, "print editorsetup.conf"))
4970 Print("# You can configure your personal editor element list here.\n");
4971 Print("# (The entries below are default and therefore commented out.)\n");
4974 // this is needed to be able to check element list for cascade elements
4975 InitElementPropertiesStatic();
4976 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4978 PrintEditorElementList();
4982 else if (strEqual(command, "print helpanim.conf"))
4984 Print("# You can configure different element help animations here.\n");
4985 Print("# (The entries below are default and therefore commented out.)\n");
4988 for (i = 0; helpanim_config[i].token != NULL; i++)
4990 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4991 helpanim_config[i].value));
4993 if (strEqual(helpanim_config[i].token, "end"))
4999 else if (strEqual(command, "print helptext.conf"))
5001 Print("# You can configure different element help text here.\n");
5002 Print("# (The entries below are default and therefore commented out.)\n");
5005 for (i = 0; helptext_config[i].token != NULL; i++)
5006 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5007 helptext_config[i].value));
5011 else if (strPrefix(command, "dump level "))
5013 char *filename = &command[11];
5015 if (!fileExists(filename))
5016 Error(ERR_EXIT, "cannot open file '%s'", filename);
5018 LoadLevelFromFilename(&level, filename);
5023 else if (strPrefix(command, "dump tape "))
5025 char *filename = &command[10];
5027 if (!fileExists(filename))
5028 Error(ERR_EXIT, "cannot open file '%s'", filename);
5030 LoadTapeFromFilename(filename);
5035 else if (strPrefix(command, "autoplay ") ||
5036 strPrefix(command, "autoffwd ") ||
5037 strPrefix(command, "autowarp ") ||
5038 strPrefix(command, "autotest ") ||
5039 strPrefix(command, "autofix "))
5041 char *str_ptr = getStringCopy(&command[8]); // read command parameters
5043 global.autoplay_mode =
5044 (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5045 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5046 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5047 strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5048 strPrefix(command, "autofix") ? AUTOPLAY_MODE_FIX :
5049 AUTOPLAY_MODE_NONE);
5051 while (*str_ptr != '\0') // continue parsing string
5053 // cut leading whitespace from string, replace it by string terminator
5054 while (*str_ptr == ' ' || *str_ptr == '\t')
5057 if (*str_ptr == '\0') // end of string reached
5060 if (global.autoplay_leveldir == NULL) // read level set string
5062 global.autoplay_leveldir = str_ptr;
5063 global.autoplay_all = TRUE; // default: play all tapes
5065 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5066 global.autoplay_level[i] = FALSE;
5068 else // read level number string
5070 int level_nr = atoi(str_ptr); // get level_nr value
5072 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5073 global.autoplay_level[level_nr] = TRUE;
5075 global.autoplay_all = FALSE;
5078 // advance string pointer to the next whitespace (or end of string)
5079 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5083 if (global.autoplay_mode & AUTOPLAY_MODE_WARP_NO_DISPLAY)
5084 program.headless = TRUE;
5086 else if (strPrefix(command, "patch tapes "))
5088 char *str_ptr = getStringCopy(&command[12]); // read command parameters
5090 // skip leading whitespace
5091 while (*str_ptr == ' ' || *str_ptr == '\t')
5094 if (*str_ptr == '\0')
5095 Error(ERR_EXIT, "cannot find MODE in command '%s'", command);
5097 global.patchtapes_mode = str_ptr; // store patch mode
5099 // advance to next whitespace (or end of string)
5100 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5103 while (*str_ptr != '\0') // continue parsing string
5105 // cut leading whitespace from string, replace it by string terminator
5106 while (*str_ptr == ' ' || *str_ptr == '\t')
5109 if (*str_ptr == '\0') // end of string reached
5112 if (global.patchtapes_leveldir == NULL) // read level set string
5114 global.patchtapes_leveldir = str_ptr;
5115 global.patchtapes_all = TRUE; // default: patch all tapes
5117 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5118 global.patchtapes_level[i] = FALSE;
5120 else // read level number string
5122 int level_nr = atoi(str_ptr); // get level_nr value
5124 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5125 global.patchtapes_level[level_nr] = TRUE;
5127 global.patchtapes_all = FALSE;
5130 // advance string pointer to the next whitespace (or end of string)
5131 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5135 if (global.patchtapes_leveldir == NULL)
5137 if (strEqual(global.patchtapes_mode, "help"))
5138 global.patchtapes_leveldir = UNDEFINED_LEVELSET;
5140 Error(ERR_EXIT, "cannot find LEVELDIR in command '%s'", command);
5143 program.headless = TRUE;
5145 else if (strPrefix(command, "convert "))
5147 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5148 char *str_ptr = strchr(str_copy, ' ');
5150 global.convert_leveldir = str_copy;
5151 global.convert_level_nr = -1;
5153 if (str_ptr != NULL) // level number follows
5155 *str_ptr++ = '\0'; // terminate leveldir string
5156 global.convert_level_nr = atoi(str_ptr); // get level_nr value
5159 program.headless = TRUE;
5161 else if (strPrefix(command, "create images "))
5163 global.create_images_dir = getStringCopy(&command[14]);
5165 if (access(global.create_images_dir, W_OK) != 0)
5166 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5167 global.create_images_dir);
5169 else if (strPrefix(command, "create CE image "))
5171 CreateCustomElementImages(&command[16]);
5177 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5180 // disable networking if any valid command was recognized
5181 options.network = setup.network_mode = FALSE;
5184 static void InitSetup(void)
5186 LoadSetup(); // global setup info
5187 LoadSetup_AutoSetup(); // global auto setup info
5189 // set some options from setup file
5191 if (setup.options.verbose)
5192 options.verbose = TRUE;
5194 if (setup.debug.show_frames_per_second)
5195 global.show_frames_per_second = TRUE;
5198 static void InitGameInfo(void)
5200 game.restart_level = FALSE;
5201 game.restart_game_message = NULL;
5202 game.request_active = FALSE;
5205 static void InitPlayerInfo(void)
5209 // choose default local player
5210 local_player = &stored_player[0];
5212 for (i = 0; i < MAX_PLAYERS; i++)
5214 stored_player[i].connected_locally = FALSE;
5215 stored_player[i].connected_network = FALSE;
5218 local_player->connected_locally = TRUE;
5221 static void InitArtworkInfo(void)
5226 static char *get_string_in_brackets(char *string)
5228 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5230 sprintf(string_in_brackets, "[%s]", string);
5232 return string_in_brackets;
5235 static char *get_level_id_suffix(int id_nr)
5237 char *id_suffix = checked_malloc(1 + 3 + 1);
5239 if (id_nr < 0 || id_nr > 999)
5242 sprintf(id_suffix, ".%03d", id_nr);
5247 static void InitArtworkConfig(void)
5249 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5251 NUM_GLOBAL_ANIM_TOKENS + 1];
5252 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5253 NUM_GLOBAL_ANIM_TOKENS + 1];
5254 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5255 NUM_GLOBAL_ANIM_TOKENS + 1];
5256 static char *action_id_suffix[NUM_ACTIONS + 1];
5257 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5258 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5259 static char *level_id_suffix[MAX_LEVELS + 1];
5260 static char *dummy[1] = { NULL };
5261 static char *ignore_generic_tokens[] =
5266 "program_copyright",
5271 static char **ignore_image_tokens;
5272 static char **ignore_sound_tokens;
5273 static char **ignore_music_tokens;
5274 int num_ignore_generic_tokens;
5275 int num_ignore_image_tokens;
5276 int num_ignore_sound_tokens;
5277 int num_ignore_music_tokens;
5280 // dynamically determine list of generic tokens to be ignored
5281 num_ignore_generic_tokens = 0;
5282 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5283 num_ignore_generic_tokens++;
5285 // dynamically determine list of image tokens to be ignored
5286 num_ignore_image_tokens = num_ignore_generic_tokens;
5287 for (i = 0; image_config_vars[i].token != NULL; i++)
5288 num_ignore_image_tokens++;
5289 ignore_image_tokens =
5290 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5291 for (i = 0; i < num_ignore_generic_tokens; i++)
5292 ignore_image_tokens[i] = ignore_generic_tokens[i];
5293 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5294 ignore_image_tokens[num_ignore_generic_tokens + i] =
5295 image_config_vars[i].token;
5296 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5298 // dynamically determine list of sound tokens to be ignored
5299 num_ignore_sound_tokens = num_ignore_generic_tokens;
5300 ignore_sound_tokens =
5301 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5302 for (i = 0; i < num_ignore_generic_tokens; i++)
5303 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5304 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5306 // dynamically determine list of music tokens to be ignored
5307 num_ignore_music_tokens = num_ignore_generic_tokens;
5308 ignore_music_tokens =
5309 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5310 for (i = 0; i < num_ignore_generic_tokens; i++)
5311 ignore_music_tokens[i] = ignore_generic_tokens[i];
5312 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5314 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5315 image_id_prefix[i] = element_info[i].token_name;
5316 for (i = 0; i < NUM_FONTS; i++)
5317 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5318 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5319 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5320 global_anim_info[i].token_name;
5321 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5323 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5324 sound_id_prefix[i] = element_info[i].token_name;
5325 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5326 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5327 get_string_in_brackets(element_info[i].class_name);
5328 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5329 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5330 global_anim_info[i].token_name;
5331 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5333 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5334 music_id_prefix[i] = music_prefix_info[i].prefix;
5335 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5336 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5337 global_anim_info[i].token_name;
5338 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5340 for (i = 0; i < NUM_ACTIONS; i++)
5341 action_id_suffix[i] = element_action_info[i].suffix;
5342 action_id_suffix[NUM_ACTIONS] = NULL;
5344 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5345 direction_id_suffix[i] = element_direction_info[i].suffix;
5346 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5348 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5349 special_id_suffix[i] = special_suffix_info[i].suffix;
5350 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5352 for (i = 0; i < MAX_LEVELS; i++)
5353 level_id_suffix[i] = get_level_id_suffix(i);
5354 level_id_suffix[MAX_LEVELS] = NULL;
5356 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5357 image_id_prefix, action_id_suffix, direction_id_suffix,
5358 special_id_suffix, ignore_image_tokens);
5359 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5360 sound_id_prefix, action_id_suffix, dummy,
5361 special_id_suffix, ignore_sound_tokens);
5362 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5363 music_id_prefix, action_id_suffix, special_id_suffix,
5364 level_id_suffix, ignore_music_tokens);
5367 static void InitMixer(void)
5374 static void InitVideoOverlay(void)
5376 // if virtual buttons are not loaded from setup file, repeat initializing
5377 // virtual buttons grid with default values now that video is initialized
5378 if (!setup.touch.grid_initialized)
5381 InitTileCursorInfo();
5385 void InitGfxBuffers(void)
5387 static int win_xsize_last = -1;
5388 static int win_ysize_last = -1;
5390 // create additional image buffers for double-buffering and cross-fading
5392 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5394 // used to temporarily store the backbuffer -- only re-create if changed
5395 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5396 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5398 win_xsize_last = WIN_XSIZE;
5399 win_ysize_last = WIN_YSIZE;
5402 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5403 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5404 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5405 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5407 // initialize screen properties
5408 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5409 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5411 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5412 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5413 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5414 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5415 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5416 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5418 // required if door size definitions have changed
5419 InitGraphicCompatibilityInfo_Doors();
5421 InitGfxBuffers_EM();
5422 InitGfxBuffers_SP();
5425 static void InitGfx(void)
5427 struct GraphicInfo *graphic_info_last = graphic_info;
5428 char *filename_font_initial = NULL;
5429 char *filename_anim_initial = NULL;
5430 Bitmap *bitmap_font_initial = NULL;
5433 // determine settings for initial font (for displaying startup messages)
5434 for (i = 0; image_config[i].token != NULL; i++)
5436 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5438 char font_token[128];
5441 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5442 len_font_token = strlen(font_token);
5444 if (strEqual(image_config[i].token, font_token))
5445 filename_font_initial = image_config[i].value;
5446 else if (strlen(image_config[i].token) > len_font_token &&
5447 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5449 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5450 font_initial[j].src_x = atoi(image_config[i].value);
5451 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5452 font_initial[j].src_y = atoi(image_config[i].value);
5453 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5454 font_initial[j].width = atoi(image_config[i].value);
5455 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5456 font_initial[j].height = atoi(image_config[i].value);
5461 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5463 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5464 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5467 if (filename_font_initial == NULL) // should not happen
5468 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5471 InitGfxCustomArtworkInfo();
5472 InitGfxOtherSettings();
5474 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5476 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5477 font_initial[j].bitmap = bitmap_font_initial;
5479 InitFontGraphicInfo();
5483 DrawInitText("Loading graphics", 120, FC_GREEN);
5485 // initialize settings for busy animation with default values
5486 int parameter[NUM_GFX_ARGS];
5487 for (i = 0; i < NUM_GFX_ARGS; i++)
5488 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5489 image_config_suffix[i].token,
5490 image_config_suffix[i].type);
5492 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5493 int len_anim_token = strlen(anim_token);
5495 // read settings for busy animation from default custom artwork config
5496 char *gfx_config_filename = getPath3(options.graphics_directory,
5498 GRAPHICSINFO_FILENAME);
5500 if (fileExists(gfx_config_filename))
5502 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5504 if (setup_file_hash)
5506 char *filename = getHashEntry(setup_file_hash, anim_token);
5510 filename_anim_initial = getStringCopy(filename);
5512 for (j = 0; image_config_suffix[j].token != NULL; j++)
5514 int type = image_config_suffix[j].type;
5515 char *suffix = image_config_suffix[j].token;
5516 char *token = getStringCat2(anim_token, suffix);
5517 char *value = getHashEntry(setup_file_hash, token);
5519 checked_free(token);
5522 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5526 freeSetupFileHash(setup_file_hash);
5530 if (filename_anim_initial == NULL)
5532 // read settings for busy animation from static default artwork config
5533 for (i = 0; image_config[i].token != NULL; i++)
5535 if (strEqual(image_config[i].token, anim_token))
5536 filename_anim_initial = getStringCopy(image_config[i].value);
5537 else if (strlen(image_config[i].token) > len_anim_token &&
5538 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5540 for (j = 0; image_config_suffix[j].token != NULL; j++)
5542 if (strEqual(&image_config[i].token[len_anim_token],
5543 image_config_suffix[j].token))
5545 get_graphic_parameter_value(image_config[i].value,
5546 image_config_suffix[j].token,
5547 image_config_suffix[j].type);
5553 if (filename_anim_initial == NULL) // should not happen
5554 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5556 anim_initial.bitmaps =
5557 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5559 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5560 LoadCustomImage(filename_anim_initial);
5562 checked_free(filename_anim_initial);
5564 graphic_info = &anim_initial; // graphic == 0 => anim_initial
5566 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5568 graphic_info = graphic_info_last;
5570 init.busy.width = anim_initial.width;
5571 init.busy.height = anim_initial.height;
5573 InitMenuDesignSettings_Static();
5575 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5576 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5577 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5578 InitGfxDrawTileCursorFunction(DrawTileCursor);
5580 gfx.fade_border_source_status = global.border_status;
5581 gfx.fade_border_target_status = global.border_status;
5582 gfx.masked_border_bitmap_ptr = backbuffer;
5584 // use copy of busy animation to prevent change while reloading artwork
5588 static void InitGfxBackground(void)
5590 fieldbuffer = bitmap_db_field;
5591 SetDrawtoField(DRAW_TO_BACKBUFFER);
5593 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5595 redraw_mask = REDRAW_ALL;
5598 static void InitLevelInfo(void)
5600 LoadLevelInfo(); // global level info
5601 LoadLevelSetup_LastSeries(); // last played series info
5602 LoadLevelSetup_SeriesInfo(); // last played level info
5604 if (global.autoplay_leveldir &&
5605 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5607 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5608 global.autoplay_leveldir);
5609 if (leveldir_current == NULL)
5610 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5613 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5616 static void InitLevelArtworkInfo(void)
5618 LoadLevelArtworkInfo();
5621 static void InitImages(void)
5623 print_timestamp_init("InitImages");
5626 printf("::: leveldir_current->identifier == '%s'\n",
5627 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5628 printf("::: leveldir_current->graphics_path == '%s'\n",
5629 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5630 printf("::: leveldir_current->graphics_set == '%s'\n",
5631 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5632 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5633 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5636 setLevelArtworkDir(artwork.gfx_first);
5639 printf("::: leveldir_current->identifier == '%s'\n",
5640 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5641 printf("::: leveldir_current->graphics_path == '%s'\n",
5642 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5643 printf("::: leveldir_current->graphics_set == '%s'\n",
5644 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5645 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5646 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5650 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5651 leveldir_current->identifier,
5652 artwork.gfx_current_identifier,
5653 artwork.gfx_current->identifier,
5654 leveldir_current->graphics_set,
5655 leveldir_current->graphics_path);
5658 UPDATE_BUSY_STATE();
5660 ReloadCustomImages();
5661 print_timestamp_time("ReloadCustomImages");
5663 UPDATE_BUSY_STATE();
5665 LoadCustomElementDescriptions();
5666 print_timestamp_time("LoadCustomElementDescriptions");
5668 UPDATE_BUSY_STATE();
5670 LoadMenuDesignSettings();
5671 print_timestamp_time("LoadMenuDesignSettings");
5673 UPDATE_BUSY_STATE();
5675 ReinitializeGraphics();
5676 print_timestamp_time("ReinitializeGraphics");
5678 LoadMenuDesignSettings_AfterGraphics();
5679 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5681 UPDATE_BUSY_STATE();
5683 print_timestamp_done("InitImages");
5686 static void InitSound(char *identifier)
5688 print_timestamp_init("InitSound");
5690 if (identifier == NULL)
5691 identifier = artwork.snd_current->identifier;
5693 // set artwork path to send it to the sound server process
5694 setLevelArtworkDir(artwork.snd_first);
5696 InitReloadCustomSounds(identifier);
5697 print_timestamp_time("InitReloadCustomSounds");
5699 ReinitializeSounds();
5700 print_timestamp_time("ReinitializeSounds");
5702 print_timestamp_done("InitSound");
5705 static void InitMusic(char *identifier)
5707 print_timestamp_init("InitMusic");
5709 if (identifier == NULL)
5710 identifier = artwork.mus_current->identifier;
5712 // set artwork path to send it to the sound server process
5713 setLevelArtworkDir(artwork.mus_first);
5715 InitReloadCustomMusic(identifier);
5716 print_timestamp_time("InitReloadCustomMusic");
5718 ReinitializeMusic();
5719 print_timestamp_time("ReinitializeMusic");
5721 print_timestamp_done("InitMusic");
5724 static void InitArtworkDone(void)
5726 if (program.headless)
5729 InitGlobalAnimations();
5732 static void InitNetworkSettings(void)
5734 boolean network_enabled = (options.network || setup.network_mode);
5735 char *network_server = (options.server_host != NULL ? options.server_host :
5736 setup.network_server_hostname);
5738 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5739 network_server = NULL;
5741 InitNetworkInfo(network_enabled,
5745 options.server_port);
5748 void InitNetworkServer(void)
5750 if (!network.enabled || network.connected)
5753 LimitScreenUpdates(FALSE);
5755 if (game_status == GAME_MODE_LOADING)
5758 if (!ConnectToServer(network.server_host, network.server_port))
5760 network.enabled = FALSE;
5762 setup.network_mode = FALSE;
5766 SendToServer_ProtocolVersion();
5767 SendToServer_PlayerName(setup.player_name);
5768 SendToServer_NrWanted(setup.network_player_nr + 1);
5770 network.connected = TRUE;
5773 // short time to recognize result of network initialization
5774 if (game_status == GAME_MODE_LOADING)
5775 Delay_WithScreenUpdates(1000);
5778 static boolean CheckArtworkConfigForCustomElements(char *filename)
5780 SetupFileHash *setup_file_hash;
5781 boolean redefined_ce_found = FALSE;
5783 // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5785 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5787 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5789 char *token = HASH_ITERATION_TOKEN(itr);
5791 if (strPrefix(token, "custom_"))
5793 redefined_ce_found = TRUE;
5798 END_HASH_ITERATION(setup_file_hash, itr)
5800 freeSetupFileHash(setup_file_hash);
5803 return redefined_ce_found;
5806 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5808 char *filename_base, *filename_local;
5809 boolean redefined_ce_found = FALSE;
5811 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5814 printf("::: leveldir_current->identifier == '%s'\n",
5815 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5816 printf("::: leveldir_current->graphics_path == '%s'\n",
5817 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5818 printf("::: leveldir_current->graphics_set == '%s'\n",
5819 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5820 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5821 leveldir_current == NULL ? "[NULL]" :
5822 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5825 // first look for special artwork configured in level series config
5826 filename_base = getCustomArtworkLevelConfigFilename(type);
5829 printf("::: filename_base == '%s'\n", filename_base);
5832 if (fileExists(filename_base))
5833 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5835 filename_local = getCustomArtworkConfigFilename(type);
5838 printf("::: filename_local == '%s'\n", filename_local);
5841 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5842 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5845 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5848 return redefined_ce_found;
5851 static void InitOverrideArtwork(void)
5853 boolean redefined_ce_found = FALSE;
5855 // to check if this level set redefines any CEs, do not use overriding
5856 gfx.override_level_graphics = FALSE;
5857 gfx.override_level_sounds = FALSE;
5858 gfx.override_level_music = FALSE;
5860 // now check if this level set has definitions for custom elements
5861 if (setup.override_level_graphics == AUTO ||
5862 setup.override_level_sounds == AUTO ||
5863 setup.override_level_music == AUTO)
5864 redefined_ce_found =
5865 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5866 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5867 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5870 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5873 if (redefined_ce_found)
5875 // this level set has CE definitions: change "AUTO" to "FALSE"
5876 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5877 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5878 gfx.override_level_music = (setup.override_level_music == TRUE);
5882 // this level set has no CE definitions: change "AUTO" to "TRUE"
5883 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5884 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5885 gfx.override_level_music = (setup.override_level_music != FALSE);
5889 printf("::: => %d, %d, %d\n",
5890 gfx.override_level_graphics,
5891 gfx.override_level_sounds,
5892 gfx.override_level_music);
5896 static char *getNewArtworkIdentifier(int type)
5898 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5899 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5900 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5901 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5902 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5903 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5904 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5905 char *leveldir_identifier = leveldir_current->identifier;
5906 // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
5907 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5908 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5909 char *artwork_current_identifier;
5910 char *artwork_new_identifier = NULL; // default: nothing has changed
5912 // leveldir_current may be invalid (level group, parent link)
5913 if (!validLevelSeries(leveldir_current))
5916 /* 1st step: determine artwork set to be activated in descending order:
5917 --------------------------------------------------------------------
5918 1. setup artwork (when configured to override everything else)
5919 2. artwork set configured in "levelinfo.conf" of current level set
5920 (artwork in level directory will have priority when loading later)
5921 3. artwork in level directory (stored in artwork sub-directory)
5922 4. setup artwork (currently configured in setup menu) */
5924 if (setup_override_artwork)
5925 artwork_current_identifier = setup_artwork_set;
5926 else if (leveldir_artwork_set != NULL)
5927 artwork_current_identifier = leveldir_artwork_set;
5928 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5929 artwork_current_identifier = leveldir_identifier;
5931 artwork_current_identifier = setup_artwork_set;
5934 /* 2nd step: check if it is really needed to reload artwork set
5935 ------------------------------------------------------------ */
5937 // ---------- reload if level set and also artwork set has changed ----------
5938 if (leveldir_current_identifier[type] != leveldir_identifier &&
5939 (last_has_level_artwork_set[type] || has_level_artwork_set))
5940 artwork_new_identifier = artwork_current_identifier;
5942 leveldir_current_identifier[type] = leveldir_identifier;
5943 last_has_level_artwork_set[type] = has_level_artwork_set;
5945 // ---------- reload if "override artwork" setting has changed --------------
5946 if (last_override_level_artwork[type] != setup_override_artwork)
5947 artwork_new_identifier = artwork_current_identifier;
5949 last_override_level_artwork[type] = setup_override_artwork;
5951 // ---------- reload if current artwork identifier has changed --------------
5952 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5953 artwork_current_identifier))
5954 artwork_new_identifier = artwork_current_identifier;
5956 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5958 // ---------- do not reload directly after starting -------------------------
5959 if (!initialized[type])
5960 artwork_new_identifier = NULL;
5962 initialized[type] = TRUE;
5964 return artwork_new_identifier;
5967 void ReloadCustomArtwork(int force_reload)
5969 int last_game_status = game_status; // save current game status
5970 char *gfx_new_identifier;
5971 char *snd_new_identifier;
5972 char *mus_new_identifier;
5973 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5974 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5975 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5976 boolean reload_needed;
5978 InitOverrideArtwork();
5980 force_reload_gfx |= AdjustGraphicsForEMC();
5981 force_reload_snd |= AdjustSoundsForEMC();
5983 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5984 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5985 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5987 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5988 snd_new_identifier != NULL || force_reload_snd ||
5989 mus_new_identifier != NULL || force_reload_mus);
5994 print_timestamp_init("ReloadCustomArtwork");
5996 SetGameStatus(GAME_MODE_LOADING);
5998 FadeOut(REDRAW_ALL);
6000 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6001 print_timestamp_time("ClearRectangle");
6005 if (gfx_new_identifier != NULL || force_reload_gfx)
6008 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6009 artwork.gfx_current_identifier,
6011 artwork.gfx_current->identifier,
6012 leveldir_current->graphics_set);
6016 print_timestamp_time("InitImages");
6019 if (snd_new_identifier != NULL || force_reload_snd)
6021 InitSound(snd_new_identifier);
6022 print_timestamp_time("InitSound");
6025 if (mus_new_identifier != NULL || force_reload_mus)
6027 InitMusic(mus_new_identifier);
6028 print_timestamp_time("InitMusic");
6033 SetGameStatus(last_game_status); // restore current game status
6035 init_last = init; // switch to new busy animation
6037 FadeOut(REDRAW_ALL);
6039 RedrawGlobalBorder();
6041 // force redraw of (open or closed) door graphics
6042 SetDoorState(DOOR_OPEN_ALL);
6043 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6045 FadeSetEnterScreen();
6046 FadeSkipNextFadeOut();
6048 print_timestamp_done("ReloadCustomArtwork");
6050 LimitScreenUpdates(FALSE);
6053 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6055 if (global.autoplay_leveldir == NULL)
6056 KeyboardAutoRepeatOff();
6059 void DisplayExitMessage(char *format, va_list ap)
6061 // also check for initialized video (headless flag may be temporarily unset)
6062 if (program.headless || !video.initialized)
6065 // check if draw buffer and fonts for exit message are already available
6066 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6069 int font_1 = FC_RED;
6070 int font_2 = FC_YELLOW;
6071 int font_3 = FC_BLUE;
6072 int font_width = getFontWidth(font_2);
6073 int font_height = getFontHeight(font_2);
6076 int sxsize = WIN_XSIZE - 2 * sx;
6077 int sysize = WIN_YSIZE - 2 * sy;
6078 int line_length = sxsize / font_width;
6079 int max_lines = sysize / font_height;
6080 int num_lines_printed;
6084 gfx.sxsize = sxsize;
6085 gfx.sysize = sysize;
6089 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6091 DrawTextSCentered(sy, font_1, "Fatal error:");
6092 sy += 3 * font_height;;
6095 DrawTextBufferVA(sx, sy, format, ap, font_2,
6096 line_length, line_length, max_lines,
6097 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6098 sy += (num_lines_printed + 3) * font_height;
6100 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6101 sy += 3 * font_height;
6104 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6105 line_length, line_length, max_lines,
6106 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6108 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6110 redraw_mask = REDRAW_ALL;
6112 // force drawing exit message even if screen updates are currently limited
6113 LimitScreenUpdates(FALSE);
6117 // deactivate toons on error message screen
6118 setup.toons = FALSE;
6120 WaitForEventToContinue();
6124 // ============================================================================
6126 // ============================================================================
6130 print_timestamp_init("OpenAll");
6132 SetGameStatus(GAME_MODE_LOADING);
6136 InitGlobal(); // initialize some global variables
6138 print_timestamp_time("[init global stuff]");
6142 print_timestamp_time("[init setup/config stuff (1)]");
6146 if (options.execute_command)
6147 Execute_Command(options.execute_command);
6149 InitNetworkSettings();
6153 if (network.serveronly)
6155 #if defined(PLATFORM_UNIX)
6156 NetworkServer(network.server_port, TRUE);
6158 Error(ERR_WARN, "networking only supported in Unix version");
6161 exit(0); // never reached, server loops forever
6165 print_timestamp_time("[init setup/config stuff (2)]");
6167 print_timestamp_time("[init setup/config stuff (3)]");
6168 InitArtworkInfo(); // needed before loading gfx, sound & music
6169 print_timestamp_time("[init setup/config stuff (4)]");
6170 InitArtworkConfig(); // needed before forking sound child process
6171 print_timestamp_time("[init setup/config stuff (5)]");
6173 print_timestamp_time("[init setup/config stuff (6)]");
6175 InitRND(NEW_RANDOMIZE);
6176 InitSimpleRandom(NEW_RANDOMIZE);
6180 print_timestamp_time("[init setup/config stuff]");
6182 InitVideoDefaults();
6184 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6187 InitEventFilter(FilterMouseMotionEvents);
6189 print_timestamp_time("[init video stuff]");
6191 InitElementPropertiesStatic();
6192 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6193 InitElementPropertiesGfxElement();
6195 print_timestamp_time("[init element properties stuff]");
6199 print_timestamp_time("InitGfx");
6202 print_timestamp_time("InitLevelInfo");
6204 InitLevelArtworkInfo();
6205 print_timestamp_time("InitLevelArtworkInfo");
6207 InitOverrideArtwork(); // needs to know current level directory
6208 print_timestamp_time("InitOverrideArtwork");
6210 InitImages(); // needs to know current level directory
6211 print_timestamp_time("InitImages");
6213 InitSound(NULL); // needs to know current level directory
6214 print_timestamp_time("InitSound");
6216 InitMusic(NULL); // needs to know current level directory
6217 print_timestamp_time("InitMusic");
6221 InitGfxBackground();
6227 if (global.autoplay_leveldir)
6232 else if (global.patchtapes_leveldir)
6237 else if (global.convert_leveldir)
6242 else if (global.create_images_dir)
6244 CreateLevelSketchImages();
6248 InitNetworkServer();
6250 SetGameStatus(GAME_MODE_MAIN);
6252 FadeSetEnterScreen();
6253 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6254 FadeSkipNextFadeOut();
6256 print_timestamp_time("[post-artwork]");
6258 print_timestamp_done("OpenAll");
6263 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6265 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6266 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6267 #if defined(PLATFORM_ANDROID)
6268 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6269 SDL_AndroidGetInternalStoragePath());
6270 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6271 SDL_AndroidGetExternalStoragePath());
6272 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6273 (SDL_AndroidGetExternalStorageState() &
6274 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6275 SDL_AndroidGetExternalStorageState() &
6276 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6281 void CloseAllAndExit(int exit_value)
6286 CloseAudio(); // called after freeing sounds (needed for SDL)
6294 // set a flag to tell the network server thread to quit and wait for it
6295 // using SDL_WaitThread()
6297 // Code used with SDL 1.2:
6298 // if (network_server) // terminate network server
6299 // SDL_KillThread(server_thread);
6301 CloseVideoDisplay();
6302 ClosePlatformDependentStuff();
6304 if (exit_value != 0 && !options.execute_command)
6306 // fall back to default level set (current set may have caused an error)
6307 SaveLevelSetup_LastSeries_Deactivate();
6309 // tell user where to find error log file which may contain more details
6310 // (error notification now directly displayed on screen inside R'n'D
6311 // NotifyUserAboutErrorFile(); // currently only works for Windows