1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #include "conf_e2g.c" /* include auto-generated data structure definitions */
28 #include "conf_esg.c" /* include auto-generated data structure definitions */
29 #include "conf_e2s.c" /* include auto-generated data structure definitions */
30 #include "conf_fnt.c" /* include auto-generated data structure definitions */
31 #include "conf_g2s.c" /* include auto-generated data structure definitions */
32 #include "conf_g2m.c" /* include auto-generated data structure definitions */
33 #include "conf_act.c" /* include auto-generated data structure definitions */
36 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41 static struct GraphicInfo anim_initial;
43 static int copy_properties[][5] =
47 EL_BUG_LEFT, EL_BUG_RIGHT,
48 EL_BUG_UP, EL_BUG_DOWN
52 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
53 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
57 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
58 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
62 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
63 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
67 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
68 EL_PACMAN_UP, EL_PACMAN_DOWN
72 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
73 EL_YAMYAM_UP, EL_YAMYAM_DOWN
77 EL_MOLE_LEFT, EL_MOLE_RIGHT,
78 EL_MOLE_UP, EL_MOLE_DOWN
87 /* forward declaration for internal use */
88 static int get_graphic_parameter_value(char *, char *, int);
91 static void DrawInitAnim(void)
93 struct GraphicInfo *graphic_info_last = graphic_info;
95 static unsigned int action_delay = 0;
96 unsigned int action_delay_value = GameFrameDelay;
97 int sync_frame = FrameCounter;
100 /* prevent OS (Windows) from complaining about program not responding */
103 if (game_status != GAME_MODE_LOADING)
106 if (anim_initial.bitmap == NULL || window == NULL)
109 if (!DelayReached(&action_delay, action_delay_value))
112 if (init_last.busy.x == -1)
113 init_last.busy.x = WIN_XSIZE / 2;
114 if (init_last.busy.y == -1)
115 init_last.busy.y = WIN_YSIZE / 2;
117 x = ALIGNED_TEXT_XPOS(&init_last.busy);
118 y = ALIGNED_TEXT_YPOS(&init_last.busy);
120 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
122 if (sync_frame % anim_initial.anim_delay == 0)
126 int width = graphic_info[graphic].width;
127 int height = graphic_info[graphic].height;
128 int frame = getGraphicAnimationFrame(graphic, sync_frame);
130 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
131 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
134 graphic_info = graphic_info_last;
139 static void FreeGadgets(void)
141 FreeLevelEditorGadgets();
148 void InitGadgets(void)
150 static boolean gadgets_initialized = FALSE;
152 if (gadgets_initialized)
155 CreateLevelEditorGadgets();
159 CreateScreenGadgets();
161 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
163 gadgets_initialized = TRUE;
166 inline static void InitElementSmallImagesScaledUp(int graphic)
168 struct GraphicInfo *g = &graphic_info[graphic];
170 // create small and game tile sized bitmaps (and scale up, if needed)
171 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
174 static void InitElementSmallImages(void)
176 print_timestamp_init("InitElementSmallImages");
178 static int special_graphics[] =
192 IMG_EDITOR_ELEMENT_BORDER,
193 IMG_EDITOR_ELEMENT_BORDER_INPUT,
194 IMG_EDITOR_CASCADE_LIST,
195 IMG_EDITOR_CASCADE_LIST_ACTIVE,
198 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
199 int num_property_mappings = getImageListPropertyMappingSize();
202 print_timestamp_time("getImageListPropertyMapping/Size");
204 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
205 /* initialize normal element images from static configuration */
206 for (i = 0; element_to_graphic[i].element > -1; i++)
207 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
208 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
210 /* initialize special element images from static configuration */
211 for (i = 0; element_to_special_graphic[i].element > -1; i++)
212 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
213 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
215 /* initialize element images from dynamic configuration */
216 for (i = 0; i < num_property_mappings; i++)
217 if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
218 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
219 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
221 /* initialize special non-element images from above list */
222 for (i = 0; special_graphics[i] > -1; i++)
223 InitElementSmallImagesScaledUp(special_graphics[i]);
224 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
226 print_timestamp_done("InitElementSmallImages");
229 inline static void InitScaledImagesScaledUp(int graphic)
231 struct GraphicInfo *g = &graphic_info[graphic];
233 ScaleImage(graphic, g->scale_up_factor);
236 static void InitScaledImages(void)
238 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
239 int num_property_mappings = getImageListPropertyMappingSize();
242 /* scale normal images from static configuration, if not already scaled */
243 for (i = 0; i < NUM_IMAGE_FILES; i++)
244 InitScaledImagesScaledUp(i);
246 /* scale images from dynamic configuration, if not already scaled */
247 for (i = 0; i < num_property_mappings; i++)
248 InitScaledImagesScaledUp(property_mapping[i].artwork_index);
251 static void InitBitmapPointers(void)
253 int num_images = getImageListSize();
256 // standard size bitmap may have changed -- update default bitmap pointer
257 for (i = 0; i < num_images; i++)
258 if (graphic_info[i].bitmaps)
259 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
262 void InitImageTextures(void)
266 FreeAllImageTextures();
268 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
269 CreateImageTextures(i);
271 for (i = 0; i < MAX_NUM_TOONS; i++)
272 CreateImageTextures(IMG_TOON_1 + i);
274 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
276 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
278 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
280 int graphic = global_anim_info[i].graphic[j][k];
282 if (graphic == IMG_UNDEFINED)
285 CreateImageTextures(graphic);
292 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
293 void SetBitmaps_EM(Bitmap **em_bitmap)
295 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
296 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
301 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
302 void SetBitmaps_SP(Bitmap **sp_bitmap)
304 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
308 static int getFontBitmapID(int font_nr)
312 /* (special case: do not use special font for GAME_MODE_LOADING) */
313 if (game_status >= GAME_MODE_TITLE_INITIAL &&
314 game_status <= GAME_MODE_PSEUDO_PREVIEW)
315 special = game_status;
316 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
317 special = GFX_SPECIAL_ARG_MAIN;
320 return font_info[font_nr].special_bitmap_id[special];
325 static int getFontFromToken(char *token)
327 char *value = getHashEntry(font_token_hash, token);
332 /* if font not found, use reliable default value */
333 return FONT_INITIAL_1;
336 static void InitFontGraphicInfo(void)
338 static struct FontBitmapInfo *font_bitmap_info = NULL;
339 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
340 int num_property_mappings = getImageListPropertyMappingSize();
341 int num_font_bitmaps = NUM_FONTS;
344 if (graphic_info == NULL) /* still at startup phase */
346 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
347 getFontBitmapID, getFontFromToken);
352 /* ---------- initialize font graphic definitions ---------- */
354 /* always start with reliable default values (normal font graphics) */
355 for (i = 0; i < NUM_FONTS; i++)
356 font_info[i].graphic = IMG_FONT_INITIAL_1;
358 /* initialize normal font/graphic mapping from static configuration */
359 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
361 int font_nr = font_to_graphic[i].font_nr;
362 int special = font_to_graphic[i].special;
363 int graphic = font_to_graphic[i].graphic;
368 font_info[font_nr].graphic = graphic;
371 /* always start with reliable default values (special font graphics) */
372 for (i = 0; i < NUM_FONTS; i++)
374 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
376 font_info[i].special_graphic[j] = font_info[i].graphic;
377 font_info[i].special_bitmap_id[j] = i;
381 /* initialize special font/graphic mapping from static configuration */
382 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
384 int font_nr = font_to_graphic[i].font_nr;
385 int special = font_to_graphic[i].special;
386 int graphic = font_to_graphic[i].graphic;
387 int base_graphic = font2baseimg(font_nr);
389 if (IS_SPECIAL_GFX_ARG(special))
391 boolean base_redefined =
392 getImageListEntryFromImageID(base_graphic)->redefined;
393 boolean special_redefined =
394 getImageListEntryFromImageID(graphic)->redefined;
395 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
397 /* if the base font ("font.title_1", for example) has been redefined,
398 but not the special font ("font.title_1.LEVELS", for example), do not
399 use an existing (in this case considered obsolete) special font
400 anymore, but use the automatically determined default font */
401 /* special case: cloned special fonts must be explicitly redefined,
402 but are not automatically redefined by redefining base font */
403 if (base_redefined && !special_redefined && !special_cloned)
406 font_info[font_nr].special_graphic[special] = graphic;
407 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
412 /* initialize special font/graphic mapping from dynamic configuration */
413 for (i = 0; i < num_property_mappings; i++)
415 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
416 int special = property_mapping[i].ext3_index;
417 int graphic = property_mapping[i].artwork_index;
419 if (font_nr < 0 || font_nr >= NUM_FONTS)
422 if (IS_SPECIAL_GFX_ARG(special))
424 font_info[font_nr].special_graphic[special] = graphic;
425 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
430 /* correct special font/graphic mapping for cloned fonts for downwards
431 compatibility of PREVIEW fonts -- this is only needed for implicit
432 redefinition of special font by redefined base font, and only if other
433 fonts are cloned from this special font (like in the "Zelda" level set) */
434 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
436 int font_nr = font_to_graphic[i].font_nr;
437 int special = font_to_graphic[i].special;
438 int graphic = font_to_graphic[i].graphic;
440 if (IS_SPECIAL_GFX_ARG(special))
442 boolean special_redefined =
443 getImageListEntryFromImageID(graphic)->redefined;
444 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
446 if (special_cloned && !special_redefined)
450 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
452 int font_nr2 = font_to_graphic[j].font_nr;
453 int special2 = font_to_graphic[j].special;
454 int graphic2 = font_to_graphic[j].graphic;
456 if (IS_SPECIAL_GFX_ARG(special2) &&
457 graphic2 == graphic_info[graphic].clone_from)
459 font_info[font_nr].special_graphic[special] =
460 font_info[font_nr2].special_graphic[special2];
461 font_info[font_nr].special_bitmap_id[special] =
462 font_info[font_nr2].special_bitmap_id[special2];
469 /* reset non-redefined ".active" font graphics if normal font is redefined */
470 /* (this different treatment is needed because normal and active fonts are
471 independently defined ("active" is not a property of font definitions!) */
472 for (i = 0; i < NUM_FONTS; i++)
474 int font_nr_base = i;
475 int font_nr_active = FONT_ACTIVE(font_nr_base);
477 /* check only those fonts with exist as normal and ".active" variant */
478 if (font_nr_base != font_nr_active)
480 int base_graphic = font_info[font_nr_base].graphic;
481 int active_graphic = font_info[font_nr_active].graphic;
482 boolean base_redefined =
483 getImageListEntryFromImageID(base_graphic)->redefined;
484 boolean active_redefined =
485 getImageListEntryFromImageID(active_graphic)->redefined;
487 /* if the base font ("font.menu_1", for example) has been redefined,
488 but not the active font ("font.menu_1.active", for example), do not
489 use an existing (in this case considered obsolete) active font
490 anymore, but use the automatically determined default font */
491 if (base_redefined && !active_redefined)
492 font_info[font_nr_active].graphic = base_graphic;
494 /* now also check each "special" font (which may be the same as above) */
495 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
497 int base_graphic = font_info[font_nr_base].special_graphic[j];
498 int active_graphic = font_info[font_nr_active].special_graphic[j];
499 boolean base_redefined =
500 getImageListEntryFromImageID(base_graphic)->redefined;
501 boolean active_redefined =
502 getImageListEntryFromImageID(active_graphic)->redefined;
504 /* same as above, but check special graphic definitions, for example:
505 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
506 if (base_redefined && !active_redefined)
508 font_info[font_nr_active].special_graphic[j] =
509 font_info[font_nr_base].special_graphic[j];
510 font_info[font_nr_active].special_bitmap_id[j] =
511 font_info[font_nr_base].special_bitmap_id[j];
517 /* ---------- initialize font bitmap array ---------- */
519 if (font_bitmap_info != NULL)
520 FreeFontInfo(font_bitmap_info);
523 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
525 /* ---------- initialize font bitmap definitions ---------- */
527 for (i = 0; i < NUM_FONTS; i++)
529 if (i < NUM_INITIAL_FONTS)
531 font_bitmap_info[i] = font_initial[i];
535 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
537 int font_bitmap_id = font_info[i].special_bitmap_id[j];
538 int graphic = font_info[i].special_graphic[j];
540 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
541 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
543 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
544 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
547 /* copy font relevant information from graphics information */
548 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
549 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
550 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
551 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
552 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
554 font_bitmap_info[font_bitmap_id].offset_x =
555 graphic_info[graphic].offset_x;
556 font_bitmap_info[font_bitmap_id].offset_y =
557 graphic_info[graphic].offset_y;
559 font_bitmap_info[font_bitmap_id].draw_xoffset =
560 graphic_info[graphic].draw_xoffset;
561 font_bitmap_info[font_bitmap_id].draw_yoffset =
562 graphic_info[graphic].draw_yoffset;
564 font_bitmap_info[font_bitmap_id].num_chars =
565 graphic_info[graphic].anim_frames;
566 font_bitmap_info[font_bitmap_id].num_chars_per_line =
567 graphic_info[graphic].anim_frames_per_line;
571 InitFontInfo(font_bitmap_info, num_font_bitmaps,
572 getFontBitmapID, getFontFromToken);
575 static void InitGlobalAnimGraphicInfo(void)
577 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
578 int num_property_mappings = getImageListPropertyMappingSize();
581 if (graphic_info == NULL) /* still at startup phase */
584 /* always start with reliable default values (no global animations) */
585 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
586 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
587 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
588 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
590 /* initialize global animation definitions from static configuration */
591 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
593 int j = GLOBAL_ANIM_ID_PART_BASE;
594 int k = GFX_SPECIAL_ARG_DEFAULT;
596 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
599 /* initialize global animation definitions from dynamic configuration */
600 for (i = 0; i < num_property_mappings; i++)
602 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
603 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
604 int special = property_mapping[i].ext3_index;
605 int graphic = property_mapping[i].artwork_index;
607 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
610 /* set animation part to base part, if not specified */
611 if (!IS_GLOBAL_ANIM_PART(part_nr))
612 part_nr = GLOBAL_ANIM_ID_PART_BASE;
614 /* set animation screen to default, if not specified */
615 if (!IS_SPECIAL_GFX_ARG(special))
616 special = GFX_SPECIAL_ARG_DEFAULT;
618 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
620 /* fix default value for ".draw_masked" (for backward compatibility) */
621 struct GraphicInfo *g = &graphic_info[graphic];
622 struct FileInfo *image = getImageListEntryFromImageID(graphic);
623 char **parameter_raw = image->parameter;
624 int p = GFX_ARG_DRAW_MASKED;
625 int draw_masked = get_graphic_parameter_value(parameter_raw[p],
626 image_config_suffix[p].token,
627 image_config_suffix[p].type);
629 /* if ".draw_masked" parameter is undefined, use default value "TRUE" */
630 if (draw_masked == ARG_UNDEFINED_VALUE)
631 g->draw_masked = TRUE;
635 printf("::: InitGlobalAnimGraphicInfo\n");
637 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
638 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
639 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
640 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
641 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
642 printf("::: - anim %d, part %d, mode %d => %d\n",
643 i, j, k, global_anim_info[i].graphic[j][k]);
647 static void InitGlobalAnimSoundInfo(void)
649 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
650 int num_property_mappings = getSoundListPropertyMappingSize();
653 /* always start with reliable default values (no global animation sounds) */
654 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
655 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
656 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
657 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
659 /* initialize global animation sound definitions from dynamic configuration */
660 for (i = 0; i < num_property_mappings; i++)
662 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
663 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
664 int special = property_mapping[i].ext3_index;
665 int sound = property_mapping[i].artwork_index;
667 // sound uses control definition; map it to position of graphic (artwork)
668 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
670 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
673 /* set animation part to base part, if not specified */
674 if (!IS_GLOBAL_ANIM_PART(part_nr))
675 part_nr = GLOBAL_ANIM_ID_PART_BASE;
677 /* set animation screen to default, if not specified */
678 if (!IS_SPECIAL_GFX_ARG(special))
679 special = GFX_SPECIAL_ARG_DEFAULT;
681 global_anim_info[anim_nr].sound[part_nr][special] = sound;
685 printf("::: InitGlobalAnimSoundInfo\n");
687 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
688 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
689 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
690 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
691 printf("::: - anim %d, part %d, mode %d => %d\n",
692 i, j, k, global_anim_info[i].sound[j][k]);
696 static void InitGlobalAnimMusicInfo(void)
698 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
699 int num_property_mappings = getMusicListPropertyMappingSize();
702 /* always start with reliable default values (no global animation music) */
703 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
704 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
705 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
706 global_anim_info[i].music[j][k] = MUS_UNDEFINED;
708 /* initialize global animation music definitions from dynamic configuration */
709 for (i = 0; i < num_property_mappings; i++)
711 int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
712 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
713 int special = property_mapping[i].ext2_index;
714 int music = property_mapping[i].artwork_index;
716 // music uses control definition; map it to position of graphic (artwork)
717 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
719 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
722 /* set animation part to base part, if not specified */
723 if (!IS_GLOBAL_ANIM_PART(part_nr))
724 part_nr = GLOBAL_ANIM_ID_PART_BASE;
726 /* set animation screen to default, if not specified */
727 if (!IS_SPECIAL_GFX_ARG(special))
728 special = GFX_SPECIAL_ARG_DEFAULT;
730 global_anim_info[anim_nr].music[part_nr][special] = music;
734 printf("::: InitGlobalAnimMusicInfo\n");
736 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
737 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
738 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
739 if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
740 printf("::: - anim %d, part %d, mode %d => %d\n",
741 i, j, k, global_anim_info[i].music[j][k]);
745 static void InitElementGraphicInfo(void)
747 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
748 int num_property_mappings = getImageListPropertyMappingSize();
751 if (graphic_info == NULL) /* still at startup phase */
754 /* set values to -1 to identify later as "uninitialized" values */
755 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
757 for (act = 0; act < NUM_ACTIONS; act++)
759 element_info[i].graphic[act] = -1;
760 element_info[i].crumbled[act] = -1;
762 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
764 element_info[i].direction_graphic[act][dir] = -1;
765 element_info[i].direction_crumbled[act][dir] = -1;
772 /* initialize normal element/graphic mapping from static configuration */
773 for (i = 0; element_to_graphic[i].element > -1; i++)
775 int element = element_to_graphic[i].element;
776 int action = element_to_graphic[i].action;
777 int direction = element_to_graphic[i].direction;
778 boolean crumbled = element_to_graphic[i].crumbled;
779 int graphic = element_to_graphic[i].graphic;
780 int base_graphic = el2baseimg(element);
782 if (graphic_info[graphic].bitmap == NULL)
785 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
788 boolean base_redefined =
789 getImageListEntryFromImageID(base_graphic)->redefined;
790 boolean act_dir_redefined =
791 getImageListEntryFromImageID(graphic)->redefined;
793 /* if the base graphic ("emerald", for example) has been redefined,
794 but not the action graphic ("emerald.falling", for example), do not
795 use an existing (in this case considered obsolete) action graphic
796 anymore, but use the automatically determined default graphic */
797 if (base_redefined && !act_dir_redefined)
802 action = ACTION_DEFAULT;
807 element_info[element].direction_crumbled[action][direction] = graphic;
809 element_info[element].crumbled[action] = graphic;
814 element_info[element].direction_graphic[action][direction] = graphic;
816 element_info[element].graphic[action] = graphic;
820 /* initialize normal element/graphic mapping from dynamic configuration */
821 for (i = 0; i < num_property_mappings; i++)
823 int element = property_mapping[i].base_index;
824 int action = property_mapping[i].ext1_index;
825 int direction = property_mapping[i].ext2_index;
826 int special = property_mapping[i].ext3_index;
827 int graphic = property_mapping[i].artwork_index;
828 boolean crumbled = FALSE;
830 if (special == GFX_SPECIAL_ARG_CRUMBLED)
836 if (graphic_info[graphic].bitmap == NULL)
839 if (element >= MAX_NUM_ELEMENTS || special != -1)
843 action = ACTION_DEFAULT;
848 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
849 element_info[element].direction_crumbled[action][dir] = -1;
852 element_info[element].direction_crumbled[action][direction] = graphic;
854 element_info[element].crumbled[action] = graphic;
859 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
860 element_info[element].direction_graphic[action][dir] = -1;
863 element_info[element].direction_graphic[action][direction] = graphic;
865 element_info[element].graphic[action] = graphic;
869 /* now copy all graphics that are defined to be cloned from other graphics */
870 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
872 int graphic = element_info[i].graphic[ACTION_DEFAULT];
873 int crumbled_like, diggable_like;
878 crumbled_like = graphic_info[graphic].crumbled_like;
879 diggable_like = graphic_info[graphic].diggable_like;
881 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
883 for (act = 0; act < NUM_ACTIONS; act++)
884 element_info[i].crumbled[act] =
885 element_info[crumbled_like].crumbled[act];
886 for (act = 0; act < NUM_ACTIONS; act++)
887 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
888 element_info[i].direction_crumbled[act][dir] =
889 element_info[crumbled_like].direction_crumbled[act][dir];
892 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
894 element_info[i].graphic[ACTION_DIGGING] =
895 element_info[diggable_like].graphic[ACTION_DIGGING];
896 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
897 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
898 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
902 /* set hardcoded definitions for some runtime elements without graphic */
903 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
905 /* set hardcoded definitions for some internal elements without graphic */
906 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
908 if (IS_EDITOR_CASCADE_INACTIVE(i))
909 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
910 else if (IS_EDITOR_CASCADE_ACTIVE(i))
911 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
914 /* now set all undefined/invalid graphics to -1 to set to default after it */
915 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
917 for (act = 0; act < NUM_ACTIONS; act++)
921 graphic = element_info[i].graphic[act];
922 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
923 element_info[i].graphic[act] = -1;
925 graphic = element_info[i].crumbled[act];
926 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
927 element_info[i].crumbled[act] = -1;
929 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
931 graphic = element_info[i].direction_graphic[act][dir];
932 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
933 element_info[i].direction_graphic[act][dir] = -1;
935 graphic = element_info[i].direction_crumbled[act][dir];
936 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
937 element_info[i].direction_crumbled[act][dir] = -1;
944 /* adjust graphics with 2nd tile for movement according to direction
945 (do this before correcting '-1' values to minimize calculations) */
946 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
948 for (act = 0; act < NUM_ACTIONS; act++)
950 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
952 int graphic = element_info[i].direction_graphic[act][dir];
953 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
955 if (act == ACTION_FALLING) /* special case */
956 graphic = element_info[i].graphic[act];
959 graphic_info[graphic].double_movement &&
960 graphic_info[graphic].swap_double_tiles != 0)
962 struct GraphicInfo *g = &graphic_info[graphic];
963 int src_x_front = g->src_x;
964 int src_y_front = g->src_y;
965 int src_x_back = g->src_x + g->offset2_x;
966 int src_y_back = g->src_y + g->offset2_y;
967 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
969 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
970 src_y_front < src_y_back);
971 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
972 boolean swap_movement_tiles_autodetected =
973 (!frames_are_ordered_diagonally &&
974 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
975 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
976 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
977 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
979 /* swap frontside and backside graphic tile coordinates, if needed */
980 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
982 /* get current (wrong) backside tile coordinates */
983 getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
985 /* set frontside tile coordinates to backside tile coordinates */
986 g->src_x = src_x_back;
987 g->src_y = src_y_back;
989 /* invert tile offset to point to new backside tile coordinates */
993 /* do not swap front and backside tiles again after correction */
994 g->swap_double_tiles = 0;
1001 UPDATE_BUSY_STATE();
1003 /* now set all '-1' values to element specific default values */
1004 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1006 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1007 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1008 int default_direction_graphic[NUM_DIRECTIONS_FULL];
1009 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1011 if (default_graphic == -1)
1012 default_graphic = IMG_UNKNOWN;
1014 if (default_crumbled == -1)
1015 default_crumbled = default_graphic;
1017 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1019 default_direction_graphic[dir] =
1020 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1021 default_direction_crumbled[dir] =
1022 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1024 if (default_direction_graphic[dir] == -1)
1025 default_direction_graphic[dir] = default_graphic;
1027 if (default_direction_crumbled[dir] == -1)
1028 default_direction_crumbled[dir] = default_direction_graphic[dir];
1031 for (act = 0; act < NUM_ACTIONS; act++)
1033 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
1034 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
1035 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1036 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1037 act == ACTION_TURNING_FROM_RIGHT ||
1038 act == ACTION_TURNING_FROM_UP ||
1039 act == ACTION_TURNING_FROM_DOWN);
1041 /* generic default action graphic (defined by "[default]" directive) */
1042 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1043 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1044 int default_remove_graphic = IMG_EMPTY;
1046 if (act_remove && default_action_graphic != -1)
1047 default_remove_graphic = default_action_graphic;
1049 /* look for special default action graphic (classic game specific) */
1050 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1051 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1052 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1053 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1054 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1055 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1056 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1057 default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1059 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1060 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1061 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1062 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1063 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1064 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1065 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1066 default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1068 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1069 /* !!! make this better !!! */
1070 if (i == EL_EMPTY_SPACE)
1072 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1073 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1076 if (default_action_graphic == -1)
1077 default_action_graphic = default_graphic;
1079 if (default_action_crumbled == -1)
1080 default_action_crumbled = default_action_graphic;
1082 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1084 /* use action graphic as the default direction graphic, if undefined */
1085 int default_action_direction_graphic = element_info[i].graphic[act];
1086 int default_action_direction_crumbled = element_info[i].crumbled[act];
1088 /* no graphic for current action -- use default direction graphic */
1089 if (default_action_direction_graphic == -1)
1090 default_action_direction_graphic =
1091 (act_remove ? default_remove_graphic :
1093 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1094 default_action_graphic != default_graphic ?
1095 default_action_graphic :
1096 default_direction_graphic[dir]);
1098 if (element_info[i].direction_graphic[act][dir] == -1)
1099 element_info[i].direction_graphic[act][dir] =
1100 default_action_direction_graphic;
1102 if (default_action_direction_crumbled == -1)
1103 default_action_direction_crumbled =
1104 element_info[i].direction_graphic[act][dir];
1106 if (element_info[i].direction_crumbled[act][dir] == -1)
1107 element_info[i].direction_crumbled[act][dir] =
1108 default_action_direction_crumbled;
1111 /* no graphic for this specific action -- use default action graphic */
1112 if (element_info[i].graphic[act] == -1)
1113 element_info[i].graphic[act] =
1114 (act_remove ? default_remove_graphic :
1115 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1116 default_action_graphic);
1118 if (element_info[i].crumbled[act] == -1)
1119 element_info[i].crumbled[act] = element_info[i].graphic[act];
1123 UPDATE_BUSY_STATE();
1126 static void InitElementSpecialGraphicInfo(void)
1128 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1129 int num_property_mappings = getImageListPropertyMappingSize();
1132 /* always start with reliable default values */
1133 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1134 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1135 element_info[i].special_graphic[j] =
1136 element_info[i].graphic[ACTION_DEFAULT];
1138 /* initialize special element/graphic mapping from static configuration */
1139 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1141 int element = element_to_special_graphic[i].element;
1142 int special = element_to_special_graphic[i].special;
1143 int graphic = element_to_special_graphic[i].graphic;
1144 int base_graphic = el2baseimg(element);
1145 boolean base_redefined =
1146 getImageListEntryFromImageID(base_graphic)->redefined;
1147 boolean special_redefined =
1148 getImageListEntryFromImageID(graphic)->redefined;
1150 /* if the base graphic ("emerald", for example) has been redefined,
1151 but not the special graphic ("emerald.EDITOR", for example), do not
1152 use an existing (in this case considered obsolete) special graphic
1153 anymore, but use the automatically created (down-scaled) graphic */
1154 if (base_redefined && !special_redefined)
1157 element_info[element].special_graphic[special] = graphic;
1160 /* initialize special element/graphic mapping from dynamic configuration */
1161 for (i = 0; i < num_property_mappings; i++)
1163 int element = property_mapping[i].base_index;
1164 int action = property_mapping[i].ext1_index;
1165 int direction = property_mapping[i].ext2_index;
1166 int special = property_mapping[i].ext3_index;
1167 int graphic = property_mapping[i].artwork_index;
1169 /* for action ".active", replace element with active element, if exists */
1170 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1172 element = ELEMENT_ACTIVE(element);
1176 if (element >= MAX_NUM_ELEMENTS)
1179 /* do not change special graphic if action or direction was specified */
1180 if (action != -1 || direction != -1)
1183 if (IS_SPECIAL_GFX_ARG(special))
1184 element_info[element].special_graphic[special] = graphic;
1187 /* now set all undefined/invalid graphics to default */
1188 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1189 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1190 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1191 element_info[i].special_graphic[j] =
1192 element_info[i].graphic[ACTION_DEFAULT];
1195 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1197 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1198 return get_parameter_value(value_raw, suffix, type);
1200 if (strEqual(value_raw, ARG_UNDEFINED))
1201 return ARG_UNDEFINED_VALUE;
1203 if (type == TYPE_ELEMENT)
1205 char *value = getHashEntry(element_token_hash, value_raw);
1209 Error(ERR_INFO_LINE, "-");
1210 Error(ERR_INFO, "warning: error found in config file:");
1211 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1212 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1213 Error(ERR_INFO, "custom graphic rejected for this element/action");
1214 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1215 Error(ERR_INFO_LINE, "-");
1218 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1220 else if (type == TYPE_GRAPHIC)
1222 char *value = getHashEntry(graphic_token_hash, value_raw);
1223 int fallback_graphic = IMG_CHAR_EXCLAM;
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 graphic token '%s'", value_raw);
1231 Error(ERR_INFO, "custom graphic rejected for this element/action");
1232 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1233 Error(ERR_INFO_LINE, "-");
1236 return (value != NULL ? atoi(value) : fallback_graphic);
1242 static int get_scaled_graphic_width(int graphic)
1244 int original_width = getOriginalImageWidthFromImageID(graphic);
1245 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1247 return original_width * scale_up_factor;
1250 static int get_scaled_graphic_height(int graphic)
1252 int original_height = getOriginalImageHeightFromImageID(graphic);
1253 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1255 return original_height * scale_up_factor;
1258 static void set_graphic_parameters_ext(int graphic, int *parameter,
1259 Bitmap **src_bitmaps)
1261 struct GraphicInfo *g = &graphic_info[graphic];
1262 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1263 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1264 int anim_frames_per_line = 1;
1266 /* always start with reliable default values */
1267 g->src_image_width = 0;
1268 g->src_image_height = 0;
1271 g->width = TILEX; /* default for element graphics */
1272 g->height = TILEY; /* default for element graphics */
1273 g->offset_x = 0; /* one or both of these values ... */
1274 g->offset_y = 0; /* ... will be corrected later */
1275 g->offset2_x = 0; /* one or both of these values ... */
1276 g->offset2_y = 0; /* ... will be corrected later */
1277 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1278 g->crumbled_like = -1; /* do not use clone element */
1279 g->diggable_like = -1; /* do not use clone element */
1280 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1281 g->scale_up_factor = 1; /* default: no scaling up */
1282 g->tile_size = TILESIZE; /* default: standard tile size */
1283 g->clone_from = -1; /* do not use clone graphic */
1284 g->init_delay_fixed = 0;
1285 g->init_delay_random = 0;
1286 g->anim_delay_fixed = 0;
1287 g->anim_delay_random = 0;
1288 g->post_delay_fixed = 0;
1289 g->post_delay_random = 0;
1290 g->init_event = ANIM_EVENT_DEFAULT;
1291 g->anim_event = ANIM_EVENT_DEFAULT;
1292 g->init_event_action = -1;
1293 g->anim_event_action = -1;
1294 g->draw_masked = FALSE;
1296 g->fade_mode = FADE_MODE_DEFAULT;
1300 g->align = ALIGN_CENTER; /* default for title screens */
1301 g->valign = VALIGN_MIDDLE; /* default for title screens */
1302 g->sort_priority = 0; /* default for title screens */
1304 g->style = STYLE_DEFAULT;
1306 g->bitmaps = src_bitmaps;
1307 g->bitmap = src_bitmap;
1309 /* optional zoom factor for scaling up the image to a larger size */
1310 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1311 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1312 if (g->scale_up_factor < 1)
1313 g->scale_up_factor = 1; /* no scaling */
1315 /* optional tile size for using non-standard image size */
1316 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1318 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1321 // CHECK: should tile sizes less than standard tile size be allowed?
1322 if (g->tile_size < TILESIZE)
1323 g->tile_size = TILESIZE; /* standard tile size */
1326 // when setting tile size, also set width and height accordingly
1327 g->width = g->tile_size;
1328 g->height = g->tile_size;
1331 if (g->use_image_size)
1333 /* set new default bitmap size (with scaling, but without small images) */
1334 g->width = get_scaled_graphic_width(graphic);
1335 g->height = get_scaled_graphic_height(graphic);
1338 /* optional width and height of each animation frame */
1339 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1340 g->width = parameter[GFX_ARG_WIDTH];
1341 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1342 g->height = parameter[GFX_ARG_HEIGHT];
1344 /* optional x and y tile position of animation frame sequence */
1345 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1346 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1347 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1348 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1350 /* optional x and y pixel position of animation frame sequence */
1351 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1352 g->src_x = parameter[GFX_ARG_X];
1353 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1354 g->src_y = parameter[GFX_ARG_Y];
1360 Error(ERR_INFO_LINE, "-");
1361 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1362 g->width, getTokenFromImageID(graphic), TILEX);
1363 Error(ERR_INFO_LINE, "-");
1365 g->width = TILEX; /* will be checked to be inside bitmap later */
1370 Error(ERR_INFO_LINE, "-");
1371 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1372 g->height, getTokenFromImageID(graphic), TILEY);
1373 Error(ERR_INFO_LINE, "-");
1375 g->height = TILEY; /* will be checked to be inside bitmap later */
1381 /* get final bitmap size (with scaling, but without small images) */
1382 int src_image_width = get_scaled_graphic_width(graphic);
1383 int src_image_height = get_scaled_graphic_height(graphic);
1385 if (src_image_width == 0 || src_image_height == 0)
1387 /* only happens when loaded outside artwork system (like "global.busy") */
1388 src_image_width = src_bitmap->width;
1389 src_image_height = src_bitmap->height;
1392 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1394 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1395 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1399 anim_frames_per_row = MAX(1, src_image_width / g->width);
1400 anim_frames_per_col = MAX(1, src_image_height / g->height);
1403 g->src_image_width = src_image_width;
1404 g->src_image_height = src_image_height;
1407 /* correct x or y offset dependent of vertical or horizontal frame order */
1408 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1410 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1411 parameter[GFX_ARG_OFFSET] : g->height);
1412 anim_frames_per_line = anim_frames_per_col;
1414 else /* frames are ordered horizontally */
1416 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1417 parameter[GFX_ARG_OFFSET] : g->width);
1418 anim_frames_per_line = anim_frames_per_row;
1421 /* optionally, the x and y offset of frames can be specified directly */
1422 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1423 g->offset_x = parameter[GFX_ARG_XOFFSET];
1424 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1425 g->offset_y = parameter[GFX_ARG_YOFFSET];
1427 /* optionally, moving animations may have separate start and end graphics */
1428 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1430 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1431 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1433 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1434 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1435 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1436 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1437 else /* frames are ordered horizontally */
1438 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1439 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1441 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1442 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1443 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1444 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1445 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1447 /* optionally, the second movement tile can be specified as start tile */
1448 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1449 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1451 /* automatically determine correct number of frames, if not defined */
1452 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1453 g->anim_frames = parameter[GFX_ARG_FRAMES];
1454 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1455 g->anim_frames = anim_frames_per_row;
1456 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1457 g->anim_frames = anim_frames_per_col;
1461 if (g->anim_frames == 0) /* frames must be at least 1 */
1464 g->anim_frames_per_line =
1465 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1466 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1468 g->anim_delay = parameter[GFX_ARG_DELAY];
1469 if (g->anim_delay == 0) /* delay must be at least 1 */
1472 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1474 /* automatically determine correct start frame, if not defined */
1475 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1476 g->anim_start_frame = 0;
1477 else if (g->anim_mode & ANIM_REVERSE)
1478 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1480 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1482 /* animation synchronized with global frame counter, not move position */
1483 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1485 /* optional element for cloning crumble graphics */
1486 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1487 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1489 /* optional element for cloning digging graphics */
1490 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1491 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1493 /* optional border size for "crumbling" diggable graphics */
1494 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1495 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1497 /* used for global animations and player "boring" and "sleeping" actions */
1498 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1499 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1500 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1501 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1502 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1503 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1504 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1505 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1506 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1507 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1508 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1509 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1511 /* used for global animations */
1512 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1513 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1514 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1515 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1516 if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1517 g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1518 if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1519 g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1521 /* used for toon animations and global animations */
1522 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1523 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1524 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1525 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1526 g->direction = parameter[GFX_ARG_DIRECTION];
1527 g->position = parameter[GFX_ARG_POSITION];
1528 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1529 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1531 /* this is only used for drawing font characters */
1532 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1533 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1535 /* use a different default value for global animations and toons */
1536 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1537 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1538 g->draw_masked = TRUE;
1540 /* this is used for drawing envelopes, global animations and toons */
1541 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1542 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1544 /* used for toon animations and global animations */
1545 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1546 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1548 /* optional graphic for cloning all graphics settings */
1549 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1550 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1552 /* optional settings for drawing title screens and title messages */
1553 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1554 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1555 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1556 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1557 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1558 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1559 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1560 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1561 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1562 g->align = parameter[GFX_ARG_ALIGN];
1563 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1564 g->valign = parameter[GFX_ARG_VALIGN];
1565 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1566 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1568 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1569 g->class = parameter[GFX_ARG_CLASS];
1570 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1571 g->style = parameter[GFX_ARG_STYLE];
1573 /* this is only used for drawing menu buttons and text */
1574 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1575 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1576 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1577 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1580 static void set_graphic_parameters(int graphic)
1582 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1583 char **parameter_raw = image->parameter;
1584 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1585 int parameter[NUM_GFX_ARGS];
1588 /* if fallback to default artwork is done, also use the default parameters */
1589 if (image->fallback_to_default)
1590 parameter_raw = image->default_parameter;
1592 /* get integer values from string parameters */
1593 for (i = 0; i < NUM_GFX_ARGS; i++)
1594 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1595 image_config_suffix[i].token,
1596 image_config_suffix[i].type);
1598 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1600 UPDATE_BUSY_STATE();
1603 static void set_cloned_graphic_parameters(int graphic)
1605 int fallback_graphic = IMG_CHAR_EXCLAM;
1606 int max_num_images = getImageListSize();
1607 int clone_graphic = graphic_info[graphic].clone_from;
1608 int num_references_followed = 1;
1610 while (graphic_info[clone_graphic].clone_from != -1 &&
1611 num_references_followed < max_num_images)
1613 clone_graphic = graphic_info[clone_graphic].clone_from;
1615 num_references_followed++;
1618 if (num_references_followed >= max_num_images)
1620 Error(ERR_INFO_LINE, "-");
1621 Error(ERR_INFO, "warning: error found in config file:");
1622 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1623 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1624 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1625 Error(ERR_INFO, "custom graphic rejected for this element/action");
1627 if (graphic == fallback_graphic)
1628 Error(ERR_EXIT, "no fallback graphic available");
1630 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1631 Error(ERR_INFO_LINE, "-");
1633 graphic_info[graphic] = graphic_info[fallback_graphic];
1637 graphic_info[graphic] = graphic_info[clone_graphic];
1638 graphic_info[graphic].clone_from = clone_graphic;
1642 static void InitGraphicInfo(void)
1644 int fallback_graphic = IMG_CHAR_EXCLAM;
1645 int num_images = getImageListSize();
1648 /* use image size as default values for width and height for these images */
1649 static int full_size_graphics[] =
1652 IMG_GLOBAL_BORDER_MAIN,
1653 IMG_GLOBAL_BORDER_SCORES,
1654 IMG_GLOBAL_BORDER_EDITOR,
1655 IMG_GLOBAL_BORDER_PLAYING,
1658 IMG_BACKGROUND_ENVELOPE_1,
1659 IMG_BACKGROUND_ENVELOPE_2,
1660 IMG_BACKGROUND_ENVELOPE_3,
1661 IMG_BACKGROUND_ENVELOPE_4,
1662 IMG_BACKGROUND_REQUEST,
1665 IMG_BACKGROUND_TITLE_INITIAL,
1666 IMG_BACKGROUND_TITLE,
1667 IMG_BACKGROUND_MAIN,
1668 IMG_BACKGROUND_LEVELS,
1669 IMG_BACKGROUND_LEVELNR,
1670 IMG_BACKGROUND_SCORES,
1671 IMG_BACKGROUND_EDITOR,
1672 IMG_BACKGROUND_INFO,
1673 IMG_BACKGROUND_INFO_ELEMENTS,
1674 IMG_BACKGROUND_INFO_MUSIC,
1675 IMG_BACKGROUND_INFO_CREDITS,
1676 IMG_BACKGROUND_INFO_PROGRAM,
1677 IMG_BACKGROUND_INFO_VERSION,
1678 IMG_BACKGROUND_INFO_LEVELSET,
1679 IMG_BACKGROUND_SETUP,
1680 IMG_BACKGROUND_PLAYING,
1681 IMG_BACKGROUND_DOOR,
1682 IMG_BACKGROUND_TAPE,
1683 IMG_BACKGROUND_PANEL,
1684 IMG_BACKGROUND_PALETTE,
1685 IMG_BACKGROUND_TOOLBOX,
1687 IMG_TITLESCREEN_INITIAL_1,
1688 IMG_TITLESCREEN_INITIAL_2,
1689 IMG_TITLESCREEN_INITIAL_3,
1690 IMG_TITLESCREEN_INITIAL_4,
1691 IMG_TITLESCREEN_INITIAL_5,
1698 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1699 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1700 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1701 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1702 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1703 IMG_BACKGROUND_TITLEMESSAGE_1,
1704 IMG_BACKGROUND_TITLEMESSAGE_2,
1705 IMG_BACKGROUND_TITLEMESSAGE_3,
1706 IMG_BACKGROUND_TITLEMESSAGE_4,
1707 IMG_BACKGROUND_TITLEMESSAGE_5,
1712 checked_free(graphic_info);
1714 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1716 /* initialize "use_image_size" flag with default value */
1717 for (i = 0; i < num_images; i++)
1718 graphic_info[i].use_image_size = FALSE;
1720 /* initialize "use_image_size" flag from static configuration above */
1721 for (i = 0; full_size_graphics[i] != -1; i++)
1722 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1724 /* first set all graphic paramaters ... */
1725 for (i = 0; i < num_images; i++)
1726 set_graphic_parameters(i);
1728 /* ... then copy these parameters for cloned graphics */
1729 for (i = 0; i < num_images; i++)
1730 if (graphic_info[i].clone_from != -1)
1731 set_cloned_graphic_parameters(i);
1733 for (i = 0; i < num_images; i++)
1735 Bitmap *src_bitmap = graphic_info[i].bitmap;
1739 int src_bitmap_width, src_bitmap_height;
1741 /* now check if no animation frames are outside of the loaded image */
1743 if (graphic_info[i].bitmap == NULL)
1744 continue; /* skip check for optional images that are undefined */
1746 /* get image size (this can differ from the standard element tile size!) */
1747 width = graphic_info[i].width;
1748 height = graphic_info[i].height;
1750 /* get final bitmap size (with scaling, but without small images) */
1751 src_bitmap_width = graphic_info[i].src_image_width;
1752 src_bitmap_height = graphic_info[i].src_image_height;
1754 /* check if first animation frame is inside specified bitmap */
1756 /* do not use getGraphicSourceXY() here to get position of first frame; */
1757 /* this avoids calculating wrong start position for out-of-bounds frame */
1758 src_x = graphic_info[i].src_x;
1759 src_y = graphic_info[i].src_y;
1761 if (program.headless)
1764 if (src_x < 0 || src_y < 0 ||
1765 src_x + width > src_bitmap_width ||
1766 src_y + height > src_bitmap_height)
1768 Error(ERR_INFO_LINE, "-");
1769 Error(ERR_INFO, "warning: error found in config file:");
1770 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1771 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1772 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1773 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1775 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1776 src_x, src_y, src_bitmap_width, src_bitmap_height);
1777 Error(ERR_INFO, "custom graphic rejected for this element/action");
1779 if (i == fallback_graphic)
1780 Error(ERR_EXIT, "no fallback graphic available");
1782 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1783 Error(ERR_INFO_LINE, "-");
1785 graphic_info[i] = graphic_info[fallback_graphic];
1787 /* if first frame out of bounds, do not check last frame anymore */
1791 /* check if last animation frame is inside specified bitmap */
1793 last_frame = graphic_info[i].anim_frames - 1;
1794 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1796 if (src_x < 0 || src_y < 0 ||
1797 src_x + width > src_bitmap_width ||
1798 src_y + height > src_bitmap_height)
1800 Error(ERR_INFO_LINE, "-");
1801 Error(ERR_INFO, "warning: error found in config file:");
1802 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1803 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1804 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1805 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1807 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1808 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1809 Error(ERR_INFO, "custom graphic rejected for this element/action");
1811 if (i == fallback_graphic)
1812 Error(ERR_EXIT, "no fallback graphic available");
1814 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1815 Error(ERR_INFO_LINE, "-");
1817 graphic_info[i] = graphic_info[fallback_graphic];
1822 static void InitGraphicCompatibilityInfo(void)
1824 struct FileInfo *fi_global_door =
1825 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1826 int num_images = getImageListSize();
1829 /* the following compatibility handling is needed for the following case:
1830 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1831 graphics mainly used for door and panel graphics, like editor, tape and
1832 in-game buttons with hard-coded bitmap positions and button sizes; as
1833 these graphics now have individual definitions, redefining "global.door"
1834 to change all these graphics at once like before does not work anymore
1835 (because all those individual definitions still have their default values);
1836 to solve this, remap all those individual definitions that are not
1837 redefined to the new bitmap of "global.door" if it was redefined */
1839 /* special compatibility handling if image "global.door" was redefined */
1840 if (fi_global_door->redefined)
1842 for (i = 0; i < num_images; i++)
1844 struct FileInfo *fi = getImageListEntryFromImageID(i);
1846 /* process only those images that still use the default settings */
1849 /* process all images which default to same image as "global.door" */
1850 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1852 // printf("::: special treatment needed for token '%s'\n", fi->token);
1854 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1855 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1861 InitGraphicCompatibilityInfo_Doors();
1864 static void InitElementSoundInfo(void)
1866 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1867 int num_property_mappings = getSoundListPropertyMappingSize();
1870 /* set values to -1 to identify later as "uninitialized" values */
1871 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1872 for (act = 0; act < NUM_ACTIONS; act++)
1873 element_info[i].sound[act] = -1;
1875 /* initialize element/sound mapping from static configuration */
1876 for (i = 0; element_to_sound[i].element > -1; i++)
1878 int element = element_to_sound[i].element;
1879 int action = element_to_sound[i].action;
1880 int sound = element_to_sound[i].sound;
1881 boolean is_class = element_to_sound[i].is_class;
1884 action = ACTION_DEFAULT;
1887 element_info[element].sound[action] = sound;
1889 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1890 if (strEqual(element_info[j].class_name,
1891 element_info[element].class_name))
1892 element_info[j].sound[action] = sound;
1895 /* initialize element class/sound mapping from dynamic configuration */
1896 for (i = 0; i < num_property_mappings; i++)
1898 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1899 int action = property_mapping[i].ext1_index;
1900 int sound = property_mapping[i].artwork_index;
1902 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1906 action = ACTION_DEFAULT;
1908 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1909 if (strEqual(element_info[j].class_name,
1910 element_info[element_class].class_name))
1911 element_info[j].sound[action] = sound;
1914 /* initialize element/sound mapping from dynamic configuration */
1915 for (i = 0; i < num_property_mappings; i++)
1917 int element = property_mapping[i].base_index;
1918 int action = property_mapping[i].ext1_index;
1919 int sound = property_mapping[i].artwork_index;
1921 if (element >= MAX_NUM_ELEMENTS)
1925 action = ACTION_DEFAULT;
1927 element_info[element].sound[action] = sound;
1930 /* now set all '-1' values to element specific default values */
1931 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1933 for (act = 0; act < NUM_ACTIONS; act++)
1935 /* generic default action sound (defined by "[default]" directive) */
1936 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1938 /* look for special default action sound (classic game specific) */
1939 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1940 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1941 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1942 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1943 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1944 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1945 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1946 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1948 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1949 /* !!! make this better !!! */
1950 if (i == EL_EMPTY_SPACE)
1951 default_action_sound = element_info[EL_DEFAULT].sound[act];
1953 /* no sound for this specific action -- use default action sound */
1954 if (element_info[i].sound[act] == -1)
1955 element_info[i].sound[act] = default_action_sound;
1959 /* copy sound settings to some elements that are only stored in level file
1960 in native R'n'D levels, but are used by game engine in native EM levels */
1961 for (i = 0; copy_properties[i][0] != -1; i++)
1962 for (j = 1; j <= 4; j++)
1963 for (act = 0; act < NUM_ACTIONS; act++)
1964 element_info[copy_properties[i][j]].sound[act] =
1965 element_info[copy_properties[i][0]].sound[act];
1968 static void InitGameModeSoundInfo(void)
1972 /* set values to -1 to identify later as "uninitialized" values */
1973 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1976 /* initialize gamemode/sound mapping from static configuration */
1977 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1979 int gamemode = gamemode_to_sound[i].gamemode;
1980 int sound = gamemode_to_sound[i].sound;
1983 gamemode = GAME_MODE_DEFAULT;
1985 menu.sound[gamemode] = sound;
1988 /* now set all '-1' values to levelset specific default values */
1989 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1990 if (menu.sound[i] == -1)
1991 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1994 static void set_sound_parameters(int sound, char **parameter_raw)
1996 int parameter[NUM_SND_ARGS];
1999 /* get integer values from string parameters */
2000 for (i = 0; i < NUM_SND_ARGS; i++)
2002 get_parameter_value(parameter_raw[i],
2003 sound_config_suffix[i].token,
2004 sound_config_suffix[i].type);
2006 /* explicit loop mode setting in configuration overrides default value */
2007 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2008 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2010 /* sound volume to change the original volume when loading the sound file */
2011 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2013 /* sound priority to give certain sounds a higher or lower priority */
2014 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2017 static void InitSoundInfo(void)
2019 int *sound_effect_properties;
2020 int num_sounds = getSoundListSize();
2023 checked_free(sound_info);
2025 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2026 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2028 /* initialize sound effect for all elements to "no sound" */
2029 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2030 for (j = 0; j < NUM_ACTIONS; j++)
2031 element_info[i].sound[j] = SND_UNDEFINED;
2033 for (i = 0; i < num_sounds; i++)
2035 struct FileInfo *sound = getSoundListEntry(i);
2036 int len_effect_text = strlen(sound->token);
2038 sound_effect_properties[i] = ACTION_OTHER;
2039 sound_info[i].loop = FALSE; /* default: play sound only once */
2041 /* determine all loop sounds and identify certain sound classes */
2043 for (j = 0; element_action_info[j].suffix; j++)
2045 int len_action_text = strlen(element_action_info[j].suffix);
2047 if (len_action_text < len_effect_text &&
2048 strEqual(&sound->token[len_effect_text - len_action_text],
2049 element_action_info[j].suffix))
2051 sound_effect_properties[i] = element_action_info[j].value;
2052 sound_info[i].loop = element_action_info[j].is_loop_sound;
2058 /* associate elements and some selected sound actions */
2060 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2062 if (element_info[j].class_name)
2064 int len_class_text = strlen(element_info[j].class_name);
2066 if (len_class_text + 1 < len_effect_text &&
2067 strncmp(sound->token,
2068 element_info[j].class_name, len_class_text) == 0 &&
2069 sound->token[len_class_text] == '.')
2071 int sound_action_value = sound_effect_properties[i];
2073 element_info[j].sound[sound_action_value] = i;
2078 set_sound_parameters(i, sound->parameter);
2081 free(sound_effect_properties);
2084 static void InitGameModeMusicInfo(void)
2086 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2087 int num_property_mappings = getMusicListPropertyMappingSize();
2088 int default_levelset_music = -1;
2091 /* set values to -1 to identify later as "uninitialized" values */
2092 for (i = 0; i < MAX_LEVELS; i++)
2093 levelset.music[i] = -1;
2094 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2097 /* initialize gamemode/music mapping from static configuration */
2098 for (i = 0; gamemode_to_music[i].music > -1; i++)
2100 int gamemode = gamemode_to_music[i].gamemode;
2101 int music = gamemode_to_music[i].music;
2104 gamemode = GAME_MODE_DEFAULT;
2106 menu.music[gamemode] = music;
2109 /* initialize gamemode/music mapping from dynamic configuration */
2110 for (i = 0; i < num_property_mappings; i++)
2112 int prefix = property_mapping[i].base_index;
2113 int gamemode = property_mapping[i].ext2_index;
2114 int level = property_mapping[i].ext3_index;
2115 int music = property_mapping[i].artwork_index;
2117 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2121 gamemode = GAME_MODE_DEFAULT;
2123 /* level specific music only allowed for in-game music */
2124 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2125 gamemode = GAME_MODE_PLAYING;
2130 default_levelset_music = music;
2133 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2134 levelset.music[level] = music;
2135 if (gamemode != GAME_MODE_PLAYING)
2136 menu.music[gamemode] = music;
2139 /* now set all '-1' values to menu specific default values */
2140 /* (undefined values of "levelset.music[]" might stay at "-1" to
2141 allow dynamic selection of music files from music directory!) */
2142 for (i = 0; i < MAX_LEVELS; i++)
2143 if (levelset.music[i] == -1)
2144 levelset.music[i] = default_levelset_music;
2145 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2146 if (menu.music[i] == -1)
2147 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2150 static void set_music_parameters(int music, char **parameter_raw)
2152 int parameter[NUM_MUS_ARGS];
2155 /* get integer values from string parameters */
2156 for (i = 0; i < NUM_MUS_ARGS; i++)
2158 get_parameter_value(parameter_raw[i],
2159 music_config_suffix[i].token,
2160 music_config_suffix[i].type);
2162 /* explicit loop mode setting in configuration overrides default value */
2163 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2164 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2167 static void InitMusicInfo(void)
2169 int num_music = getMusicListSize();
2172 checked_free(music_info);
2174 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2176 for (i = 0; i < num_music; i++)
2178 struct FileInfo *music = getMusicListEntry(i);
2179 int len_music_text = strlen(music->token);
2181 music_info[i].loop = TRUE; /* default: play music in loop mode */
2183 /* determine all loop music */
2185 for (j = 0; music_prefix_info[j].prefix; j++)
2187 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2189 if (len_prefix_text < len_music_text &&
2190 strncmp(music->token,
2191 music_prefix_info[j].prefix, len_prefix_text) == 0)
2193 music_info[i].loop = music_prefix_info[j].is_loop_music;
2199 set_music_parameters(i, music->parameter);
2203 static void ReinitializeGraphics(void)
2205 print_timestamp_init("ReinitializeGraphics");
2207 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2209 InitGraphicInfo(); /* graphic properties mapping */
2210 print_timestamp_time("InitGraphicInfo");
2211 InitElementGraphicInfo(); /* element game graphic mapping */
2212 print_timestamp_time("InitElementGraphicInfo");
2213 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2214 print_timestamp_time("InitElementSpecialGraphicInfo");
2216 InitElementSmallImages(); /* scale elements to all needed sizes */
2217 print_timestamp_time("InitElementSmallImages");
2218 InitScaledImages(); /* scale all other images, if needed */
2219 print_timestamp_time("InitScaledImages");
2220 InitBitmapPointers(); /* set standard size bitmap pointers */
2221 print_timestamp_time("InitBitmapPointers");
2222 InitFontGraphicInfo(); /* initialize text drawing functions */
2223 print_timestamp_time("InitFontGraphicInfo");
2224 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2225 print_timestamp_time("InitGlobalAnimGraphicInfo");
2227 InitImageTextures(); /* create textures for certain images */
2228 print_timestamp_time("InitImageTextures");
2230 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2231 print_timestamp_time("InitGraphicInfo_EM");
2233 InitGraphicCompatibilityInfo();
2234 print_timestamp_time("InitGraphicCompatibilityInfo");
2236 SetMainBackgroundImage(IMG_BACKGROUND);
2237 print_timestamp_time("SetMainBackgroundImage");
2238 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2239 print_timestamp_time("SetDoorBackgroundImage");
2242 print_timestamp_time("InitGadgets");
2244 print_timestamp_time("InitDoors");
2246 print_timestamp_done("ReinitializeGraphics");
2249 static void ReinitializeSounds(void)
2251 InitSoundInfo(); /* sound properties mapping */
2252 InitElementSoundInfo(); /* element game sound mapping */
2253 InitGameModeSoundInfo(); /* game mode sound mapping */
2254 InitGlobalAnimSoundInfo(); /* global animation sound settings */
2256 InitPlayLevelSound(); /* internal game sound settings */
2259 static void ReinitializeMusic(void)
2261 InitMusicInfo(); /* music properties mapping */
2262 InitGameModeMusicInfo(); /* game mode music mapping */
2263 InitGlobalAnimMusicInfo(); /* global animation music settings */
2266 static int get_special_property_bit(int element, int property_bit_nr)
2268 struct PropertyBitInfo
2274 static struct PropertyBitInfo pb_can_move_into_acid[] =
2276 /* the player may be able fall into acid when gravity is activated */
2281 { EL_SP_MURPHY, 0 },
2282 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2284 /* all elements that can move may be able to also move into acid */
2287 { EL_BUG_RIGHT, 1 },
2290 { EL_SPACESHIP, 2 },
2291 { EL_SPACESHIP_LEFT, 2 },
2292 { EL_SPACESHIP_RIGHT, 2 },
2293 { EL_SPACESHIP_UP, 2 },
2294 { EL_SPACESHIP_DOWN, 2 },
2295 { EL_BD_BUTTERFLY, 3 },
2296 { EL_BD_BUTTERFLY_LEFT, 3 },
2297 { EL_BD_BUTTERFLY_RIGHT, 3 },
2298 { EL_BD_BUTTERFLY_UP, 3 },
2299 { EL_BD_BUTTERFLY_DOWN, 3 },
2300 { EL_BD_FIREFLY, 4 },
2301 { EL_BD_FIREFLY_LEFT, 4 },
2302 { EL_BD_FIREFLY_RIGHT, 4 },
2303 { EL_BD_FIREFLY_UP, 4 },
2304 { EL_BD_FIREFLY_DOWN, 4 },
2306 { EL_YAMYAM_LEFT, 5 },
2307 { EL_YAMYAM_RIGHT, 5 },
2308 { EL_YAMYAM_UP, 5 },
2309 { EL_YAMYAM_DOWN, 5 },
2310 { EL_DARK_YAMYAM, 6 },
2313 { EL_PACMAN_LEFT, 8 },
2314 { EL_PACMAN_RIGHT, 8 },
2315 { EL_PACMAN_UP, 8 },
2316 { EL_PACMAN_DOWN, 8 },
2318 { EL_MOLE_LEFT, 9 },
2319 { EL_MOLE_RIGHT, 9 },
2321 { EL_MOLE_DOWN, 9 },
2325 { EL_SATELLITE, 13 },
2326 { EL_SP_SNIKSNAK, 14 },
2327 { EL_SP_ELECTRON, 15 },
2330 { EL_EMC_ANDROID, 18 },
2335 static struct PropertyBitInfo pb_dont_collide_with[] =
2337 { EL_SP_SNIKSNAK, 0 },
2338 { EL_SP_ELECTRON, 1 },
2346 struct PropertyBitInfo *pb_info;
2349 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2350 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2355 struct PropertyBitInfo *pb_info = NULL;
2358 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2359 if (pb_definition[i].bit_nr == property_bit_nr)
2360 pb_info = pb_definition[i].pb_info;
2362 if (pb_info == NULL)
2365 for (i = 0; pb_info[i].element != -1; i++)
2366 if (pb_info[i].element == element)
2367 return pb_info[i].bit_nr;
2372 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2373 boolean property_value)
2375 int bit_nr = get_special_property_bit(element, property_bit_nr);
2380 *bitfield |= (1 << bit_nr);
2382 *bitfield &= ~(1 << bit_nr);
2386 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2388 int bit_nr = get_special_property_bit(element, property_bit_nr);
2391 return ((*bitfield & (1 << bit_nr)) != 0);
2396 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2398 static int group_nr;
2399 static struct ElementGroupInfo *group;
2400 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2403 if (actual_group == NULL) /* not yet initialized */
2406 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2408 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2409 group_element - EL_GROUP_START + 1);
2411 /* replace element which caused too deep recursion by question mark */
2412 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2417 if (recursion_depth == 0) /* initialization */
2419 group = actual_group;
2420 group_nr = GROUP_NR(group_element);
2422 group->num_elements_resolved = 0;
2423 group->choice_pos = 0;
2425 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2426 element_info[i].in_group[group_nr] = FALSE;
2429 for (i = 0; i < actual_group->num_elements; i++)
2431 int element = actual_group->element[i];
2433 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2436 if (IS_GROUP_ELEMENT(element))
2437 ResolveGroupElementExt(element, recursion_depth + 1);
2440 group->element_resolved[group->num_elements_resolved++] = element;
2441 element_info[element].in_group[group_nr] = TRUE;
2446 void ResolveGroupElement(int group_element)
2448 ResolveGroupElementExt(group_element, 0);
2451 void InitElementPropertiesStatic(void)
2453 static boolean clipboard_elements_initialized = FALSE;
2455 static int ep_diggable[] =
2460 EL_SP_BUGGY_BASE_ACTIVATING,
2463 EL_INVISIBLE_SAND_ACTIVE,
2466 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2467 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2472 EL_SP_BUGGY_BASE_ACTIVE,
2479 static int ep_collectible_only[] =
2501 EL_DYNABOMB_INCREASE_NUMBER,
2502 EL_DYNABOMB_INCREASE_SIZE,
2503 EL_DYNABOMB_INCREASE_POWER,
2521 /* !!! handle separately !!! */
2522 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2528 static int ep_dont_run_into[] =
2530 /* same elements as in 'ep_dont_touch' */
2536 /* same elements as in 'ep_dont_collide_with' */
2548 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2553 EL_SP_BUGGY_BASE_ACTIVE,
2560 static int ep_dont_collide_with[] =
2562 /* same elements as in 'ep_dont_touch' */
2579 static int ep_dont_touch[] =
2589 static int ep_indestructible[] =
2593 EL_ACID_POOL_TOPLEFT,
2594 EL_ACID_POOL_TOPRIGHT,
2595 EL_ACID_POOL_BOTTOMLEFT,
2596 EL_ACID_POOL_BOTTOM,
2597 EL_ACID_POOL_BOTTOMRIGHT,
2598 EL_SP_HARDWARE_GRAY,
2599 EL_SP_HARDWARE_GREEN,
2600 EL_SP_HARDWARE_BLUE,
2602 EL_SP_HARDWARE_YELLOW,
2603 EL_SP_HARDWARE_BASE_1,
2604 EL_SP_HARDWARE_BASE_2,
2605 EL_SP_HARDWARE_BASE_3,
2606 EL_SP_HARDWARE_BASE_4,
2607 EL_SP_HARDWARE_BASE_5,
2608 EL_SP_HARDWARE_BASE_6,
2609 EL_INVISIBLE_STEELWALL,
2610 EL_INVISIBLE_STEELWALL_ACTIVE,
2611 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2612 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2613 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2614 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2615 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2616 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2617 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2618 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2619 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2620 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2621 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2622 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2624 EL_LIGHT_SWITCH_ACTIVE,
2625 EL_SIGN_EXCLAMATION,
2626 EL_SIGN_RADIOACTIVITY,
2633 EL_SIGN_ENTRY_FORBIDDEN,
2634 EL_SIGN_EMERGENCY_EXIT,
2642 EL_STEEL_EXIT_CLOSED,
2644 EL_STEEL_EXIT_OPENING,
2645 EL_STEEL_EXIT_CLOSING,
2646 EL_EM_STEEL_EXIT_CLOSED,
2647 EL_EM_STEEL_EXIT_OPEN,
2648 EL_EM_STEEL_EXIT_OPENING,
2649 EL_EM_STEEL_EXIT_CLOSING,
2650 EL_DC_STEELWALL_1_LEFT,
2651 EL_DC_STEELWALL_1_RIGHT,
2652 EL_DC_STEELWALL_1_TOP,
2653 EL_DC_STEELWALL_1_BOTTOM,
2654 EL_DC_STEELWALL_1_HORIZONTAL,
2655 EL_DC_STEELWALL_1_VERTICAL,
2656 EL_DC_STEELWALL_1_TOPLEFT,
2657 EL_DC_STEELWALL_1_TOPRIGHT,
2658 EL_DC_STEELWALL_1_BOTTOMLEFT,
2659 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2660 EL_DC_STEELWALL_1_TOPLEFT_2,
2661 EL_DC_STEELWALL_1_TOPRIGHT_2,
2662 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2663 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2664 EL_DC_STEELWALL_2_LEFT,
2665 EL_DC_STEELWALL_2_RIGHT,
2666 EL_DC_STEELWALL_2_TOP,
2667 EL_DC_STEELWALL_2_BOTTOM,
2668 EL_DC_STEELWALL_2_HORIZONTAL,
2669 EL_DC_STEELWALL_2_VERTICAL,
2670 EL_DC_STEELWALL_2_MIDDLE,
2671 EL_DC_STEELWALL_2_SINGLE,
2672 EL_STEELWALL_SLIPPERY,
2686 EL_GATE_1_GRAY_ACTIVE,
2687 EL_GATE_2_GRAY_ACTIVE,
2688 EL_GATE_3_GRAY_ACTIVE,
2689 EL_GATE_4_GRAY_ACTIVE,
2698 EL_EM_GATE_1_GRAY_ACTIVE,
2699 EL_EM_GATE_2_GRAY_ACTIVE,
2700 EL_EM_GATE_3_GRAY_ACTIVE,
2701 EL_EM_GATE_4_GRAY_ACTIVE,
2710 EL_EMC_GATE_5_GRAY_ACTIVE,
2711 EL_EMC_GATE_6_GRAY_ACTIVE,
2712 EL_EMC_GATE_7_GRAY_ACTIVE,
2713 EL_EMC_GATE_8_GRAY_ACTIVE,
2715 EL_DC_GATE_WHITE_GRAY,
2716 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2717 EL_DC_GATE_FAKE_GRAY,
2719 EL_SWITCHGATE_OPENING,
2720 EL_SWITCHGATE_CLOSED,
2721 EL_SWITCHGATE_CLOSING,
2722 EL_DC_SWITCHGATE_SWITCH_UP,
2723 EL_DC_SWITCHGATE_SWITCH_DOWN,
2725 EL_TIMEGATE_OPENING,
2727 EL_TIMEGATE_CLOSING,
2728 EL_DC_TIMEGATE_SWITCH,
2729 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2733 EL_TUBE_VERTICAL_LEFT,
2734 EL_TUBE_VERTICAL_RIGHT,
2735 EL_TUBE_HORIZONTAL_UP,
2736 EL_TUBE_HORIZONTAL_DOWN,
2741 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2742 EL_EXPANDABLE_STEELWALL_VERTICAL,
2743 EL_EXPANDABLE_STEELWALL_ANY,
2748 static int ep_slippery[] =
2762 EL_ROBOT_WHEEL_ACTIVE,
2768 EL_ACID_POOL_TOPLEFT,
2769 EL_ACID_POOL_TOPRIGHT,
2779 EL_STEELWALL_SLIPPERY,
2782 EL_EMC_WALL_SLIPPERY_1,
2783 EL_EMC_WALL_SLIPPERY_2,
2784 EL_EMC_WALL_SLIPPERY_3,
2785 EL_EMC_WALL_SLIPPERY_4,
2787 EL_EMC_MAGIC_BALL_ACTIVE,
2792 static int ep_can_change[] =
2797 static int ep_can_move[] =
2799 /* same elements as in 'pb_can_move_into_acid' */
2822 static int ep_can_fall[] =
2836 EL_QUICKSAND_FAST_FULL,
2838 EL_BD_MAGIC_WALL_FULL,
2839 EL_DC_MAGIC_WALL_FULL,
2853 static int ep_can_smash_player[] =
2879 static int ep_can_smash_enemies[] =
2888 static int ep_can_smash_everything[] =
2897 static int ep_explodes_by_fire[] =
2899 /* same elements as in 'ep_explodes_impact' */
2904 /* same elements as in 'ep_explodes_smashed' */
2914 EL_EM_DYNAMITE_ACTIVE,
2915 EL_DYNABOMB_PLAYER_1_ACTIVE,
2916 EL_DYNABOMB_PLAYER_2_ACTIVE,
2917 EL_DYNABOMB_PLAYER_3_ACTIVE,
2918 EL_DYNABOMB_PLAYER_4_ACTIVE,
2919 EL_DYNABOMB_INCREASE_NUMBER,
2920 EL_DYNABOMB_INCREASE_SIZE,
2921 EL_DYNABOMB_INCREASE_POWER,
2922 EL_SP_DISK_RED_ACTIVE,
2936 static int ep_explodes_smashed[] =
2938 /* same elements as in 'ep_explodes_impact' */
2952 static int ep_explodes_impact[] =
2961 static int ep_walkable_over[] =
2965 EL_SOKOBAN_FIELD_EMPTY,
2972 EL_EM_STEEL_EXIT_OPEN,
2973 EL_EM_STEEL_EXIT_OPENING,
2982 EL_GATE_1_GRAY_ACTIVE,
2983 EL_GATE_2_GRAY_ACTIVE,
2984 EL_GATE_3_GRAY_ACTIVE,
2985 EL_GATE_4_GRAY_ACTIVE,
2993 static int ep_walkable_inside[] =
2998 EL_TUBE_VERTICAL_LEFT,
2999 EL_TUBE_VERTICAL_RIGHT,
3000 EL_TUBE_HORIZONTAL_UP,
3001 EL_TUBE_HORIZONTAL_DOWN,
3010 static int ep_walkable_under[] =
3015 static int ep_passable_over[] =
3025 EL_EM_GATE_1_GRAY_ACTIVE,
3026 EL_EM_GATE_2_GRAY_ACTIVE,
3027 EL_EM_GATE_3_GRAY_ACTIVE,
3028 EL_EM_GATE_4_GRAY_ACTIVE,
3037 EL_EMC_GATE_5_GRAY_ACTIVE,
3038 EL_EMC_GATE_6_GRAY_ACTIVE,
3039 EL_EMC_GATE_7_GRAY_ACTIVE,
3040 EL_EMC_GATE_8_GRAY_ACTIVE,
3042 EL_DC_GATE_WHITE_GRAY,
3043 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3050 static int ep_passable_inside[] =
3056 EL_SP_PORT_HORIZONTAL,
3057 EL_SP_PORT_VERTICAL,
3059 EL_SP_GRAVITY_PORT_LEFT,
3060 EL_SP_GRAVITY_PORT_RIGHT,
3061 EL_SP_GRAVITY_PORT_UP,
3062 EL_SP_GRAVITY_PORT_DOWN,
3063 EL_SP_GRAVITY_ON_PORT_LEFT,
3064 EL_SP_GRAVITY_ON_PORT_RIGHT,
3065 EL_SP_GRAVITY_ON_PORT_UP,
3066 EL_SP_GRAVITY_ON_PORT_DOWN,
3067 EL_SP_GRAVITY_OFF_PORT_LEFT,
3068 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3069 EL_SP_GRAVITY_OFF_PORT_UP,
3070 EL_SP_GRAVITY_OFF_PORT_DOWN,
3075 static int ep_passable_under[] =
3080 static int ep_droppable[] =
3085 static int ep_explodes_1x1_old[] =
3090 static int ep_pushable[] =
3102 EL_SOKOBAN_FIELD_FULL,
3111 static int ep_explodes_cross_old[] =
3116 static int ep_protected[] =
3118 /* same elements as in 'ep_walkable_inside' */
3122 EL_TUBE_VERTICAL_LEFT,
3123 EL_TUBE_VERTICAL_RIGHT,
3124 EL_TUBE_HORIZONTAL_UP,
3125 EL_TUBE_HORIZONTAL_DOWN,
3131 /* same elements as in 'ep_passable_over' */
3140 EL_EM_GATE_1_GRAY_ACTIVE,
3141 EL_EM_GATE_2_GRAY_ACTIVE,
3142 EL_EM_GATE_3_GRAY_ACTIVE,
3143 EL_EM_GATE_4_GRAY_ACTIVE,
3152 EL_EMC_GATE_5_GRAY_ACTIVE,
3153 EL_EMC_GATE_6_GRAY_ACTIVE,
3154 EL_EMC_GATE_7_GRAY_ACTIVE,
3155 EL_EMC_GATE_8_GRAY_ACTIVE,
3157 EL_DC_GATE_WHITE_GRAY,
3158 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3162 /* same elements as in 'ep_passable_inside' */
3167 EL_SP_PORT_HORIZONTAL,
3168 EL_SP_PORT_VERTICAL,
3170 EL_SP_GRAVITY_PORT_LEFT,
3171 EL_SP_GRAVITY_PORT_RIGHT,
3172 EL_SP_GRAVITY_PORT_UP,
3173 EL_SP_GRAVITY_PORT_DOWN,
3174 EL_SP_GRAVITY_ON_PORT_LEFT,
3175 EL_SP_GRAVITY_ON_PORT_RIGHT,
3176 EL_SP_GRAVITY_ON_PORT_UP,
3177 EL_SP_GRAVITY_ON_PORT_DOWN,
3178 EL_SP_GRAVITY_OFF_PORT_LEFT,
3179 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3180 EL_SP_GRAVITY_OFF_PORT_UP,
3181 EL_SP_GRAVITY_OFF_PORT_DOWN,
3186 static int ep_throwable[] =
3191 static int ep_can_explode[] =
3193 /* same elements as in 'ep_explodes_impact' */
3198 /* same elements as in 'ep_explodes_smashed' */
3204 /* elements that can explode by explosion or by dragonfire */
3208 EL_EM_DYNAMITE_ACTIVE,
3209 EL_DYNABOMB_PLAYER_1_ACTIVE,
3210 EL_DYNABOMB_PLAYER_2_ACTIVE,
3211 EL_DYNABOMB_PLAYER_3_ACTIVE,
3212 EL_DYNABOMB_PLAYER_4_ACTIVE,
3213 EL_DYNABOMB_INCREASE_NUMBER,
3214 EL_DYNABOMB_INCREASE_SIZE,
3215 EL_DYNABOMB_INCREASE_POWER,
3216 EL_SP_DISK_RED_ACTIVE,
3224 /* elements that can explode only by explosion */
3230 static int ep_gravity_reachable[] =
3236 EL_INVISIBLE_SAND_ACTIVE,
3241 EL_SP_PORT_HORIZONTAL,
3242 EL_SP_PORT_VERTICAL,
3244 EL_SP_GRAVITY_PORT_LEFT,
3245 EL_SP_GRAVITY_PORT_RIGHT,
3246 EL_SP_GRAVITY_PORT_UP,
3247 EL_SP_GRAVITY_PORT_DOWN,
3248 EL_SP_GRAVITY_ON_PORT_LEFT,
3249 EL_SP_GRAVITY_ON_PORT_RIGHT,
3250 EL_SP_GRAVITY_ON_PORT_UP,
3251 EL_SP_GRAVITY_ON_PORT_DOWN,
3252 EL_SP_GRAVITY_OFF_PORT_LEFT,
3253 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3254 EL_SP_GRAVITY_OFF_PORT_UP,
3255 EL_SP_GRAVITY_OFF_PORT_DOWN,
3261 static int ep_player[] =
3268 EL_SOKOBAN_FIELD_PLAYER,
3274 static int ep_can_pass_magic_wall[] =
3288 static int ep_can_pass_dc_magic_wall[] =
3304 static int ep_switchable[] =
3308 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3309 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3310 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3311 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3312 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3313 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3314 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3315 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3316 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3317 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3318 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3319 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3320 EL_SWITCHGATE_SWITCH_UP,
3321 EL_SWITCHGATE_SWITCH_DOWN,
3322 EL_DC_SWITCHGATE_SWITCH_UP,
3323 EL_DC_SWITCHGATE_SWITCH_DOWN,
3325 EL_LIGHT_SWITCH_ACTIVE,
3327 EL_DC_TIMEGATE_SWITCH,
3328 EL_BALLOON_SWITCH_LEFT,
3329 EL_BALLOON_SWITCH_RIGHT,
3330 EL_BALLOON_SWITCH_UP,
3331 EL_BALLOON_SWITCH_DOWN,
3332 EL_BALLOON_SWITCH_ANY,
3333 EL_BALLOON_SWITCH_NONE,
3336 EL_EMC_MAGIC_BALL_SWITCH,
3337 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3342 static int ep_bd_element[] =
3376 static int ep_sp_element[] =
3378 /* should always be valid */
3381 /* standard classic Supaplex elements */
3388 EL_SP_HARDWARE_GRAY,
3396 EL_SP_GRAVITY_PORT_RIGHT,
3397 EL_SP_GRAVITY_PORT_DOWN,
3398 EL_SP_GRAVITY_PORT_LEFT,
3399 EL_SP_GRAVITY_PORT_UP,
3404 EL_SP_PORT_VERTICAL,
3405 EL_SP_PORT_HORIZONTAL,
3411 EL_SP_HARDWARE_BASE_1,
3412 EL_SP_HARDWARE_GREEN,
3413 EL_SP_HARDWARE_BLUE,
3415 EL_SP_HARDWARE_YELLOW,
3416 EL_SP_HARDWARE_BASE_2,
3417 EL_SP_HARDWARE_BASE_3,
3418 EL_SP_HARDWARE_BASE_4,
3419 EL_SP_HARDWARE_BASE_5,
3420 EL_SP_HARDWARE_BASE_6,
3424 /* additional elements that appeared in newer Supaplex levels */
3427 /* additional gravity port elements (not switching, but setting gravity) */
3428 EL_SP_GRAVITY_ON_PORT_LEFT,
3429 EL_SP_GRAVITY_ON_PORT_RIGHT,
3430 EL_SP_GRAVITY_ON_PORT_UP,
3431 EL_SP_GRAVITY_ON_PORT_DOWN,
3432 EL_SP_GRAVITY_OFF_PORT_LEFT,
3433 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3434 EL_SP_GRAVITY_OFF_PORT_UP,
3435 EL_SP_GRAVITY_OFF_PORT_DOWN,
3437 /* more than one Murphy in a level results in an inactive clone */
3440 /* runtime Supaplex elements */
3441 EL_SP_DISK_RED_ACTIVE,
3442 EL_SP_TERMINAL_ACTIVE,
3443 EL_SP_BUGGY_BASE_ACTIVATING,
3444 EL_SP_BUGGY_BASE_ACTIVE,
3451 static int ep_sb_element[] =
3456 EL_SOKOBAN_FIELD_EMPTY,
3457 EL_SOKOBAN_FIELD_FULL,
3458 EL_SOKOBAN_FIELD_PLAYER,
3463 EL_INVISIBLE_STEELWALL,
3468 static int ep_gem[] =
3480 static int ep_food_dark_yamyam[] =
3508 static int ep_food_penguin[] =
3522 static int ep_food_pig[] =
3534 static int ep_historic_wall[] =
3545 EL_GATE_1_GRAY_ACTIVE,
3546 EL_GATE_2_GRAY_ACTIVE,
3547 EL_GATE_3_GRAY_ACTIVE,
3548 EL_GATE_4_GRAY_ACTIVE,
3557 EL_EM_GATE_1_GRAY_ACTIVE,
3558 EL_EM_GATE_2_GRAY_ACTIVE,
3559 EL_EM_GATE_3_GRAY_ACTIVE,
3560 EL_EM_GATE_4_GRAY_ACTIVE,
3567 EL_EXPANDABLE_WALL_HORIZONTAL,
3568 EL_EXPANDABLE_WALL_VERTICAL,
3569 EL_EXPANDABLE_WALL_ANY,
3570 EL_EXPANDABLE_WALL_GROWING,
3571 EL_BD_EXPANDABLE_WALL,
3578 EL_SP_HARDWARE_GRAY,
3579 EL_SP_HARDWARE_GREEN,
3580 EL_SP_HARDWARE_BLUE,
3582 EL_SP_HARDWARE_YELLOW,
3583 EL_SP_HARDWARE_BASE_1,
3584 EL_SP_HARDWARE_BASE_2,
3585 EL_SP_HARDWARE_BASE_3,
3586 EL_SP_HARDWARE_BASE_4,
3587 EL_SP_HARDWARE_BASE_5,
3588 EL_SP_HARDWARE_BASE_6,
3590 EL_SP_TERMINAL_ACTIVE,
3593 EL_INVISIBLE_STEELWALL,
3594 EL_INVISIBLE_STEELWALL_ACTIVE,
3596 EL_INVISIBLE_WALL_ACTIVE,
3597 EL_STEELWALL_SLIPPERY,
3614 static int ep_historic_solid[] =
3618 EL_EXPANDABLE_WALL_HORIZONTAL,
3619 EL_EXPANDABLE_WALL_VERTICAL,
3620 EL_EXPANDABLE_WALL_ANY,
3621 EL_BD_EXPANDABLE_WALL,
3634 EL_QUICKSAND_FILLING,
3635 EL_QUICKSAND_EMPTYING,
3637 EL_MAGIC_WALL_ACTIVE,
3638 EL_MAGIC_WALL_EMPTYING,
3639 EL_MAGIC_WALL_FILLING,
3643 EL_BD_MAGIC_WALL_ACTIVE,
3644 EL_BD_MAGIC_WALL_EMPTYING,
3645 EL_BD_MAGIC_WALL_FULL,
3646 EL_BD_MAGIC_WALL_FILLING,
3647 EL_BD_MAGIC_WALL_DEAD,
3656 EL_SP_TERMINAL_ACTIVE,
3660 EL_INVISIBLE_WALL_ACTIVE,
3661 EL_SWITCHGATE_SWITCH_UP,
3662 EL_SWITCHGATE_SWITCH_DOWN,
3664 EL_TIMEGATE_SWITCH_ACTIVE,
3676 /* the following elements are a direct copy of "indestructible" elements,
3677 except "EL_ACID", which is "indestructible", but not "solid"! */
3682 EL_ACID_POOL_TOPLEFT,
3683 EL_ACID_POOL_TOPRIGHT,
3684 EL_ACID_POOL_BOTTOMLEFT,
3685 EL_ACID_POOL_BOTTOM,
3686 EL_ACID_POOL_BOTTOMRIGHT,
3687 EL_SP_HARDWARE_GRAY,
3688 EL_SP_HARDWARE_GREEN,
3689 EL_SP_HARDWARE_BLUE,
3691 EL_SP_HARDWARE_YELLOW,
3692 EL_SP_HARDWARE_BASE_1,
3693 EL_SP_HARDWARE_BASE_2,
3694 EL_SP_HARDWARE_BASE_3,
3695 EL_SP_HARDWARE_BASE_4,
3696 EL_SP_HARDWARE_BASE_5,
3697 EL_SP_HARDWARE_BASE_6,
3698 EL_INVISIBLE_STEELWALL,
3699 EL_INVISIBLE_STEELWALL_ACTIVE,
3700 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3701 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3702 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3703 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3704 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3705 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3706 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3707 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3708 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3709 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3710 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3711 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3713 EL_LIGHT_SWITCH_ACTIVE,
3714 EL_SIGN_EXCLAMATION,
3715 EL_SIGN_RADIOACTIVITY,
3722 EL_SIGN_ENTRY_FORBIDDEN,
3723 EL_SIGN_EMERGENCY_EXIT,
3731 EL_STEEL_EXIT_CLOSED,
3733 EL_STEEL_EXIT_OPENING,
3734 EL_STEEL_EXIT_CLOSING,
3735 EL_EM_STEEL_EXIT_CLOSED,
3736 EL_EM_STEEL_EXIT_OPEN,
3737 EL_EM_STEEL_EXIT_OPENING,
3738 EL_EM_STEEL_EXIT_CLOSING,
3739 EL_DC_STEELWALL_1_LEFT,
3740 EL_DC_STEELWALL_1_RIGHT,
3741 EL_DC_STEELWALL_1_TOP,
3742 EL_DC_STEELWALL_1_BOTTOM,
3743 EL_DC_STEELWALL_1_HORIZONTAL,
3744 EL_DC_STEELWALL_1_VERTICAL,
3745 EL_DC_STEELWALL_1_TOPLEFT,
3746 EL_DC_STEELWALL_1_TOPRIGHT,
3747 EL_DC_STEELWALL_1_BOTTOMLEFT,
3748 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3749 EL_DC_STEELWALL_1_TOPLEFT_2,
3750 EL_DC_STEELWALL_1_TOPRIGHT_2,
3751 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3752 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3753 EL_DC_STEELWALL_2_LEFT,
3754 EL_DC_STEELWALL_2_RIGHT,
3755 EL_DC_STEELWALL_2_TOP,
3756 EL_DC_STEELWALL_2_BOTTOM,
3757 EL_DC_STEELWALL_2_HORIZONTAL,
3758 EL_DC_STEELWALL_2_VERTICAL,
3759 EL_DC_STEELWALL_2_MIDDLE,
3760 EL_DC_STEELWALL_2_SINGLE,
3761 EL_STEELWALL_SLIPPERY,
3775 EL_GATE_1_GRAY_ACTIVE,
3776 EL_GATE_2_GRAY_ACTIVE,
3777 EL_GATE_3_GRAY_ACTIVE,
3778 EL_GATE_4_GRAY_ACTIVE,
3787 EL_EM_GATE_1_GRAY_ACTIVE,
3788 EL_EM_GATE_2_GRAY_ACTIVE,
3789 EL_EM_GATE_3_GRAY_ACTIVE,
3790 EL_EM_GATE_4_GRAY_ACTIVE,
3799 EL_EMC_GATE_5_GRAY_ACTIVE,
3800 EL_EMC_GATE_6_GRAY_ACTIVE,
3801 EL_EMC_GATE_7_GRAY_ACTIVE,
3802 EL_EMC_GATE_8_GRAY_ACTIVE,
3804 EL_DC_GATE_WHITE_GRAY,
3805 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3806 EL_DC_GATE_FAKE_GRAY,
3808 EL_SWITCHGATE_OPENING,
3809 EL_SWITCHGATE_CLOSED,
3810 EL_SWITCHGATE_CLOSING,
3811 EL_DC_SWITCHGATE_SWITCH_UP,
3812 EL_DC_SWITCHGATE_SWITCH_DOWN,
3814 EL_TIMEGATE_OPENING,
3816 EL_TIMEGATE_CLOSING,
3817 EL_DC_TIMEGATE_SWITCH,
3818 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3822 EL_TUBE_VERTICAL_LEFT,
3823 EL_TUBE_VERTICAL_RIGHT,
3824 EL_TUBE_HORIZONTAL_UP,
3825 EL_TUBE_HORIZONTAL_DOWN,
3830 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3831 EL_EXPANDABLE_STEELWALL_VERTICAL,
3832 EL_EXPANDABLE_STEELWALL_ANY,
3837 static int ep_classic_enemy[] =
3854 static int ep_belt[] =
3856 EL_CONVEYOR_BELT_1_LEFT,
3857 EL_CONVEYOR_BELT_1_MIDDLE,
3858 EL_CONVEYOR_BELT_1_RIGHT,
3859 EL_CONVEYOR_BELT_2_LEFT,
3860 EL_CONVEYOR_BELT_2_MIDDLE,
3861 EL_CONVEYOR_BELT_2_RIGHT,
3862 EL_CONVEYOR_BELT_3_LEFT,
3863 EL_CONVEYOR_BELT_3_MIDDLE,
3864 EL_CONVEYOR_BELT_3_RIGHT,
3865 EL_CONVEYOR_BELT_4_LEFT,
3866 EL_CONVEYOR_BELT_4_MIDDLE,
3867 EL_CONVEYOR_BELT_4_RIGHT,
3872 static int ep_belt_active[] =
3874 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3875 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3876 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3877 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3878 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3879 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3880 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3881 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3882 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3883 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3884 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3885 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3890 static int ep_belt_switch[] =
3892 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3893 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3894 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3895 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3896 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3897 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3898 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3899 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3900 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3901 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3902 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3903 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3908 static int ep_tube[] =
3915 EL_TUBE_HORIZONTAL_UP,
3916 EL_TUBE_HORIZONTAL_DOWN,
3918 EL_TUBE_VERTICAL_LEFT,
3919 EL_TUBE_VERTICAL_RIGHT,
3925 static int ep_acid_pool[] =
3927 EL_ACID_POOL_TOPLEFT,
3928 EL_ACID_POOL_TOPRIGHT,
3929 EL_ACID_POOL_BOTTOMLEFT,
3930 EL_ACID_POOL_BOTTOM,
3931 EL_ACID_POOL_BOTTOMRIGHT,
3936 static int ep_keygate[] =
3946 EL_GATE_1_GRAY_ACTIVE,
3947 EL_GATE_2_GRAY_ACTIVE,
3948 EL_GATE_3_GRAY_ACTIVE,
3949 EL_GATE_4_GRAY_ACTIVE,
3958 EL_EM_GATE_1_GRAY_ACTIVE,
3959 EL_EM_GATE_2_GRAY_ACTIVE,
3960 EL_EM_GATE_3_GRAY_ACTIVE,
3961 EL_EM_GATE_4_GRAY_ACTIVE,
3970 EL_EMC_GATE_5_GRAY_ACTIVE,
3971 EL_EMC_GATE_6_GRAY_ACTIVE,
3972 EL_EMC_GATE_7_GRAY_ACTIVE,
3973 EL_EMC_GATE_8_GRAY_ACTIVE,
3975 EL_DC_GATE_WHITE_GRAY,
3976 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3981 static int ep_amoeboid[] =
3993 static int ep_amoebalive[] =
4004 static int ep_has_editor_content[] =
4010 EL_SOKOBAN_FIELD_PLAYER,
4027 static int ep_can_turn_each_move[] =
4029 /* !!! do something with this one !!! */
4033 static int ep_can_grow[] =
4047 static int ep_active_bomb[] =
4050 EL_EM_DYNAMITE_ACTIVE,
4051 EL_DYNABOMB_PLAYER_1_ACTIVE,
4052 EL_DYNABOMB_PLAYER_2_ACTIVE,
4053 EL_DYNABOMB_PLAYER_3_ACTIVE,
4054 EL_DYNABOMB_PLAYER_4_ACTIVE,
4055 EL_SP_DISK_RED_ACTIVE,
4060 static int ep_inactive[] =
4070 EL_QUICKSAND_FAST_EMPTY,
4093 EL_GATE_1_GRAY_ACTIVE,
4094 EL_GATE_2_GRAY_ACTIVE,
4095 EL_GATE_3_GRAY_ACTIVE,
4096 EL_GATE_4_GRAY_ACTIVE,
4105 EL_EM_GATE_1_GRAY_ACTIVE,
4106 EL_EM_GATE_2_GRAY_ACTIVE,
4107 EL_EM_GATE_3_GRAY_ACTIVE,
4108 EL_EM_GATE_4_GRAY_ACTIVE,
4117 EL_EMC_GATE_5_GRAY_ACTIVE,
4118 EL_EMC_GATE_6_GRAY_ACTIVE,
4119 EL_EMC_GATE_7_GRAY_ACTIVE,
4120 EL_EMC_GATE_8_GRAY_ACTIVE,
4122 EL_DC_GATE_WHITE_GRAY,
4123 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4124 EL_DC_GATE_FAKE_GRAY,
4127 EL_INVISIBLE_STEELWALL,
4135 EL_WALL_EMERALD_YELLOW,
4136 EL_DYNABOMB_INCREASE_NUMBER,
4137 EL_DYNABOMB_INCREASE_SIZE,
4138 EL_DYNABOMB_INCREASE_POWER,
4142 EL_SOKOBAN_FIELD_EMPTY,
4143 EL_SOKOBAN_FIELD_FULL,
4144 EL_WALL_EMERALD_RED,
4145 EL_WALL_EMERALD_PURPLE,
4146 EL_ACID_POOL_TOPLEFT,
4147 EL_ACID_POOL_TOPRIGHT,
4148 EL_ACID_POOL_BOTTOMLEFT,
4149 EL_ACID_POOL_BOTTOM,
4150 EL_ACID_POOL_BOTTOMRIGHT,
4154 EL_BD_MAGIC_WALL_DEAD,
4156 EL_DC_MAGIC_WALL_DEAD,
4157 EL_AMOEBA_TO_DIAMOND,
4165 EL_SP_GRAVITY_PORT_RIGHT,
4166 EL_SP_GRAVITY_PORT_DOWN,
4167 EL_SP_GRAVITY_PORT_LEFT,
4168 EL_SP_GRAVITY_PORT_UP,
4169 EL_SP_PORT_HORIZONTAL,
4170 EL_SP_PORT_VERTICAL,
4181 EL_SP_HARDWARE_GRAY,
4182 EL_SP_HARDWARE_GREEN,
4183 EL_SP_HARDWARE_BLUE,
4185 EL_SP_HARDWARE_YELLOW,
4186 EL_SP_HARDWARE_BASE_1,
4187 EL_SP_HARDWARE_BASE_2,
4188 EL_SP_HARDWARE_BASE_3,
4189 EL_SP_HARDWARE_BASE_4,
4190 EL_SP_HARDWARE_BASE_5,
4191 EL_SP_HARDWARE_BASE_6,
4192 EL_SP_GRAVITY_ON_PORT_LEFT,
4193 EL_SP_GRAVITY_ON_PORT_RIGHT,
4194 EL_SP_GRAVITY_ON_PORT_UP,
4195 EL_SP_GRAVITY_ON_PORT_DOWN,
4196 EL_SP_GRAVITY_OFF_PORT_LEFT,
4197 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4198 EL_SP_GRAVITY_OFF_PORT_UP,
4199 EL_SP_GRAVITY_OFF_PORT_DOWN,
4200 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4201 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4202 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4203 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4204 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4205 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4206 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4207 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4208 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4209 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4210 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4211 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4212 EL_SIGN_EXCLAMATION,
4213 EL_SIGN_RADIOACTIVITY,
4220 EL_SIGN_ENTRY_FORBIDDEN,
4221 EL_SIGN_EMERGENCY_EXIT,
4229 EL_DC_STEELWALL_1_LEFT,
4230 EL_DC_STEELWALL_1_RIGHT,
4231 EL_DC_STEELWALL_1_TOP,
4232 EL_DC_STEELWALL_1_BOTTOM,
4233 EL_DC_STEELWALL_1_HORIZONTAL,
4234 EL_DC_STEELWALL_1_VERTICAL,
4235 EL_DC_STEELWALL_1_TOPLEFT,
4236 EL_DC_STEELWALL_1_TOPRIGHT,
4237 EL_DC_STEELWALL_1_BOTTOMLEFT,
4238 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4239 EL_DC_STEELWALL_1_TOPLEFT_2,
4240 EL_DC_STEELWALL_1_TOPRIGHT_2,
4241 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4242 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4243 EL_DC_STEELWALL_2_LEFT,
4244 EL_DC_STEELWALL_2_RIGHT,
4245 EL_DC_STEELWALL_2_TOP,
4246 EL_DC_STEELWALL_2_BOTTOM,
4247 EL_DC_STEELWALL_2_HORIZONTAL,
4248 EL_DC_STEELWALL_2_VERTICAL,
4249 EL_DC_STEELWALL_2_MIDDLE,
4250 EL_DC_STEELWALL_2_SINGLE,
4251 EL_STEELWALL_SLIPPERY,
4256 EL_EMC_WALL_SLIPPERY_1,
4257 EL_EMC_WALL_SLIPPERY_2,
4258 EL_EMC_WALL_SLIPPERY_3,
4259 EL_EMC_WALL_SLIPPERY_4,
4280 static int ep_em_slippery_wall[] =
4285 static int ep_gfx_crumbled[] =
4296 static int ep_editor_cascade_active[] =
4298 EL_INTERNAL_CASCADE_BD_ACTIVE,
4299 EL_INTERNAL_CASCADE_EM_ACTIVE,
4300 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4301 EL_INTERNAL_CASCADE_RND_ACTIVE,
4302 EL_INTERNAL_CASCADE_SB_ACTIVE,
4303 EL_INTERNAL_CASCADE_SP_ACTIVE,
4304 EL_INTERNAL_CASCADE_DC_ACTIVE,
4305 EL_INTERNAL_CASCADE_DX_ACTIVE,
4306 EL_INTERNAL_CASCADE_MM_ACTIVE,
4307 EL_INTERNAL_CASCADE_DF_ACTIVE,
4308 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4309 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4310 EL_INTERNAL_CASCADE_CE_ACTIVE,
4311 EL_INTERNAL_CASCADE_GE_ACTIVE,
4312 EL_INTERNAL_CASCADE_REF_ACTIVE,
4313 EL_INTERNAL_CASCADE_USER_ACTIVE,
4314 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4319 static int ep_editor_cascade_inactive[] =
4321 EL_INTERNAL_CASCADE_BD,
4322 EL_INTERNAL_CASCADE_EM,
4323 EL_INTERNAL_CASCADE_EMC,
4324 EL_INTERNAL_CASCADE_RND,
4325 EL_INTERNAL_CASCADE_SB,
4326 EL_INTERNAL_CASCADE_SP,
4327 EL_INTERNAL_CASCADE_DC,
4328 EL_INTERNAL_CASCADE_DX,
4329 EL_INTERNAL_CASCADE_MM,
4330 EL_INTERNAL_CASCADE_DF,
4331 EL_INTERNAL_CASCADE_CHARS,
4332 EL_INTERNAL_CASCADE_STEEL_CHARS,
4333 EL_INTERNAL_CASCADE_CE,
4334 EL_INTERNAL_CASCADE_GE,
4335 EL_INTERNAL_CASCADE_REF,
4336 EL_INTERNAL_CASCADE_USER,
4337 EL_INTERNAL_CASCADE_DYNAMIC,
4342 static int ep_obsolete[] =
4346 EL_EM_KEY_1_FILE_OBSOLETE,
4347 EL_EM_KEY_2_FILE_OBSOLETE,
4348 EL_EM_KEY_3_FILE_OBSOLETE,
4349 EL_EM_KEY_4_FILE_OBSOLETE,
4350 EL_ENVELOPE_OBSOLETE,
4359 } element_properties[] =
4361 { ep_diggable, EP_DIGGABLE },
4362 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4363 { ep_dont_run_into, EP_DONT_RUN_INTO },
4364 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4365 { ep_dont_touch, EP_DONT_TOUCH },
4366 { ep_indestructible, EP_INDESTRUCTIBLE },
4367 { ep_slippery, EP_SLIPPERY },
4368 { ep_can_change, EP_CAN_CHANGE },
4369 { ep_can_move, EP_CAN_MOVE },
4370 { ep_can_fall, EP_CAN_FALL },
4371 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4372 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4373 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4374 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4375 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4376 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4377 { ep_walkable_over, EP_WALKABLE_OVER },
4378 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4379 { ep_walkable_under, EP_WALKABLE_UNDER },
4380 { ep_passable_over, EP_PASSABLE_OVER },
4381 { ep_passable_inside, EP_PASSABLE_INSIDE },
4382 { ep_passable_under, EP_PASSABLE_UNDER },
4383 { ep_droppable, EP_DROPPABLE },
4384 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4385 { ep_pushable, EP_PUSHABLE },
4386 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4387 { ep_protected, EP_PROTECTED },
4388 { ep_throwable, EP_THROWABLE },
4389 { ep_can_explode, EP_CAN_EXPLODE },
4390 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4392 { ep_player, EP_PLAYER },
4393 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4394 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4395 { ep_switchable, EP_SWITCHABLE },
4396 { ep_bd_element, EP_BD_ELEMENT },
4397 { ep_sp_element, EP_SP_ELEMENT },
4398 { ep_sb_element, EP_SB_ELEMENT },
4400 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4401 { ep_food_penguin, EP_FOOD_PENGUIN },
4402 { ep_food_pig, EP_FOOD_PIG },
4403 { ep_historic_wall, EP_HISTORIC_WALL },
4404 { ep_historic_solid, EP_HISTORIC_SOLID },
4405 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4406 { ep_belt, EP_BELT },
4407 { ep_belt_active, EP_BELT_ACTIVE },
4408 { ep_belt_switch, EP_BELT_SWITCH },
4409 { ep_tube, EP_TUBE },
4410 { ep_acid_pool, EP_ACID_POOL },
4411 { ep_keygate, EP_KEYGATE },
4412 { ep_amoeboid, EP_AMOEBOID },
4413 { ep_amoebalive, EP_AMOEBALIVE },
4414 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4415 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4416 { ep_can_grow, EP_CAN_GROW },
4417 { ep_active_bomb, EP_ACTIVE_BOMB },
4418 { ep_inactive, EP_INACTIVE },
4420 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4422 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4424 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4425 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4427 { ep_obsolete, EP_OBSOLETE },
4434 /* always start with reliable default values (element has no properties) */
4435 /* (but never initialize clipboard elements after the very first time) */
4436 /* (to be able to use clipboard elements between several levels) */
4437 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4438 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4439 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4440 SET_PROPERTY(i, j, FALSE);
4442 /* set all base element properties from above array definitions */
4443 for (i = 0; element_properties[i].elements != NULL; i++)
4444 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4445 SET_PROPERTY((element_properties[i].elements)[j],
4446 element_properties[i].property, TRUE);
4448 /* copy properties to some elements that are only stored in level file */
4449 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4450 for (j = 0; copy_properties[j][0] != -1; j++)
4451 if (HAS_PROPERTY(copy_properties[j][0], i))
4452 for (k = 1; k <= 4; k++)
4453 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4455 /* set static element properties that are not listed in array definitions */
4456 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4457 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4459 clipboard_elements_initialized = TRUE;
4462 void InitElementPropertiesEngine(int engine_version)
4464 static int no_wall_properties[] =
4467 EP_COLLECTIBLE_ONLY,
4469 EP_DONT_COLLIDE_WITH,
4472 EP_CAN_SMASH_PLAYER,
4473 EP_CAN_SMASH_ENEMIES,
4474 EP_CAN_SMASH_EVERYTHING,
4479 EP_FOOD_DARK_YAMYAM,
4495 /* important: after initialization in InitElementPropertiesStatic(), the
4496 elements are not again initialized to a default value; therefore all
4497 changes have to make sure that they leave the element with a defined
4498 property (which means that conditional property changes must be set to
4499 a reliable default value before) */
4501 /* resolve group elements */
4502 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4503 ResolveGroupElement(EL_GROUP_START + i);
4505 /* set all special, combined or engine dependent element properties */
4506 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4508 /* do not change (already initialized) clipboard elements here */
4509 if (IS_CLIPBOARD_ELEMENT(i))
4512 /* ---------- INACTIVE ------------------------------------------------- */
4513 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4514 i <= EL_CHAR_END) ||
4515 (i >= EL_STEEL_CHAR_START &&
4516 i <= EL_STEEL_CHAR_END)));
4518 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4519 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4520 IS_WALKABLE_INSIDE(i) ||
4521 IS_WALKABLE_UNDER(i)));
4523 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4524 IS_PASSABLE_INSIDE(i) ||
4525 IS_PASSABLE_UNDER(i)));
4527 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4528 IS_PASSABLE_OVER(i)));
4530 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4531 IS_PASSABLE_INSIDE(i)));
4533 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4534 IS_PASSABLE_UNDER(i)));
4536 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4539 /* ---------- COLLECTIBLE ---------------------------------------------- */
4540 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4544 /* ---------- SNAPPABLE ------------------------------------------------ */
4545 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4546 IS_COLLECTIBLE(i) ||
4550 /* ---------- WALL ----------------------------------------------------- */
4551 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4553 for (j = 0; no_wall_properties[j] != -1; j++)
4554 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4555 i >= EL_FIRST_RUNTIME_UNREAL)
4556 SET_PROPERTY(i, EP_WALL, FALSE);
4558 if (IS_HISTORIC_WALL(i))
4559 SET_PROPERTY(i, EP_WALL, TRUE);
4561 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4562 if (engine_version < VERSION_IDENT(2,2,0,0))
4563 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4565 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4567 !IS_COLLECTIBLE(i)));
4569 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4570 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4571 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4573 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4576 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4578 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4579 else if (engine_version < VERSION_IDENT(2,2,0,0))
4580 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4582 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4586 if (IS_CUSTOM_ELEMENT(i))
4588 /* these are additional properties which are initially false when set */
4590 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4592 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4593 if (DONT_COLLIDE_WITH(i))
4594 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4596 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4597 if (CAN_SMASH_EVERYTHING(i))
4598 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4599 if (CAN_SMASH_ENEMIES(i))
4600 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4603 /* ---------- CAN_SMASH ------------------------------------------------ */
4604 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4605 CAN_SMASH_ENEMIES(i) ||
4606 CAN_SMASH_EVERYTHING(i)));
4608 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4609 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4610 EXPLODES_BY_FIRE(i)));
4612 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4613 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4614 EXPLODES_SMASHED(i)));
4616 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4617 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4618 EXPLODES_IMPACT(i)));
4620 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4621 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4623 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4624 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4625 i == EL_BLACK_ORB));
4627 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4628 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4630 IS_CUSTOM_ELEMENT(i)));
4632 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4633 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4634 i == EL_SP_ELECTRON));
4636 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4637 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4638 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4639 getMoveIntoAcidProperty(&level, i));
4641 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4642 if (MAYBE_DONT_COLLIDE_WITH(i))
4643 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4644 getDontCollideWithProperty(&level, i));
4646 /* ---------- SP_PORT -------------------------------------------------- */
4647 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4648 IS_PASSABLE_INSIDE(i)));
4650 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4651 for (j = 0; j < level.num_android_clone_elements; j++)
4652 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4654 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4656 /* ---------- CAN_CHANGE ----------------------------------------------- */
4657 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4658 for (j = 0; j < element_info[i].num_change_pages; j++)
4659 if (element_info[i].change_page[j].can_change)
4660 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4662 /* ---------- HAS_ACTION ----------------------------------------------- */
4663 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4664 for (j = 0; j < element_info[i].num_change_pages; j++)
4665 if (element_info[i].change_page[j].has_action)
4666 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4668 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4669 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4672 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4673 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4674 element_info[i].crumbled[ACTION_DEFAULT] !=
4675 element_info[i].graphic[ACTION_DEFAULT]);
4677 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4678 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4679 IS_EDITOR_CASCADE_INACTIVE(i)));
4682 /* dynamically adjust element properties according to game engine version */
4684 static int ep_em_slippery_wall[] =
4689 EL_EXPANDABLE_WALL_HORIZONTAL,
4690 EL_EXPANDABLE_WALL_VERTICAL,
4691 EL_EXPANDABLE_WALL_ANY,
4692 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4693 EL_EXPANDABLE_STEELWALL_VERTICAL,
4694 EL_EXPANDABLE_STEELWALL_ANY,
4695 EL_EXPANDABLE_STEELWALL_GROWING,
4699 static int ep_em_explodes_by_fire[] =
4702 EL_EM_DYNAMITE_ACTIVE,
4707 /* special EM style gems behaviour */
4708 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4709 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4710 level.em_slippery_gems);
4712 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4713 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4714 (level.em_slippery_gems &&
4715 engine_version > VERSION_IDENT(2,0,1,0)));
4717 /* special EM style explosion behaviour regarding chain reactions */
4718 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4719 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4720 level.em_explodes_by_fire);
4723 /* this is needed because some graphics depend on element properties */
4724 if (game_status == GAME_MODE_PLAYING)
4725 InitElementGraphicInfo();
4728 void InitElementPropertiesGfxElement(void)
4732 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4734 struct ElementInfo *ei = &element_info[i];
4736 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4740 static void InitGlobal(void)
4745 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4747 /* check if element_name_info entry defined for each element in "main.h" */
4748 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4749 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4751 element_info[i].token_name = element_name_info[i].token_name;
4752 element_info[i].class_name = element_name_info[i].class_name;
4753 element_info[i].editor_description= element_name_info[i].editor_description;
4756 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4758 /* check if global_anim_name_info defined for each entry in "main.h" */
4759 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4760 global_anim_name_info[i].token_name == NULL)
4761 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4763 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4766 /* create hash from image config list */
4767 image_config_hash = newSetupFileHash();
4768 for (i = 0; image_config[i].token != NULL; i++)
4769 setHashEntry(image_config_hash,
4770 image_config[i].token,
4771 image_config[i].value);
4773 /* create hash from element token list */
4774 element_token_hash = newSetupFileHash();
4775 for (i = 0; element_name_info[i].token_name != NULL; i++)
4776 setHashEntry(element_token_hash,
4777 element_name_info[i].token_name,
4780 /* create hash from graphic token list */
4781 graphic_token_hash = newSetupFileHash();
4782 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4783 if (strSuffix(image_config[i].value, ".png") ||
4784 strSuffix(image_config[i].value, ".pcx") ||
4785 strSuffix(image_config[i].value, ".wav") ||
4786 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4787 setHashEntry(graphic_token_hash,
4788 image_config[i].token,
4789 int2str(graphic++, 0));
4791 /* create hash from font token list */
4792 font_token_hash = newSetupFileHash();
4793 for (i = 0; font_info[i].token_name != NULL; i++)
4794 setHashEntry(font_token_hash,
4795 font_info[i].token_name,
4798 /* set default filenames for all cloned graphics in static configuration */
4799 for (i = 0; image_config[i].token != NULL; i++)
4801 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4803 char *token = image_config[i].token;
4804 char *token_clone_from = getStringCat2(token, ".clone_from");
4805 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4807 if (token_cloned != NULL)
4809 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4811 if (value_cloned != NULL)
4813 /* set default filename in static configuration */
4814 image_config[i].value = value_cloned;
4816 /* set default filename in image config hash */
4817 setHashEntry(image_config_hash, token, value_cloned);
4821 free(token_clone_from);
4825 /* always start with reliable default values (all elements) */
4826 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4827 ActiveElement[i] = i;
4829 /* now add all entries that have an active state (active elements) */
4830 for (i = 0; element_with_active_state[i].element != -1; i++)
4832 int element = element_with_active_state[i].element;
4833 int element_active = element_with_active_state[i].element_active;
4835 ActiveElement[element] = element_active;
4838 /* always start with reliable default values (all buttons) */
4839 for (i = 0; i < NUM_IMAGE_FILES; i++)
4840 ActiveButton[i] = i;
4842 /* now add all entries that have an active state (active buttons) */
4843 for (i = 0; button_with_active_state[i].button != -1; i++)
4845 int button = button_with_active_state[i].button;
4846 int button_active = button_with_active_state[i].button_active;
4848 ActiveButton[button] = button_active;
4851 /* always start with reliable default values (all fonts) */
4852 for (i = 0; i < NUM_FONTS; i++)
4855 /* now add all entries that have an active state (active fonts) */
4856 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4858 int font = font_with_active_state[i].font_nr;
4859 int font_active = font_with_active_state[i].font_nr_active;
4861 ActiveFont[font] = font_active;
4864 global.autoplay_leveldir = NULL;
4865 global.convert_leveldir = NULL;
4866 global.create_images_dir = NULL;
4868 global.frames_per_second = 0;
4869 global.show_frames_per_second = FALSE;
4871 global.border_status = GAME_MODE_LOADING;
4872 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4874 global.use_envelope_request = FALSE;
4877 static void Execute_Command(char *command)
4881 if (strEqual(command, "print graphicsinfo.conf"))
4883 Print("# You can configure additional/alternative image files here.\n");
4884 Print("# (The entries below are default and therefore commented out.)\n");
4886 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4888 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4891 for (i = 0; image_config[i].token != NULL; i++)
4892 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4893 image_config[i].value));
4897 else if (strEqual(command, "print soundsinfo.conf"))
4899 Print("# You can configure additional/alternative sound files here.\n");
4900 Print("# (The entries below are default and therefore commented out.)\n");
4902 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4904 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4907 for (i = 0; sound_config[i].token != NULL; i++)
4908 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4909 sound_config[i].value));
4913 else if (strEqual(command, "print musicinfo.conf"))
4915 Print("# You can configure additional/alternative music files here.\n");
4916 Print("# (The entries below are default and therefore commented out.)\n");
4918 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4920 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4923 for (i = 0; music_config[i].token != NULL; i++)
4924 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4925 music_config[i].value));
4929 else if (strEqual(command, "print editorsetup.conf"))
4931 Print("# You can configure your personal editor element list here.\n");
4932 Print("# (The entries below are default and therefore commented out.)\n");
4935 /* this is needed to be able to check element list for cascade elements */
4936 InitElementPropertiesStatic();
4937 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4939 PrintEditorElementList();
4943 else if (strEqual(command, "print helpanim.conf"))
4945 Print("# You can configure different element help animations here.\n");
4946 Print("# (The entries below are default and therefore commented out.)\n");
4949 for (i = 0; helpanim_config[i].token != NULL; i++)
4951 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4952 helpanim_config[i].value));
4954 if (strEqual(helpanim_config[i].token, "end"))
4960 else if (strEqual(command, "print helptext.conf"))
4962 Print("# You can configure different element help text here.\n");
4963 Print("# (The entries below are default and therefore commented out.)\n");
4966 for (i = 0; helptext_config[i].token != NULL; i++)
4967 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4968 helptext_config[i].value));
4972 else if (strPrefix(command, "dump level "))
4974 char *filename = &command[11];
4976 if (!fileExists(filename))
4977 Error(ERR_EXIT, "cannot open file '%s'", filename);
4979 LoadLevelFromFilename(&level, filename);
4984 else if (strPrefix(command, "dump tape "))
4986 char *filename = &command[10];
4988 if (!fileExists(filename))
4989 Error(ERR_EXIT, "cannot open file '%s'", filename);
4991 LoadTapeFromFilename(filename);
4996 else if (strPrefix(command, "autotest ") ||
4997 strPrefix(command, "autoplay ") ||
4998 strPrefix(command, "autoffwd ") ||
4999 strPrefix(command, "autowarp "))
5001 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5003 global.autoplay_mode =
5004 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5005 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5006 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5007 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5008 AUTOPLAY_MODE_NONE);
5010 while (*str_ptr != '\0') /* continue parsing string */
5012 /* cut leading whitespace from string, replace it by string terminator */
5013 while (*str_ptr == ' ' || *str_ptr == '\t')
5016 if (*str_ptr == '\0') /* end of string reached */
5019 if (global.autoplay_leveldir == NULL) /* read level set string */
5021 global.autoplay_leveldir = str_ptr;
5022 global.autoplay_all = TRUE; /* default: play all tapes */
5024 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5025 global.autoplay_level[i] = FALSE;
5027 else /* read level number string */
5029 int level_nr = atoi(str_ptr); /* get level_nr value */
5031 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5032 global.autoplay_level[level_nr] = TRUE;
5034 global.autoplay_all = FALSE;
5037 /* advance string pointer to the next whitespace (or end of string) */
5038 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5042 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5043 program.headless = TRUE;
5045 else if (strPrefix(command, "convert "))
5047 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5048 char *str_ptr = strchr(str_copy, ' ');
5050 global.convert_leveldir = str_copy;
5051 global.convert_level_nr = -1;
5053 if (str_ptr != NULL) /* level number follows */
5055 *str_ptr++ = '\0'; /* terminate leveldir string */
5056 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5059 program.headless = TRUE;
5061 else if (strPrefix(command, "create images "))
5063 global.create_images_dir = getStringCopy(&command[14]);
5065 if (access(global.create_images_dir, W_OK) != 0)
5066 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5067 global.create_images_dir);
5069 else if (strPrefix(command, "create CE image "))
5071 CreateCustomElementImages(&command[16]);
5077 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5080 /* disable networking if any valid command was recognized */
5081 options.network = setup.network_mode = FALSE;
5084 static void InitSetup(void)
5086 LoadSetup(); /* global setup info */
5087 LoadSetup_AutoSetup(); /* global auto setup info */
5089 /* set some options from setup file */
5091 if (setup.options.verbose)
5092 options.verbose = TRUE;
5094 if (setup.debug.show_frames_per_second)
5095 global.show_frames_per_second = TRUE;
5098 static void InitGameInfo(void)
5100 game.restart_level = FALSE;
5101 game.restart_game_message = NULL;
5104 static void InitPlayerInfo(void)
5108 /* choose default local player */
5109 local_player = &stored_player[0];
5111 for (i = 0; i < MAX_PLAYERS; i++)
5113 stored_player[i].connected_locally = FALSE;
5114 stored_player[i].connected_network = FALSE;
5117 local_player->connected_locally = TRUE;
5120 static void InitArtworkInfo(void)
5125 static char *get_string_in_brackets(char *string)
5127 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5129 sprintf(string_in_brackets, "[%s]", string);
5131 return string_in_brackets;
5134 static char *get_level_id_suffix(int id_nr)
5136 char *id_suffix = checked_malloc(1 + 3 + 1);
5138 if (id_nr < 0 || id_nr > 999)
5141 sprintf(id_suffix, ".%03d", id_nr);
5146 static void InitArtworkConfig(void)
5148 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5150 NUM_GLOBAL_ANIM_TOKENS + 1];
5151 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5152 NUM_GLOBAL_ANIM_TOKENS + 1];
5153 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5154 NUM_GLOBAL_ANIM_TOKENS + 1];
5155 static char *action_id_suffix[NUM_ACTIONS + 1];
5156 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5157 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5158 static char *level_id_suffix[MAX_LEVELS + 1];
5159 static char *dummy[1] = { NULL };
5160 static char *ignore_generic_tokens[] =
5165 "program_copyright",
5170 static char **ignore_image_tokens;
5171 static char **ignore_sound_tokens;
5172 static char **ignore_music_tokens;
5173 int num_ignore_generic_tokens;
5174 int num_ignore_image_tokens;
5175 int num_ignore_sound_tokens;
5176 int num_ignore_music_tokens;
5179 /* dynamically determine list of generic tokens to be ignored */
5180 num_ignore_generic_tokens = 0;
5181 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5182 num_ignore_generic_tokens++;
5184 /* dynamically determine list of image tokens to be ignored */
5185 num_ignore_image_tokens = num_ignore_generic_tokens;
5186 for (i = 0; image_config_vars[i].token != NULL; i++)
5187 num_ignore_image_tokens++;
5188 ignore_image_tokens =
5189 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5190 for (i = 0; i < num_ignore_generic_tokens; i++)
5191 ignore_image_tokens[i] = ignore_generic_tokens[i];
5192 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5193 ignore_image_tokens[num_ignore_generic_tokens + i] =
5194 image_config_vars[i].token;
5195 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5197 /* dynamically determine list of sound tokens to be ignored */
5198 num_ignore_sound_tokens = num_ignore_generic_tokens;
5199 ignore_sound_tokens =
5200 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5201 for (i = 0; i < num_ignore_generic_tokens; i++)
5202 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5203 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5205 /* dynamically determine list of music tokens to be ignored */
5206 num_ignore_music_tokens = num_ignore_generic_tokens;
5207 ignore_music_tokens =
5208 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5209 for (i = 0; i < num_ignore_generic_tokens; i++)
5210 ignore_music_tokens[i] = ignore_generic_tokens[i];
5211 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5213 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5214 image_id_prefix[i] = element_info[i].token_name;
5215 for (i = 0; i < NUM_FONTS; i++)
5216 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5217 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5218 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5219 global_anim_info[i].token_name;
5220 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5222 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5223 sound_id_prefix[i] = element_info[i].token_name;
5224 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5225 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5226 get_string_in_brackets(element_info[i].class_name);
5227 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5228 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5229 global_anim_info[i].token_name;
5230 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5232 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5233 music_id_prefix[i] = music_prefix_info[i].prefix;
5234 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5235 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5236 global_anim_info[i].token_name;
5237 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5239 for (i = 0; i < NUM_ACTIONS; i++)
5240 action_id_suffix[i] = element_action_info[i].suffix;
5241 action_id_suffix[NUM_ACTIONS] = NULL;
5243 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5244 direction_id_suffix[i] = element_direction_info[i].suffix;
5245 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5247 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5248 special_id_suffix[i] = special_suffix_info[i].suffix;
5249 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5251 for (i = 0; i < MAX_LEVELS; i++)
5252 level_id_suffix[i] = get_level_id_suffix(i);
5253 level_id_suffix[MAX_LEVELS] = NULL;
5255 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5256 image_id_prefix, action_id_suffix, direction_id_suffix,
5257 special_id_suffix, ignore_image_tokens);
5258 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5259 sound_id_prefix, action_id_suffix, dummy,
5260 special_id_suffix, ignore_sound_tokens);
5261 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5262 music_id_prefix, action_id_suffix, special_id_suffix,
5263 level_id_suffix, ignore_music_tokens);
5266 static void InitMixer(void)
5273 static void InitVideoOverlay(void)
5275 // if virtual buttons are not loaded from setup file, repeat initializing
5276 // virtual buttons grid with default values now that video is initialized
5277 if (!setup.touch.grid_initialized)
5280 InitTileCursorInfo();
5284 void InitGfxBuffers(void)
5286 static int win_xsize_last = -1;
5287 static int win_ysize_last = -1;
5289 /* create additional image buffers for double-buffering and cross-fading */
5291 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5293 /* used to temporarily store the backbuffer -- only re-create if changed */
5294 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5295 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5297 win_xsize_last = WIN_XSIZE;
5298 win_ysize_last = WIN_YSIZE;
5301 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5302 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5303 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5304 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5306 /* initialize screen properties */
5307 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5308 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5310 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5311 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5312 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5313 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5314 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5315 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5317 /* required if door size definitions have changed */
5318 InitGraphicCompatibilityInfo_Doors();
5320 InitGfxBuffers_EM();
5321 InitGfxBuffers_SP();
5324 static void InitGfx(void)
5326 struct GraphicInfo *graphic_info_last = graphic_info;
5327 char *filename_font_initial = NULL;
5328 char *filename_anim_initial = NULL;
5329 Bitmap *bitmap_font_initial = NULL;
5333 /* determine settings for initial font (for displaying startup messages) */
5334 for (i = 0; image_config[i].token != NULL; i++)
5336 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5338 char font_token[128];
5341 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5342 len_font_token = strlen(font_token);
5344 if (strEqual(image_config[i].token, font_token))
5345 filename_font_initial = image_config[i].value;
5346 else if (strlen(image_config[i].token) > len_font_token &&
5347 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5349 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5350 font_initial[j].src_x = atoi(image_config[i].value);
5351 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5352 font_initial[j].src_y = atoi(image_config[i].value);
5353 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5354 font_initial[j].width = atoi(image_config[i].value);
5355 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5356 font_initial[j].height = atoi(image_config[i].value);
5361 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5363 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5364 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5367 if (filename_font_initial == NULL) /* should not happen */
5368 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5371 InitGfxCustomArtworkInfo();
5372 InitGfxOtherSettings();
5374 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5376 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5377 font_initial[j].bitmap = bitmap_font_initial;
5379 InitFontGraphicInfo();
5381 font_height = getFontHeight(FC_RED);
5383 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5384 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5385 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5388 DrawInitText("Loading graphics", 120, FC_GREEN);
5390 /* initialize settings for busy animation with default values */
5391 int parameter[NUM_GFX_ARGS];
5392 for (i = 0; i < NUM_GFX_ARGS; i++)
5393 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5394 image_config_suffix[i].token,
5395 image_config_suffix[i].type);
5397 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5398 int len_anim_token = strlen(anim_token);
5400 /* read settings for busy animation from default custom artwork config */
5401 char *gfx_config_filename = getPath3(options.graphics_directory,
5403 GRAPHICSINFO_FILENAME);
5405 if (fileExists(gfx_config_filename))
5407 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5409 if (setup_file_hash)
5411 char *filename = getHashEntry(setup_file_hash, anim_token);
5415 filename_anim_initial = getStringCopy(filename);
5417 for (j = 0; image_config_suffix[j].token != NULL; j++)
5419 int type = image_config_suffix[j].type;
5420 char *suffix = image_config_suffix[j].token;
5421 char *token = getStringCat2(anim_token, suffix);
5422 char *value = getHashEntry(setup_file_hash, token);
5424 checked_free(token);
5427 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5431 freeSetupFileHash(setup_file_hash);
5435 if (filename_anim_initial == NULL)
5437 /* read settings for busy animation from static default artwork config */
5438 for (i = 0; image_config[i].token != NULL; i++)
5440 if (strEqual(image_config[i].token, anim_token))
5441 filename_anim_initial = getStringCopy(image_config[i].value);
5442 else if (strlen(image_config[i].token) > len_anim_token &&
5443 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5445 for (j = 0; image_config_suffix[j].token != NULL; j++)
5447 if (strEqual(&image_config[i].token[len_anim_token],
5448 image_config_suffix[j].token))
5450 get_graphic_parameter_value(image_config[i].value,
5451 image_config_suffix[j].token,
5452 image_config_suffix[j].type);
5458 if (filename_anim_initial == NULL) /* should not happen */
5459 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5461 anim_initial.bitmaps =
5462 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5464 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5465 LoadCustomImage(filename_anim_initial);
5467 checked_free(filename_anim_initial);
5469 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5471 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5473 graphic_info = graphic_info_last;
5475 init.busy.width = anim_initial.width;
5476 init.busy.height = anim_initial.height;
5478 InitMenuDesignSettings_Static();
5480 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5481 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5482 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5483 InitGfxDrawTileCursorFunction(DrawTileCursor);
5485 gfx.fade_border_source_status = global.border_status;
5486 gfx.fade_border_target_status = global.border_status;
5487 gfx.masked_border_bitmap_ptr = backbuffer;
5489 /* use copy of busy animation to prevent change while reloading artwork */
5493 static void InitGfxBackground(void)
5495 fieldbuffer = bitmap_db_field;
5496 SetDrawtoField(DRAW_TO_BACKBUFFER);
5498 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5500 redraw_mask = REDRAW_ALL;
5503 static void InitLevelInfo(void)
5505 LoadLevelInfo(); /* global level info */
5506 LoadLevelSetup_LastSeries(); /* last played series info */
5507 LoadLevelSetup_SeriesInfo(); /* last played level info */
5509 if (global.autoplay_leveldir &&
5510 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5512 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5513 global.autoplay_leveldir);
5514 if (leveldir_current == NULL)
5515 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5518 SetLevelSetInfo(leveldir_current->identifier, level_nr);
5521 static void InitLevelArtworkInfo(void)
5523 LoadLevelArtworkInfo();
5526 static void InitImages(void)
5528 print_timestamp_init("InitImages");
5531 printf("::: leveldir_current->identifier == '%s'\n",
5532 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5533 printf("::: leveldir_current->graphics_path == '%s'\n",
5534 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5535 printf("::: leveldir_current->graphics_set == '%s'\n",
5536 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5537 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5538 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5541 setLevelArtworkDir(artwork.gfx_first);
5544 printf("::: leveldir_current->identifier == '%s'\n",
5545 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5546 printf("::: leveldir_current->graphics_path == '%s'\n",
5547 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5548 printf("::: leveldir_current->graphics_set == '%s'\n",
5549 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5550 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5551 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5555 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5556 leveldir_current->identifier,
5557 artwork.gfx_current_identifier,
5558 artwork.gfx_current->identifier,
5559 leveldir_current->graphics_set,
5560 leveldir_current->graphics_path);
5563 UPDATE_BUSY_STATE();
5565 ReloadCustomImages();
5566 print_timestamp_time("ReloadCustomImages");
5568 UPDATE_BUSY_STATE();
5570 LoadCustomElementDescriptions();
5571 print_timestamp_time("LoadCustomElementDescriptions");
5573 UPDATE_BUSY_STATE();
5575 LoadMenuDesignSettings();
5576 print_timestamp_time("LoadMenuDesignSettings");
5578 UPDATE_BUSY_STATE();
5580 ReinitializeGraphics();
5581 print_timestamp_time("ReinitializeGraphics");
5583 LoadMenuDesignSettings_AfterGraphics();
5584 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5586 UPDATE_BUSY_STATE();
5588 print_timestamp_done("InitImages");
5591 static void InitSound(char *identifier)
5593 print_timestamp_init("InitSound");
5595 if (identifier == NULL)
5596 identifier = artwork.snd_current->identifier;
5598 /* set artwork path to send it to the sound server process */
5599 setLevelArtworkDir(artwork.snd_first);
5601 InitReloadCustomSounds(identifier);
5602 print_timestamp_time("InitReloadCustomSounds");
5604 ReinitializeSounds();
5605 print_timestamp_time("ReinitializeSounds");
5607 print_timestamp_done("InitSound");
5610 static void InitMusic(char *identifier)
5612 print_timestamp_init("InitMusic");
5614 if (identifier == NULL)
5615 identifier = artwork.mus_current->identifier;
5617 /* set artwork path to send it to the sound server process */
5618 setLevelArtworkDir(artwork.mus_first);
5620 InitReloadCustomMusic(identifier);
5621 print_timestamp_time("InitReloadCustomMusic");
5623 ReinitializeMusic();
5624 print_timestamp_time("ReinitializeMusic");
5626 print_timestamp_done("InitMusic");
5629 static void InitArtworkDone(void)
5631 if (program.headless)
5634 InitGlobalAnimations();
5637 static void InitNetworkSettings(void)
5639 boolean network_enabled = (options.network || setup.network_mode);
5640 char *network_server = (options.server_host != NULL ? options.server_host :
5641 setup.network_server_hostname);
5643 if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5644 network_server = NULL;
5646 InitNetworkInfo(network_enabled,
5650 options.server_port);
5653 void InitNetworkServer(void)
5655 if (!network.enabled || network.connected)
5658 LimitScreenUpdates(FALSE);
5660 if (!ConnectToServer(network.server_host, network.server_port))
5662 network.enabled = FALSE;
5664 setup.network_mode = FALSE;
5668 SendToServer_ProtocolVersion();
5669 SendToServer_PlayerName(setup.player_name);
5670 SendToServer_NrWanted(setup.network_player_nr + 1);
5672 network.connected = TRUE;
5675 /* short time to recognize result of network initialization */
5676 Delay_WithScreenUpdates(1000);
5679 static boolean CheckArtworkConfigForCustomElements(char *filename)
5681 SetupFileHash *setup_file_hash;
5682 boolean redefined_ce_found = FALSE;
5684 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5686 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5688 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5690 char *token = HASH_ITERATION_TOKEN(itr);
5692 if (strPrefix(token, "custom_"))
5694 redefined_ce_found = TRUE;
5699 END_HASH_ITERATION(setup_file_hash, itr)
5701 freeSetupFileHash(setup_file_hash);
5704 return redefined_ce_found;
5707 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5709 char *filename_base, *filename_local;
5710 boolean redefined_ce_found = FALSE;
5712 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5715 printf("::: leveldir_current->identifier == '%s'\n",
5716 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5717 printf("::: leveldir_current->graphics_path == '%s'\n",
5718 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5719 printf("::: leveldir_current->graphics_set == '%s'\n",
5720 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5721 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5722 leveldir_current == NULL ? "[NULL]" :
5723 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5726 /* first look for special artwork configured in level series config */
5727 filename_base = getCustomArtworkLevelConfigFilename(type);
5730 printf("::: filename_base == '%s'\n", filename_base);
5733 if (fileExists(filename_base))
5734 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5736 filename_local = getCustomArtworkConfigFilename(type);
5739 printf("::: filename_local == '%s'\n", filename_local);
5742 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5743 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5746 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5749 return redefined_ce_found;
5752 static void InitOverrideArtwork(void)
5754 boolean redefined_ce_found = FALSE;
5756 /* to check if this level set redefines any CEs, do not use overriding */
5757 gfx.override_level_graphics = FALSE;
5758 gfx.override_level_sounds = FALSE;
5759 gfx.override_level_music = FALSE;
5761 /* now check if this level set has definitions for custom elements */
5762 if (setup.override_level_graphics == AUTO ||
5763 setup.override_level_sounds == AUTO ||
5764 setup.override_level_music == AUTO)
5765 redefined_ce_found =
5766 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5767 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5768 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5771 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5774 if (redefined_ce_found)
5776 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5777 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5778 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5779 gfx.override_level_music = (setup.override_level_music == TRUE);
5783 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5784 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5785 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5786 gfx.override_level_music = (setup.override_level_music != FALSE);
5790 printf("::: => %d, %d, %d\n",
5791 gfx.override_level_graphics,
5792 gfx.override_level_sounds,
5793 gfx.override_level_music);
5797 static char *getNewArtworkIdentifier(int type)
5799 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5800 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5801 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5802 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5803 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5804 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5805 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5806 char *leveldir_identifier = leveldir_current->identifier;
5807 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5808 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5809 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5810 char *artwork_current_identifier;
5811 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5813 /* leveldir_current may be invalid (level group, parent link) */
5814 if (!validLevelSeries(leveldir_current))
5817 /* 1st step: determine artwork set to be activated in descending order:
5818 --------------------------------------------------------------------
5819 1. setup artwork (when configured to override everything else)
5820 2. artwork set configured in "levelinfo.conf" of current level set
5821 (artwork in level directory will have priority when loading later)
5822 3. artwork in level directory (stored in artwork sub-directory)
5823 4. setup artwork (currently configured in setup menu) */
5825 if (setup_override_artwork)
5826 artwork_current_identifier = setup_artwork_set;
5827 else if (leveldir_artwork_set != NULL)
5828 artwork_current_identifier = leveldir_artwork_set;
5829 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5830 artwork_current_identifier = leveldir_identifier;
5832 artwork_current_identifier = setup_artwork_set;
5835 /* 2nd step: check if it is really needed to reload artwork set
5836 ------------------------------------------------------------ */
5838 /* ---------- reload if level set and also artwork set has changed ------- */
5839 if (leveldir_current_identifier[type] != leveldir_identifier &&
5840 (last_has_level_artwork_set[type] || has_level_artwork_set))
5841 artwork_new_identifier = artwork_current_identifier;
5843 leveldir_current_identifier[type] = leveldir_identifier;
5844 last_has_level_artwork_set[type] = has_level_artwork_set;
5846 /* ---------- reload if "override artwork" setting has changed ----------- */
5847 if (last_override_level_artwork[type] != setup_override_artwork)
5848 artwork_new_identifier = artwork_current_identifier;
5850 last_override_level_artwork[type] = setup_override_artwork;
5852 /* ---------- reload if current artwork identifier has changed ----------- */
5853 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5854 artwork_current_identifier))
5855 artwork_new_identifier = artwork_current_identifier;
5857 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5859 /* ---------- do not reload directly after starting ---------------------- */
5860 if (!initialized[type])
5861 artwork_new_identifier = NULL;
5863 initialized[type] = TRUE;
5865 return artwork_new_identifier;
5868 void ReloadCustomArtwork(int force_reload)
5870 int last_game_status = game_status; /* save current game status */
5871 char *gfx_new_identifier;
5872 char *snd_new_identifier;
5873 char *mus_new_identifier;
5874 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5875 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5876 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5877 boolean reload_needed;
5879 InitOverrideArtwork();
5881 force_reload_gfx |= AdjustGraphicsForEMC();
5883 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5884 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5885 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5887 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5888 snd_new_identifier != NULL || force_reload_snd ||
5889 mus_new_identifier != NULL || force_reload_mus);
5894 print_timestamp_init("ReloadCustomArtwork");
5896 SetGameStatus(GAME_MODE_LOADING);
5898 FadeOut(REDRAW_ALL);
5900 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5901 print_timestamp_time("ClearRectangle");
5905 if (gfx_new_identifier != NULL || force_reload_gfx)
5908 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5909 artwork.gfx_current_identifier,
5911 artwork.gfx_current->identifier,
5912 leveldir_current->graphics_set);
5916 print_timestamp_time("InitImages");
5919 if (snd_new_identifier != NULL || force_reload_snd)
5921 InitSound(snd_new_identifier);
5922 print_timestamp_time("InitSound");
5925 if (mus_new_identifier != NULL || force_reload_mus)
5927 InitMusic(mus_new_identifier);
5928 print_timestamp_time("InitMusic");
5933 SetGameStatus(last_game_status); /* restore current game status */
5935 init_last = init; /* switch to new busy animation */
5937 FadeOut(REDRAW_ALL);
5939 RedrawGlobalBorder();
5941 /* force redraw of (open or closed) door graphics */
5942 SetDoorState(DOOR_OPEN_ALL);
5943 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5945 FadeSetEnterScreen();
5946 FadeSkipNextFadeOut();
5948 print_timestamp_done("ReloadCustomArtwork");
5950 LimitScreenUpdates(FALSE);
5953 void KeyboardAutoRepeatOffUnlessAutoplay(void)
5955 if (global.autoplay_leveldir == NULL)
5956 KeyboardAutoRepeatOff();
5959 void DisplayExitMessage(char *format, va_list ap)
5961 // also check for initialized video (headless flag may be temporarily unset)
5962 if (program.headless || !video.initialized)
5965 // check if draw buffer and fonts for exit message are already available
5966 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5969 int font_1 = FC_RED;
5970 int font_2 = FC_YELLOW;
5971 int font_3 = FC_BLUE;
5972 int font_width = getFontWidth(font_2);
5973 int font_height = getFontHeight(font_2);
5976 int sxsize = WIN_XSIZE - 2 * sx;
5977 int sysize = WIN_YSIZE - 2 * sy;
5978 int line_length = sxsize / font_width;
5979 int max_lines = sysize / font_height;
5980 int num_lines_printed;
5984 gfx.sxsize = sxsize;
5985 gfx.sysize = sysize;
5989 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5991 DrawTextSCentered(sy, font_1, "Fatal error:");
5992 sy += 3 * font_height;;
5995 DrawTextBufferVA(sx, sy, format, ap, font_2,
5996 line_length, line_length, max_lines,
5997 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5998 sy += (num_lines_printed + 3) * font_height;
6000 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6001 sy += 3 * font_height;
6004 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6005 line_length, line_length, max_lines,
6006 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6008 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6010 redraw_mask = REDRAW_ALL;
6012 /* force drawing exit message even if screen updates are currently limited */
6013 LimitScreenUpdates(FALSE);
6017 /* deactivate toons on error message screen */
6018 setup.toons = FALSE;
6020 WaitForEventToContinue();
6024 /* ========================================================================= */
6026 /* ========================================================================= */
6030 print_timestamp_init("OpenAll");
6032 SetGameStatus(GAME_MODE_LOADING);
6036 InitGlobal(); /* initialize some global variables */
6038 print_timestamp_time("[init global stuff]");
6042 print_timestamp_time("[init setup/config stuff (1)]");
6046 if (options.execute_command)
6047 Execute_Command(options.execute_command);
6049 InitNetworkSettings();
6051 if (network.serveronly)
6053 #if defined(PLATFORM_UNIX)
6054 NetworkServer(network.server_port, TRUE);
6056 Error(ERR_WARN, "networking only supported in Unix version");
6059 exit(0); /* never reached, server loops forever */
6063 print_timestamp_time("[init setup/config stuff (2)]");
6065 print_timestamp_time("[init setup/config stuff (3)]");
6066 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6067 print_timestamp_time("[init setup/config stuff (4)]");
6068 InitArtworkConfig(); /* needed before forking sound child process */
6069 print_timestamp_time("[init setup/config stuff (5)]");
6071 print_timestamp_time("[init setup/config stuff (6)]");
6073 InitRND(NEW_RANDOMIZE);
6074 InitSimpleRandom(NEW_RANDOMIZE);
6078 print_timestamp_time("[init setup/config stuff]");
6080 InitVideoDefaults();
6082 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6085 print_timestamp_time("[init video stuff]");
6087 InitElementPropertiesStatic();
6088 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6089 InitElementPropertiesGfxElement();
6091 print_timestamp_time("[init element properties stuff]");
6095 print_timestamp_time("InitGfx");
6098 print_timestamp_time("InitLevelInfo");
6100 InitLevelArtworkInfo();
6101 print_timestamp_time("InitLevelArtworkInfo");
6103 InitOverrideArtwork(); /* needs to know current level directory */
6104 print_timestamp_time("InitOverrideArtwork");
6106 InitImages(); /* needs to know current level directory */
6107 print_timestamp_time("InitImages");
6109 InitSound(NULL); /* needs to know current level directory */
6110 print_timestamp_time("InitSound");
6112 InitMusic(NULL); /* needs to know current level directory */
6113 print_timestamp_time("InitMusic");
6117 InitGfxBackground();
6123 if (global.autoplay_leveldir)
6128 else if (global.convert_leveldir)
6133 else if (global.create_images_dir)
6135 CreateLevelSketchImages();
6139 InitNetworkServer();
6141 SetGameStatus(GAME_MODE_MAIN);
6143 FadeSetEnterScreen();
6144 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6145 FadeSkipNextFadeOut();
6147 print_timestamp_time("[post-artwork]");
6149 print_timestamp_done("OpenAll");
6154 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6156 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6157 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6158 #if defined(PLATFORM_ANDROID)
6159 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6160 SDL_AndroidGetInternalStoragePath());
6161 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6162 SDL_AndroidGetExternalStoragePath());
6163 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6164 (SDL_AndroidGetExternalStorageState() &
6165 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6166 SDL_AndroidGetExternalStorageState() &
6167 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6172 void CloseAllAndExit(int exit_value)
6177 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6184 #if defined(TARGET_SDL)
6185 #if defined(TARGET_SDL2)
6187 // set a flag to tell the network server thread to quit and wait for it
6188 // using SDL_WaitThread()
6190 if (network_server) /* terminate network server */
6191 SDL_KillThread(server_thread);
6195 CloseVideoDisplay();
6196 ClosePlatformDependentStuff();
6198 if (exit_value != 0 && !options.execute_command)
6200 /* fall back to default level set (current set may have caused an error) */
6201 SaveLevelSetup_LastSeries_Deactivate();
6203 /* tell user where to find error log file which may contain more details */
6204 // (error notification now directly displayed on screen inside R'n'D
6205 // NotifyUserAboutErrorFile(); /* currently only works for Windows */