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);
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;
141 FreeLevelEditorGadgets();
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 void InitElementSmallImages()
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 void InitScaledImages()
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 void InitBitmapPointers()
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()
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 void InitFontGraphicInfo()
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 void InitGlobalAnimGraphicInfo()
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 void InitGlobalAnimSoundInfo()
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 void InitGlobalAnimMusicInfo()
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 void InitElementGraphicInfo()
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 void InitElementSpecialGraphicInfo()
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()
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()
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()
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()
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()
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()
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()
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()
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()
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()
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()
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,
3663 EL_DC_SWITCHGATE_SWITCH_UP,
3664 EL_DC_SWITCHGATE_SWITCH_DOWN,
3666 EL_TIMEGATE_SWITCH_ACTIVE,
3667 EL_DC_TIMEGATE_SWITCH,
3668 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3680 /* the following elements are a direct copy of "indestructible" elements,
3681 except "EL_ACID", which is "indestructible", but not "solid"! */
3686 EL_ACID_POOL_TOPLEFT,
3687 EL_ACID_POOL_TOPRIGHT,
3688 EL_ACID_POOL_BOTTOMLEFT,
3689 EL_ACID_POOL_BOTTOM,
3690 EL_ACID_POOL_BOTTOMRIGHT,
3691 EL_SP_HARDWARE_GRAY,
3692 EL_SP_HARDWARE_GREEN,
3693 EL_SP_HARDWARE_BLUE,
3695 EL_SP_HARDWARE_YELLOW,
3696 EL_SP_HARDWARE_BASE_1,
3697 EL_SP_HARDWARE_BASE_2,
3698 EL_SP_HARDWARE_BASE_3,
3699 EL_SP_HARDWARE_BASE_4,
3700 EL_SP_HARDWARE_BASE_5,
3701 EL_SP_HARDWARE_BASE_6,
3702 EL_INVISIBLE_STEELWALL,
3703 EL_INVISIBLE_STEELWALL_ACTIVE,
3704 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3705 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3706 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3707 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3708 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3709 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3710 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3711 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3712 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3713 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3714 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3715 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3717 EL_LIGHT_SWITCH_ACTIVE,
3718 EL_SIGN_EXCLAMATION,
3719 EL_SIGN_RADIOACTIVITY,
3726 EL_SIGN_ENTRY_FORBIDDEN,
3727 EL_SIGN_EMERGENCY_EXIT,
3735 EL_STEEL_EXIT_CLOSED,
3737 EL_DC_STEELWALL_1_LEFT,
3738 EL_DC_STEELWALL_1_RIGHT,
3739 EL_DC_STEELWALL_1_TOP,
3740 EL_DC_STEELWALL_1_BOTTOM,
3741 EL_DC_STEELWALL_1_HORIZONTAL,
3742 EL_DC_STEELWALL_1_VERTICAL,
3743 EL_DC_STEELWALL_1_TOPLEFT,
3744 EL_DC_STEELWALL_1_TOPRIGHT,
3745 EL_DC_STEELWALL_1_BOTTOMLEFT,
3746 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3747 EL_DC_STEELWALL_1_TOPLEFT_2,
3748 EL_DC_STEELWALL_1_TOPRIGHT_2,
3749 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3750 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3751 EL_DC_STEELWALL_2_LEFT,
3752 EL_DC_STEELWALL_2_RIGHT,
3753 EL_DC_STEELWALL_2_TOP,
3754 EL_DC_STEELWALL_2_BOTTOM,
3755 EL_DC_STEELWALL_2_HORIZONTAL,
3756 EL_DC_STEELWALL_2_VERTICAL,
3757 EL_DC_STEELWALL_2_MIDDLE,
3758 EL_DC_STEELWALL_2_SINGLE,
3759 EL_STEELWALL_SLIPPERY,
3773 EL_GATE_1_GRAY_ACTIVE,
3774 EL_GATE_2_GRAY_ACTIVE,
3775 EL_GATE_3_GRAY_ACTIVE,
3776 EL_GATE_4_GRAY_ACTIVE,
3785 EL_EM_GATE_1_GRAY_ACTIVE,
3786 EL_EM_GATE_2_GRAY_ACTIVE,
3787 EL_EM_GATE_3_GRAY_ACTIVE,
3788 EL_EM_GATE_4_GRAY_ACTIVE,
3790 EL_SWITCHGATE_OPENING,
3791 EL_SWITCHGATE_CLOSED,
3792 EL_SWITCHGATE_CLOSING,
3794 EL_TIMEGATE_OPENING,
3796 EL_TIMEGATE_CLOSING,
3800 EL_TUBE_VERTICAL_LEFT,
3801 EL_TUBE_VERTICAL_RIGHT,
3802 EL_TUBE_HORIZONTAL_UP,
3803 EL_TUBE_HORIZONTAL_DOWN,
3812 static int ep_classic_enemy[] =
3829 static int ep_belt[] =
3831 EL_CONVEYOR_BELT_1_LEFT,
3832 EL_CONVEYOR_BELT_1_MIDDLE,
3833 EL_CONVEYOR_BELT_1_RIGHT,
3834 EL_CONVEYOR_BELT_2_LEFT,
3835 EL_CONVEYOR_BELT_2_MIDDLE,
3836 EL_CONVEYOR_BELT_2_RIGHT,
3837 EL_CONVEYOR_BELT_3_LEFT,
3838 EL_CONVEYOR_BELT_3_MIDDLE,
3839 EL_CONVEYOR_BELT_3_RIGHT,
3840 EL_CONVEYOR_BELT_4_LEFT,
3841 EL_CONVEYOR_BELT_4_MIDDLE,
3842 EL_CONVEYOR_BELT_4_RIGHT,
3847 static int ep_belt_active[] =
3849 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3850 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3851 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3852 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3853 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3854 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3855 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3856 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3857 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3858 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3859 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3860 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3865 static int ep_belt_switch[] =
3867 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3868 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3869 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3870 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3871 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3872 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3873 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3874 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3875 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3876 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3877 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3878 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3883 static int ep_tube[] =
3890 EL_TUBE_HORIZONTAL_UP,
3891 EL_TUBE_HORIZONTAL_DOWN,
3893 EL_TUBE_VERTICAL_LEFT,
3894 EL_TUBE_VERTICAL_RIGHT,
3900 static int ep_acid_pool[] =
3902 EL_ACID_POOL_TOPLEFT,
3903 EL_ACID_POOL_TOPRIGHT,
3904 EL_ACID_POOL_BOTTOMLEFT,
3905 EL_ACID_POOL_BOTTOM,
3906 EL_ACID_POOL_BOTTOMRIGHT,
3911 static int ep_keygate[] =
3921 EL_GATE_1_GRAY_ACTIVE,
3922 EL_GATE_2_GRAY_ACTIVE,
3923 EL_GATE_3_GRAY_ACTIVE,
3924 EL_GATE_4_GRAY_ACTIVE,
3933 EL_EM_GATE_1_GRAY_ACTIVE,
3934 EL_EM_GATE_2_GRAY_ACTIVE,
3935 EL_EM_GATE_3_GRAY_ACTIVE,
3936 EL_EM_GATE_4_GRAY_ACTIVE,
3945 EL_EMC_GATE_5_GRAY_ACTIVE,
3946 EL_EMC_GATE_6_GRAY_ACTIVE,
3947 EL_EMC_GATE_7_GRAY_ACTIVE,
3948 EL_EMC_GATE_8_GRAY_ACTIVE,
3950 EL_DC_GATE_WHITE_GRAY,
3951 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3956 static int ep_amoeboid[] =
3968 static int ep_amoebalive[] =
3979 static int ep_has_editor_content[] =
3985 EL_SOKOBAN_FIELD_PLAYER,
4002 static int ep_can_turn_each_move[] =
4004 /* !!! do something with this one !!! */
4008 static int ep_can_grow[] =
4022 static int ep_active_bomb[] =
4025 EL_EM_DYNAMITE_ACTIVE,
4026 EL_DYNABOMB_PLAYER_1_ACTIVE,
4027 EL_DYNABOMB_PLAYER_2_ACTIVE,
4028 EL_DYNABOMB_PLAYER_3_ACTIVE,
4029 EL_DYNABOMB_PLAYER_4_ACTIVE,
4030 EL_SP_DISK_RED_ACTIVE,
4035 static int ep_inactive[] =
4045 EL_QUICKSAND_FAST_EMPTY,
4068 EL_GATE_1_GRAY_ACTIVE,
4069 EL_GATE_2_GRAY_ACTIVE,
4070 EL_GATE_3_GRAY_ACTIVE,
4071 EL_GATE_4_GRAY_ACTIVE,
4080 EL_EM_GATE_1_GRAY_ACTIVE,
4081 EL_EM_GATE_2_GRAY_ACTIVE,
4082 EL_EM_GATE_3_GRAY_ACTIVE,
4083 EL_EM_GATE_4_GRAY_ACTIVE,
4092 EL_EMC_GATE_5_GRAY_ACTIVE,
4093 EL_EMC_GATE_6_GRAY_ACTIVE,
4094 EL_EMC_GATE_7_GRAY_ACTIVE,
4095 EL_EMC_GATE_8_GRAY_ACTIVE,
4097 EL_DC_GATE_WHITE_GRAY,
4098 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4099 EL_DC_GATE_FAKE_GRAY,
4102 EL_INVISIBLE_STEELWALL,
4110 EL_WALL_EMERALD_YELLOW,
4111 EL_DYNABOMB_INCREASE_NUMBER,
4112 EL_DYNABOMB_INCREASE_SIZE,
4113 EL_DYNABOMB_INCREASE_POWER,
4117 EL_SOKOBAN_FIELD_EMPTY,
4118 EL_SOKOBAN_FIELD_FULL,
4119 EL_WALL_EMERALD_RED,
4120 EL_WALL_EMERALD_PURPLE,
4121 EL_ACID_POOL_TOPLEFT,
4122 EL_ACID_POOL_TOPRIGHT,
4123 EL_ACID_POOL_BOTTOMLEFT,
4124 EL_ACID_POOL_BOTTOM,
4125 EL_ACID_POOL_BOTTOMRIGHT,
4129 EL_BD_MAGIC_WALL_DEAD,
4131 EL_DC_MAGIC_WALL_DEAD,
4132 EL_AMOEBA_TO_DIAMOND,
4140 EL_SP_GRAVITY_PORT_RIGHT,
4141 EL_SP_GRAVITY_PORT_DOWN,
4142 EL_SP_GRAVITY_PORT_LEFT,
4143 EL_SP_GRAVITY_PORT_UP,
4144 EL_SP_PORT_HORIZONTAL,
4145 EL_SP_PORT_VERTICAL,
4156 EL_SP_HARDWARE_GRAY,
4157 EL_SP_HARDWARE_GREEN,
4158 EL_SP_HARDWARE_BLUE,
4160 EL_SP_HARDWARE_YELLOW,
4161 EL_SP_HARDWARE_BASE_1,
4162 EL_SP_HARDWARE_BASE_2,
4163 EL_SP_HARDWARE_BASE_3,
4164 EL_SP_HARDWARE_BASE_4,
4165 EL_SP_HARDWARE_BASE_5,
4166 EL_SP_HARDWARE_BASE_6,
4167 EL_SP_GRAVITY_ON_PORT_LEFT,
4168 EL_SP_GRAVITY_ON_PORT_RIGHT,
4169 EL_SP_GRAVITY_ON_PORT_UP,
4170 EL_SP_GRAVITY_ON_PORT_DOWN,
4171 EL_SP_GRAVITY_OFF_PORT_LEFT,
4172 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4173 EL_SP_GRAVITY_OFF_PORT_UP,
4174 EL_SP_GRAVITY_OFF_PORT_DOWN,
4175 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4176 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4177 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4178 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4179 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4180 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4181 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4182 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4183 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4184 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4185 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4186 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4187 EL_SIGN_EXCLAMATION,
4188 EL_SIGN_RADIOACTIVITY,
4195 EL_SIGN_ENTRY_FORBIDDEN,
4196 EL_SIGN_EMERGENCY_EXIT,
4204 EL_DC_STEELWALL_1_LEFT,
4205 EL_DC_STEELWALL_1_RIGHT,
4206 EL_DC_STEELWALL_1_TOP,
4207 EL_DC_STEELWALL_1_BOTTOM,
4208 EL_DC_STEELWALL_1_HORIZONTAL,
4209 EL_DC_STEELWALL_1_VERTICAL,
4210 EL_DC_STEELWALL_1_TOPLEFT,
4211 EL_DC_STEELWALL_1_TOPRIGHT,
4212 EL_DC_STEELWALL_1_BOTTOMLEFT,
4213 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4214 EL_DC_STEELWALL_1_TOPLEFT_2,
4215 EL_DC_STEELWALL_1_TOPRIGHT_2,
4216 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4217 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4218 EL_DC_STEELWALL_2_LEFT,
4219 EL_DC_STEELWALL_2_RIGHT,
4220 EL_DC_STEELWALL_2_TOP,
4221 EL_DC_STEELWALL_2_BOTTOM,
4222 EL_DC_STEELWALL_2_HORIZONTAL,
4223 EL_DC_STEELWALL_2_VERTICAL,
4224 EL_DC_STEELWALL_2_MIDDLE,
4225 EL_DC_STEELWALL_2_SINGLE,
4226 EL_STEELWALL_SLIPPERY,
4231 EL_EMC_WALL_SLIPPERY_1,
4232 EL_EMC_WALL_SLIPPERY_2,
4233 EL_EMC_WALL_SLIPPERY_3,
4234 EL_EMC_WALL_SLIPPERY_4,
4255 static int ep_em_slippery_wall[] =
4260 static int ep_gfx_crumbled[] =
4271 static int ep_editor_cascade_active[] =
4273 EL_INTERNAL_CASCADE_BD_ACTIVE,
4274 EL_INTERNAL_CASCADE_EM_ACTIVE,
4275 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4276 EL_INTERNAL_CASCADE_RND_ACTIVE,
4277 EL_INTERNAL_CASCADE_SB_ACTIVE,
4278 EL_INTERNAL_CASCADE_SP_ACTIVE,
4279 EL_INTERNAL_CASCADE_DC_ACTIVE,
4280 EL_INTERNAL_CASCADE_DX_ACTIVE,
4281 EL_INTERNAL_CASCADE_MM_ACTIVE,
4282 EL_INTERNAL_CASCADE_DF_ACTIVE,
4283 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4284 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4285 EL_INTERNAL_CASCADE_CE_ACTIVE,
4286 EL_INTERNAL_CASCADE_GE_ACTIVE,
4287 EL_INTERNAL_CASCADE_REF_ACTIVE,
4288 EL_INTERNAL_CASCADE_USER_ACTIVE,
4289 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4294 static int ep_editor_cascade_inactive[] =
4296 EL_INTERNAL_CASCADE_BD,
4297 EL_INTERNAL_CASCADE_EM,
4298 EL_INTERNAL_CASCADE_EMC,
4299 EL_INTERNAL_CASCADE_RND,
4300 EL_INTERNAL_CASCADE_SB,
4301 EL_INTERNAL_CASCADE_SP,
4302 EL_INTERNAL_CASCADE_DC,
4303 EL_INTERNAL_CASCADE_DX,
4304 EL_INTERNAL_CASCADE_MM,
4305 EL_INTERNAL_CASCADE_DF,
4306 EL_INTERNAL_CASCADE_CHARS,
4307 EL_INTERNAL_CASCADE_STEEL_CHARS,
4308 EL_INTERNAL_CASCADE_CE,
4309 EL_INTERNAL_CASCADE_GE,
4310 EL_INTERNAL_CASCADE_REF,
4311 EL_INTERNAL_CASCADE_USER,
4312 EL_INTERNAL_CASCADE_DYNAMIC,
4317 static int ep_obsolete[] =
4321 EL_EM_KEY_1_FILE_OBSOLETE,
4322 EL_EM_KEY_2_FILE_OBSOLETE,
4323 EL_EM_KEY_3_FILE_OBSOLETE,
4324 EL_EM_KEY_4_FILE_OBSOLETE,
4325 EL_ENVELOPE_OBSOLETE,
4334 } element_properties[] =
4336 { ep_diggable, EP_DIGGABLE },
4337 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4338 { ep_dont_run_into, EP_DONT_RUN_INTO },
4339 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4340 { ep_dont_touch, EP_DONT_TOUCH },
4341 { ep_indestructible, EP_INDESTRUCTIBLE },
4342 { ep_slippery, EP_SLIPPERY },
4343 { ep_can_change, EP_CAN_CHANGE },
4344 { ep_can_move, EP_CAN_MOVE },
4345 { ep_can_fall, EP_CAN_FALL },
4346 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4347 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4348 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4349 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4350 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4351 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4352 { ep_walkable_over, EP_WALKABLE_OVER },
4353 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4354 { ep_walkable_under, EP_WALKABLE_UNDER },
4355 { ep_passable_over, EP_PASSABLE_OVER },
4356 { ep_passable_inside, EP_PASSABLE_INSIDE },
4357 { ep_passable_under, EP_PASSABLE_UNDER },
4358 { ep_droppable, EP_DROPPABLE },
4359 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4360 { ep_pushable, EP_PUSHABLE },
4361 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4362 { ep_protected, EP_PROTECTED },
4363 { ep_throwable, EP_THROWABLE },
4364 { ep_can_explode, EP_CAN_EXPLODE },
4365 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4367 { ep_player, EP_PLAYER },
4368 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4369 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4370 { ep_switchable, EP_SWITCHABLE },
4371 { ep_bd_element, EP_BD_ELEMENT },
4372 { ep_sp_element, EP_SP_ELEMENT },
4373 { ep_sb_element, EP_SB_ELEMENT },
4375 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4376 { ep_food_penguin, EP_FOOD_PENGUIN },
4377 { ep_food_pig, EP_FOOD_PIG },
4378 { ep_historic_wall, EP_HISTORIC_WALL },
4379 { ep_historic_solid, EP_HISTORIC_SOLID },
4380 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4381 { ep_belt, EP_BELT },
4382 { ep_belt_active, EP_BELT_ACTIVE },
4383 { ep_belt_switch, EP_BELT_SWITCH },
4384 { ep_tube, EP_TUBE },
4385 { ep_acid_pool, EP_ACID_POOL },
4386 { ep_keygate, EP_KEYGATE },
4387 { ep_amoeboid, EP_AMOEBOID },
4388 { ep_amoebalive, EP_AMOEBALIVE },
4389 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4390 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4391 { ep_can_grow, EP_CAN_GROW },
4392 { ep_active_bomb, EP_ACTIVE_BOMB },
4393 { ep_inactive, EP_INACTIVE },
4395 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4397 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4399 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4400 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4402 { ep_obsolete, EP_OBSOLETE },
4409 /* always start with reliable default values (element has no properties) */
4410 /* (but never initialize clipboard elements after the very first time) */
4411 /* (to be able to use clipboard elements between several levels) */
4412 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4413 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4414 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4415 SET_PROPERTY(i, j, FALSE);
4417 /* set all base element properties from above array definitions */
4418 for (i = 0; element_properties[i].elements != NULL; i++)
4419 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4420 SET_PROPERTY((element_properties[i].elements)[j],
4421 element_properties[i].property, TRUE);
4423 /* copy properties to some elements that are only stored in level file */
4424 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4425 for (j = 0; copy_properties[j][0] != -1; j++)
4426 if (HAS_PROPERTY(copy_properties[j][0], i))
4427 for (k = 1; k <= 4; k++)
4428 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4430 /* set static element properties that are not listed in array definitions */
4431 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4432 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4434 clipboard_elements_initialized = TRUE;
4437 void InitElementPropertiesEngine(int engine_version)
4439 static int no_wall_properties[] =
4442 EP_COLLECTIBLE_ONLY,
4444 EP_DONT_COLLIDE_WITH,
4447 EP_CAN_SMASH_PLAYER,
4448 EP_CAN_SMASH_ENEMIES,
4449 EP_CAN_SMASH_EVERYTHING,
4454 EP_FOOD_DARK_YAMYAM,
4470 /* important: after initialization in InitElementPropertiesStatic(), the
4471 elements are not again initialized to a default value; therefore all
4472 changes have to make sure that they leave the element with a defined
4473 property (which means that conditional property changes must be set to
4474 a reliable default value before) */
4476 /* resolve group elements */
4477 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4478 ResolveGroupElement(EL_GROUP_START + i);
4480 /* set all special, combined or engine dependent element properties */
4481 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4483 /* do not change (already initialized) clipboard elements here */
4484 if (IS_CLIPBOARD_ELEMENT(i))
4487 /* ---------- INACTIVE ------------------------------------------------- */
4488 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4489 i <= EL_CHAR_END) ||
4490 (i >= EL_STEEL_CHAR_START &&
4491 i <= EL_STEEL_CHAR_END)));
4493 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4494 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4495 IS_WALKABLE_INSIDE(i) ||
4496 IS_WALKABLE_UNDER(i)));
4498 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4499 IS_PASSABLE_INSIDE(i) ||
4500 IS_PASSABLE_UNDER(i)));
4502 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4503 IS_PASSABLE_OVER(i)));
4505 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4506 IS_PASSABLE_INSIDE(i)));
4508 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4509 IS_PASSABLE_UNDER(i)));
4511 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4514 /* ---------- COLLECTIBLE ---------------------------------------------- */
4515 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4519 /* ---------- SNAPPABLE ------------------------------------------------ */
4520 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4521 IS_COLLECTIBLE(i) ||
4525 /* ---------- WALL ----------------------------------------------------- */
4526 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4528 for (j = 0; no_wall_properties[j] != -1; j++)
4529 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4530 i >= EL_FIRST_RUNTIME_UNREAL)
4531 SET_PROPERTY(i, EP_WALL, FALSE);
4533 if (IS_HISTORIC_WALL(i))
4534 SET_PROPERTY(i, EP_WALL, TRUE);
4536 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4537 if (engine_version < VERSION_IDENT(2,2,0,0))
4538 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4540 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4542 !IS_COLLECTIBLE(i)));
4544 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4545 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4546 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4548 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4549 IS_INDESTRUCTIBLE(i)));
4551 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4553 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4554 else if (engine_version < VERSION_IDENT(2,2,0,0))
4555 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4557 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4561 if (IS_CUSTOM_ELEMENT(i))
4563 /* these are additional properties which are initially false when set */
4565 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4567 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4568 if (DONT_COLLIDE_WITH(i))
4569 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4571 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4572 if (CAN_SMASH_EVERYTHING(i))
4573 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4574 if (CAN_SMASH_ENEMIES(i))
4575 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4578 /* ---------- CAN_SMASH ------------------------------------------------ */
4579 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4580 CAN_SMASH_ENEMIES(i) ||
4581 CAN_SMASH_EVERYTHING(i)));
4583 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4584 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4585 EXPLODES_BY_FIRE(i)));
4587 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4588 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4589 EXPLODES_SMASHED(i)));
4591 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4592 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4593 EXPLODES_IMPACT(i)));
4595 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4596 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4598 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4599 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4600 i == EL_BLACK_ORB));
4602 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4603 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4605 IS_CUSTOM_ELEMENT(i)));
4607 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4608 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4609 i == EL_SP_ELECTRON));
4611 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4612 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4613 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4614 getMoveIntoAcidProperty(&level, i));
4616 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4617 if (MAYBE_DONT_COLLIDE_WITH(i))
4618 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4619 getDontCollideWithProperty(&level, i));
4621 /* ---------- SP_PORT -------------------------------------------------- */
4622 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4623 IS_PASSABLE_INSIDE(i)));
4625 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4626 for (j = 0; j < level.num_android_clone_elements; j++)
4627 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4629 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4631 /* ---------- CAN_CHANGE ----------------------------------------------- */
4632 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4633 for (j = 0; j < element_info[i].num_change_pages; j++)
4634 if (element_info[i].change_page[j].can_change)
4635 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4637 /* ---------- HAS_ACTION ----------------------------------------------- */
4638 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4639 for (j = 0; j < element_info[i].num_change_pages; j++)
4640 if (element_info[i].change_page[j].has_action)
4641 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4643 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4644 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4647 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4648 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4649 element_info[i].crumbled[ACTION_DEFAULT] !=
4650 element_info[i].graphic[ACTION_DEFAULT]);
4652 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4653 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4654 IS_EDITOR_CASCADE_INACTIVE(i)));
4657 /* dynamically adjust element properties according to game engine version */
4659 static int ep_em_slippery_wall[] =
4664 EL_EXPANDABLE_WALL_HORIZONTAL,
4665 EL_EXPANDABLE_WALL_VERTICAL,
4666 EL_EXPANDABLE_WALL_ANY,
4667 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4668 EL_EXPANDABLE_STEELWALL_VERTICAL,
4669 EL_EXPANDABLE_STEELWALL_ANY,
4670 EL_EXPANDABLE_STEELWALL_GROWING,
4674 static int ep_em_explodes_by_fire[] =
4677 EL_EM_DYNAMITE_ACTIVE,
4682 /* special EM style gems behaviour */
4683 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4684 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4685 level.em_slippery_gems);
4687 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4688 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4689 (level.em_slippery_gems &&
4690 engine_version > VERSION_IDENT(2,0,1,0)));
4692 /* special EM style explosion behaviour regarding chain reactions */
4693 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4694 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4695 level.em_explodes_by_fire);
4698 /* this is needed because some graphics depend on element properties */
4699 if (game_status == GAME_MODE_PLAYING)
4700 InitElementGraphicInfo();
4703 void InitElementPropertiesGfxElement()
4707 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4709 struct ElementInfo *ei = &element_info[i];
4711 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4715 static void InitGlobal()
4720 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4722 /* check if element_name_info entry defined for each element in "main.h" */
4723 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4724 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4726 element_info[i].token_name = element_name_info[i].token_name;
4727 element_info[i].class_name = element_name_info[i].class_name;
4728 element_info[i].editor_description= element_name_info[i].editor_description;
4731 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4733 /* check if global_anim_name_info defined for each entry in "main.h" */
4734 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4735 global_anim_name_info[i].token_name == NULL)
4736 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4738 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4741 /* create hash from image config list */
4742 image_config_hash = newSetupFileHash();
4743 for (i = 0; image_config[i].token != NULL; i++)
4744 setHashEntry(image_config_hash,
4745 image_config[i].token,
4746 image_config[i].value);
4748 /* create hash from element token list */
4749 element_token_hash = newSetupFileHash();
4750 for (i = 0; element_name_info[i].token_name != NULL; i++)
4751 setHashEntry(element_token_hash,
4752 element_name_info[i].token_name,
4755 /* create hash from graphic token list */
4756 graphic_token_hash = newSetupFileHash();
4757 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4758 if (strSuffix(image_config[i].value, ".png") ||
4759 strSuffix(image_config[i].value, ".pcx") ||
4760 strSuffix(image_config[i].value, ".wav") ||
4761 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4762 setHashEntry(graphic_token_hash,
4763 image_config[i].token,
4764 int2str(graphic++, 0));
4766 /* create hash from font token list */
4767 font_token_hash = newSetupFileHash();
4768 for (i = 0; font_info[i].token_name != NULL; i++)
4769 setHashEntry(font_token_hash,
4770 font_info[i].token_name,
4773 /* set default filenames for all cloned graphics in static configuration */
4774 for (i = 0; image_config[i].token != NULL; i++)
4776 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4778 char *token = image_config[i].token;
4779 char *token_clone_from = getStringCat2(token, ".clone_from");
4780 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4782 if (token_cloned != NULL)
4784 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4786 if (value_cloned != NULL)
4788 /* set default filename in static configuration */
4789 image_config[i].value = value_cloned;
4791 /* set default filename in image config hash */
4792 setHashEntry(image_config_hash, token, value_cloned);
4796 free(token_clone_from);
4800 /* always start with reliable default values (all elements) */
4801 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4802 ActiveElement[i] = i;
4804 /* now add all entries that have an active state (active elements) */
4805 for (i = 0; element_with_active_state[i].element != -1; i++)
4807 int element = element_with_active_state[i].element;
4808 int element_active = element_with_active_state[i].element_active;
4810 ActiveElement[element] = element_active;
4813 /* always start with reliable default values (all buttons) */
4814 for (i = 0; i < NUM_IMAGE_FILES; i++)
4815 ActiveButton[i] = i;
4817 /* now add all entries that have an active state (active buttons) */
4818 for (i = 0; button_with_active_state[i].button != -1; i++)
4820 int button = button_with_active_state[i].button;
4821 int button_active = button_with_active_state[i].button_active;
4823 ActiveButton[button] = button_active;
4826 /* always start with reliable default values (all fonts) */
4827 for (i = 0; i < NUM_FONTS; i++)
4830 /* now add all entries that have an active state (active fonts) */
4831 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4833 int font = font_with_active_state[i].font_nr;
4834 int font_active = font_with_active_state[i].font_nr_active;
4836 ActiveFont[font] = font_active;
4839 global.autoplay_leveldir = NULL;
4840 global.convert_leveldir = NULL;
4841 global.create_images_dir = NULL;
4843 global.frames_per_second = 0;
4844 global.show_frames_per_second = FALSE;
4846 global.border_status = GAME_MODE_LOADING;
4847 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4849 global.use_envelope_request = FALSE;
4852 void Execute_Command(char *command)
4856 if (strEqual(command, "print graphicsinfo.conf"))
4858 Print("# You can configure additional/alternative image files here.\n");
4859 Print("# (The entries below are default and therefore commented out.)\n");
4861 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4863 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4866 for (i = 0; image_config[i].token != NULL; i++)
4867 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4868 image_config[i].value));
4872 else if (strEqual(command, "print soundsinfo.conf"))
4874 Print("# You can configure additional/alternative sound files here.\n");
4875 Print("# (The entries below are default and therefore commented out.)\n");
4877 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4879 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4882 for (i = 0; sound_config[i].token != NULL; i++)
4883 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4884 sound_config[i].value));
4888 else if (strEqual(command, "print musicinfo.conf"))
4890 Print("# You can configure additional/alternative music files here.\n");
4891 Print("# (The entries below are default and therefore commented out.)\n");
4893 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4895 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4898 for (i = 0; music_config[i].token != NULL; i++)
4899 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4900 music_config[i].value));
4904 else if (strEqual(command, "print editorsetup.conf"))
4906 Print("# You can configure your personal editor element list here.\n");
4907 Print("# (The entries below are default and therefore commented out.)\n");
4910 /* this is needed to be able to check element list for cascade elements */
4911 InitElementPropertiesStatic();
4912 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4914 PrintEditorElementList();
4918 else if (strEqual(command, "print helpanim.conf"))
4920 Print("# You can configure different element help animations here.\n");
4921 Print("# (The entries below are default and therefore commented out.)\n");
4924 for (i = 0; helpanim_config[i].token != NULL; i++)
4926 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4927 helpanim_config[i].value));
4929 if (strEqual(helpanim_config[i].token, "end"))
4935 else if (strEqual(command, "print helptext.conf"))
4937 Print("# You can configure different element help text here.\n");
4938 Print("# (The entries below are default and therefore commented out.)\n");
4941 for (i = 0; helptext_config[i].token != NULL; i++)
4942 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4943 helptext_config[i].value));
4947 else if (strPrefix(command, "dump level "))
4949 char *filename = &command[11];
4951 if (!fileExists(filename))
4952 Error(ERR_EXIT, "cannot open file '%s'", filename);
4954 LoadLevelFromFilename(&level, filename);
4959 else if (strPrefix(command, "dump tape "))
4961 char *filename = &command[10];
4963 if (!fileExists(filename))
4964 Error(ERR_EXIT, "cannot open file '%s'", filename);
4966 LoadTapeFromFilename(filename);
4971 else if (strPrefix(command, "autotest ") ||
4972 strPrefix(command, "autoplay ") ||
4973 strPrefix(command, "autoffwd ") ||
4974 strPrefix(command, "autowarp "))
4976 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4978 global.autoplay_mode =
4979 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
4980 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
4981 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
4982 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
4983 AUTOPLAY_MODE_NONE);
4985 while (*str_ptr != '\0') /* continue parsing string */
4987 /* cut leading whitespace from string, replace it by string terminator */
4988 while (*str_ptr == ' ' || *str_ptr == '\t')
4991 if (*str_ptr == '\0') /* end of string reached */
4994 if (global.autoplay_leveldir == NULL) /* read level set string */
4996 global.autoplay_leveldir = str_ptr;
4997 global.autoplay_all = TRUE; /* default: play all tapes */
4999 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5000 global.autoplay_level[i] = FALSE;
5002 else /* read level number string */
5004 int level_nr = atoi(str_ptr); /* get level_nr value */
5006 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5007 global.autoplay_level[level_nr] = TRUE;
5009 global.autoplay_all = FALSE;
5012 /* advance string pointer to the next whitespace (or end of string) */
5013 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5017 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5018 program.headless = TRUE;
5020 else if (strPrefix(command, "convert "))
5022 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5023 char *str_ptr = strchr(str_copy, ' ');
5025 global.convert_leveldir = str_copy;
5026 global.convert_level_nr = -1;
5028 if (str_ptr != NULL) /* level number follows */
5030 *str_ptr++ = '\0'; /* terminate leveldir string */
5031 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5034 program.headless = TRUE;
5036 else if (strPrefix(command, "create images "))
5038 global.create_images_dir = getStringCopy(&command[14]);
5040 if (access(global.create_images_dir, W_OK) != 0)
5041 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5042 global.create_images_dir);
5044 else if (strPrefix(command, "create CE image "))
5046 CreateCustomElementImages(&command[16]);
5052 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5056 static void InitSetup()
5058 LoadSetup(); /* global setup info */
5059 LoadSetup_AutoSetup(); /* global auto setup info */
5061 /* set some options from setup file */
5063 if (setup.options.verbose)
5064 options.verbose = TRUE;
5066 if (setup.debug.show_frames_per_second)
5067 global.show_frames_per_second = TRUE;
5070 static void InitGameInfo()
5072 game.restart_level = FALSE;
5073 game.restart_game_message = NULL;
5076 static void InitPlayerInfo()
5080 /* choose default local player */
5081 local_player = &stored_player[0];
5083 for (i = 0; i < MAX_PLAYERS; i++)
5085 stored_player[i].connected_locally = FALSE;
5086 stored_player[i].connected_network = FALSE;
5089 local_player->connected_locally = TRUE;
5092 static void InitArtworkInfo()
5097 static char *get_string_in_brackets(char *string)
5099 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5101 sprintf(string_in_brackets, "[%s]", string);
5103 return string_in_brackets;
5106 static char *get_level_id_suffix(int id_nr)
5108 char *id_suffix = checked_malloc(1 + 3 + 1);
5110 if (id_nr < 0 || id_nr > 999)
5113 sprintf(id_suffix, ".%03d", id_nr);
5118 static void InitArtworkConfig()
5120 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5122 NUM_GLOBAL_ANIM_TOKENS + 1];
5123 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5124 NUM_GLOBAL_ANIM_TOKENS + 1];
5125 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5126 NUM_GLOBAL_ANIM_TOKENS + 1];
5127 static char *action_id_suffix[NUM_ACTIONS + 1];
5128 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5129 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5130 static char *level_id_suffix[MAX_LEVELS + 1];
5131 static char *dummy[1] = { NULL };
5132 static char *ignore_generic_tokens[] =
5137 "program_copyright",
5142 static char **ignore_image_tokens;
5143 static char **ignore_sound_tokens;
5144 static char **ignore_music_tokens;
5145 int num_ignore_generic_tokens;
5146 int num_ignore_image_tokens;
5147 int num_ignore_sound_tokens;
5148 int num_ignore_music_tokens;
5151 /* dynamically determine list of generic tokens to be ignored */
5152 num_ignore_generic_tokens = 0;
5153 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5154 num_ignore_generic_tokens++;
5156 /* dynamically determine list of image tokens to be ignored */
5157 num_ignore_image_tokens = num_ignore_generic_tokens;
5158 for (i = 0; image_config_vars[i].token != NULL; i++)
5159 num_ignore_image_tokens++;
5160 ignore_image_tokens =
5161 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5162 for (i = 0; i < num_ignore_generic_tokens; i++)
5163 ignore_image_tokens[i] = ignore_generic_tokens[i];
5164 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5165 ignore_image_tokens[num_ignore_generic_tokens + i] =
5166 image_config_vars[i].token;
5167 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5169 /* dynamically determine list of sound tokens to be ignored */
5170 num_ignore_sound_tokens = num_ignore_generic_tokens;
5171 ignore_sound_tokens =
5172 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5173 for (i = 0; i < num_ignore_generic_tokens; i++)
5174 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5175 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5177 /* dynamically determine list of music tokens to be ignored */
5178 num_ignore_music_tokens = num_ignore_generic_tokens;
5179 ignore_music_tokens =
5180 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5181 for (i = 0; i < num_ignore_generic_tokens; i++)
5182 ignore_music_tokens[i] = ignore_generic_tokens[i];
5183 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5185 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5186 image_id_prefix[i] = element_info[i].token_name;
5187 for (i = 0; i < NUM_FONTS; i++)
5188 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5189 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5190 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5191 global_anim_info[i].token_name;
5192 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5194 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5195 sound_id_prefix[i] = element_info[i].token_name;
5196 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5197 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5198 get_string_in_brackets(element_info[i].class_name);
5199 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5200 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5201 global_anim_info[i].token_name;
5202 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5204 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5205 music_id_prefix[i] = music_prefix_info[i].prefix;
5206 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5207 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5208 global_anim_info[i].token_name;
5209 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5211 for (i = 0; i < NUM_ACTIONS; i++)
5212 action_id_suffix[i] = element_action_info[i].suffix;
5213 action_id_suffix[NUM_ACTIONS] = NULL;
5215 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5216 direction_id_suffix[i] = element_direction_info[i].suffix;
5217 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5219 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5220 special_id_suffix[i] = special_suffix_info[i].suffix;
5221 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5223 for (i = 0; i < MAX_LEVELS; i++)
5224 level_id_suffix[i] = get_level_id_suffix(i);
5225 level_id_suffix[MAX_LEVELS] = NULL;
5227 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5228 image_id_prefix, action_id_suffix, direction_id_suffix,
5229 special_id_suffix, ignore_image_tokens);
5230 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5231 sound_id_prefix, action_id_suffix, dummy,
5232 special_id_suffix, ignore_sound_tokens);
5233 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5234 music_id_prefix, action_id_suffix, special_id_suffix,
5235 level_id_suffix, ignore_music_tokens);
5238 static void InitMixer()
5245 static void InitVideoOverlay()
5247 // if virtual buttons are not loaded from setup file, repeat initializing
5248 // virtual buttons grid with default values now that video is initialized
5249 if (!setup.touch.grid_initialized)
5252 InitTileCursorInfo();
5256 void InitGfxBuffers()
5258 static int win_xsize_last = -1;
5259 static int win_ysize_last = -1;
5261 /* create additional image buffers for double-buffering and cross-fading */
5263 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5265 /* used to temporarily store the backbuffer -- only re-create if changed */
5266 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5267 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5269 win_xsize_last = WIN_XSIZE;
5270 win_ysize_last = WIN_YSIZE;
5273 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5274 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5275 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5276 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5278 /* initialize screen properties */
5279 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5280 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5282 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5283 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5284 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5285 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5286 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5287 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5289 /* required if door size definitions have changed */
5290 InitGraphicCompatibilityInfo_Doors();
5292 InitGfxBuffers_EM();
5293 InitGfxBuffers_SP();
5298 struct GraphicInfo *graphic_info_last = graphic_info;
5299 char *filename_font_initial = NULL;
5300 char *filename_anim_initial = NULL;
5301 Bitmap *bitmap_font_initial = NULL;
5305 /* determine settings for initial font (for displaying startup messages) */
5306 for (i = 0; image_config[i].token != NULL; i++)
5308 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5310 char font_token[128];
5313 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5314 len_font_token = strlen(font_token);
5316 if (strEqual(image_config[i].token, font_token))
5317 filename_font_initial = image_config[i].value;
5318 else if (strlen(image_config[i].token) > len_font_token &&
5319 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5321 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5322 font_initial[j].src_x = atoi(image_config[i].value);
5323 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5324 font_initial[j].src_y = atoi(image_config[i].value);
5325 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5326 font_initial[j].width = atoi(image_config[i].value);
5327 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5328 font_initial[j].height = atoi(image_config[i].value);
5333 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5335 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5336 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5339 if (filename_font_initial == NULL) /* should not happen */
5340 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5343 InitGfxCustomArtworkInfo();
5344 InitGfxOtherSettings();
5346 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5348 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5349 font_initial[j].bitmap = bitmap_font_initial;
5351 InitFontGraphicInfo();
5353 font_height = getFontHeight(FC_RED);
5355 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5356 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5357 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5360 DrawInitText("Loading graphics", 120, FC_GREEN);
5362 /* initialize settings for busy animation with default values */
5363 int parameter[NUM_GFX_ARGS];
5364 for (i = 0; i < NUM_GFX_ARGS; i++)
5365 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5366 image_config_suffix[i].token,
5367 image_config_suffix[i].type);
5369 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5370 int len_anim_token = strlen(anim_token);
5372 /* read settings for busy animation from default custom artwork config */
5373 char *gfx_config_filename = getPath3(options.graphics_directory,
5375 GRAPHICSINFO_FILENAME);
5377 if (fileExists(gfx_config_filename))
5379 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5381 if (setup_file_hash)
5383 char *filename = getHashEntry(setup_file_hash, anim_token);
5387 filename_anim_initial = getStringCopy(filename);
5389 for (j = 0; image_config_suffix[j].token != NULL; j++)
5391 int type = image_config_suffix[j].type;
5392 char *suffix = image_config_suffix[j].token;
5393 char *token = getStringCat2(anim_token, suffix);
5394 char *value = getHashEntry(setup_file_hash, token);
5396 checked_free(token);
5399 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5403 freeSetupFileHash(setup_file_hash);
5407 if (filename_anim_initial == NULL)
5409 /* read settings for busy animation from static default artwork config */
5410 for (i = 0; image_config[i].token != NULL; i++)
5412 if (strEqual(image_config[i].token, anim_token))
5413 filename_anim_initial = getStringCopy(image_config[i].value);
5414 else if (strlen(image_config[i].token) > len_anim_token &&
5415 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5417 for (j = 0; image_config_suffix[j].token != NULL; j++)
5419 if (strEqual(&image_config[i].token[len_anim_token],
5420 image_config_suffix[j].token))
5422 get_graphic_parameter_value(image_config[i].value,
5423 image_config_suffix[j].token,
5424 image_config_suffix[j].type);
5430 if (filename_anim_initial == NULL) /* should not happen */
5431 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5433 anim_initial.bitmaps =
5434 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5436 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5437 LoadCustomImage(filename_anim_initial);
5439 checked_free(filename_anim_initial);
5441 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5443 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5445 graphic_info = graphic_info_last;
5447 init.busy.width = anim_initial.width;
5448 init.busy.height = anim_initial.height;
5450 InitMenuDesignSettings_Static();
5452 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5453 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5454 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5455 InitGfxDrawTileCursorFunction(DrawTileCursor);
5457 gfx.fade_border_source_status = global.border_status;
5458 gfx.fade_border_target_status = global.border_status;
5459 gfx.masked_border_bitmap_ptr = backbuffer;
5461 /* use copy of busy animation to prevent change while reloading artwork */
5465 void InitGfxBackground()
5467 fieldbuffer = bitmap_db_field;
5468 SetDrawtoField(DRAW_TO_BACKBUFFER);
5470 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5472 redraw_mask = REDRAW_ALL;
5475 static void InitLevelInfo()
5477 LoadLevelInfo(); /* global level info */
5478 LoadLevelSetup_LastSeries(); /* last played series info */
5479 LoadLevelSetup_SeriesInfo(); /* last played level info */
5481 if (global.autoplay_leveldir &&
5482 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5484 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5485 global.autoplay_leveldir);
5486 if (leveldir_current == NULL)
5487 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5491 static void InitLevelArtworkInfo()
5493 LoadLevelArtworkInfo();
5496 static void InitImages()
5498 print_timestamp_init("InitImages");
5501 printf("::: leveldir_current->identifier == '%s'\n",
5502 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5503 printf("::: leveldir_current->graphics_path == '%s'\n",
5504 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5505 printf("::: leveldir_current->graphics_set == '%s'\n",
5506 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5507 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5508 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5511 setLevelArtworkDir(artwork.gfx_first);
5514 printf("::: leveldir_current->identifier == '%s'\n",
5515 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5516 printf("::: leveldir_current->graphics_path == '%s'\n",
5517 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5518 printf("::: leveldir_current->graphics_set == '%s'\n",
5519 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5520 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5521 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5525 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5526 leveldir_current->identifier,
5527 artwork.gfx_current_identifier,
5528 artwork.gfx_current->identifier,
5529 leveldir_current->graphics_set,
5530 leveldir_current->graphics_path);
5533 UPDATE_BUSY_STATE();
5535 ReloadCustomImages();
5536 print_timestamp_time("ReloadCustomImages");
5538 UPDATE_BUSY_STATE();
5540 LoadCustomElementDescriptions();
5541 print_timestamp_time("LoadCustomElementDescriptions");
5543 UPDATE_BUSY_STATE();
5545 LoadMenuDesignSettings();
5546 print_timestamp_time("LoadMenuDesignSettings");
5548 UPDATE_BUSY_STATE();
5550 ReinitializeGraphics();
5551 print_timestamp_time("ReinitializeGraphics");
5553 LoadMenuDesignSettings_AfterGraphics();
5554 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5556 UPDATE_BUSY_STATE();
5558 print_timestamp_done("InitImages");
5561 static void InitSound(char *identifier)
5563 print_timestamp_init("InitSound");
5565 if (identifier == NULL)
5566 identifier = artwork.snd_current->identifier;
5568 /* set artwork path to send it to the sound server process */
5569 setLevelArtworkDir(artwork.snd_first);
5571 InitReloadCustomSounds(identifier);
5572 print_timestamp_time("InitReloadCustomSounds");
5574 ReinitializeSounds();
5575 print_timestamp_time("ReinitializeSounds");
5577 print_timestamp_done("InitSound");
5580 static void InitMusic(char *identifier)
5582 print_timestamp_init("InitMusic");
5584 if (identifier == NULL)
5585 identifier = artwork.mus_current->identifier;
5587 /* set artwork path to send it to the sound server process */
5588 setLevelArtworkDir(artwork.mus_first);
5590 InitReloadCustomMusic(identifier);
5591 print_timestamp_time("InitReloadCustomMusic");
5593 ReinitializeMusic();
5594 print_timestamp_time("ReinitializeMusic");
5596 print_timestamp_done("InitMusic");
5599 static void InitArtworkDone()
5601 if (program.headless)
5604 InitGlobalAnimations();
5607 void InitNetworkSettings()
5609 InitNetworkInfo(options.network || setup.network_mode,
5612 options.server_host,
5613 options.server_port);
5616 void InitNetworkServer()
5618 if (!network.enabled || network.connected)
5621 LimitScreenUpdates(FALSE);
5623 if (!ConnectToServer(network.server_host, network.server_port))
5625 network.enabled = FALSE;
5627 setup.network_mode = FALSE;
5631 SendToServer_PlayerName(setup.player_name);
5632 SendToServer_ProtocolVersion();
5633 SendToServer_NrWanted(setup.network_player_nr + 1);
5635 network.connected = TRUE;
5638 /* short time to recognize result of network initialization */
5639 Delay_WithScreenUpdates(1000);
5642 static boolean CheckArtworkConfigForCustomElements(char *filename)
5644 SetupFileHash *setup_file_hash;
5645 boolean redefined_ce_found = FALSE;
5647 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5649 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5651 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5653 char *token = HASH_ITERATION_TOKEN(itr);
5655 if (strPrefix(token, "custom_"))
5657 redefined_ce_found = TRUE;
5662 END_HASH_ITERATION(setup_file_hash, itr)
5664 freeSetupFileHash(setup_file_hash);
5667 return redefined_ce_found;
5670 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5672 char *filename_base, *filename_local;
5673 boolean redefined_ce_found = FALSE;
5675 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5678 printf("::: leveldir_current->identifier == '%s'\n",
5679 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5680 printf("::: leveldir_current->graphics_path == '%s'\n",
5681 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5682 printf("::: leveldir_current->graphics_set == '%s'\n",
5683 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5684 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5685 leveldir_current == NULL ? "[NULL]" :
5686 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5689 /* first look for special artwork configured in level series config */
5690 filename_base = getCustomArtworkLevelConfigFilename(type);
5693 printf("::: filename_base == '%s'\n", filename_base);
5696 if (fileExists(filename_base))
5697 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5699 filename_local = getCustomArtworkConfigFilename(type);
5702 printf("::: filename_local == '%s'\n", filename_local);
5705 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5706 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5709 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5712 return redefined_ce_found;
5715 static void InitOverrideArtwork()
5717 boolean redefined_ce_found = FALSE;
5719 /* to check if this level set redefines any CEs, do not use overriding */
5720 gfx.override_level_graphics = FALSE;
5721 gfx.override_level_sounds = FALSE;
5722 gfx.override_level_music = FALSE;
5724 /* now check if this level set has definitions for custom elements */
5725 if (setup.override_level_graphics == AUTO ||
5726 setup.override_level_sounds == AUTO ||
5727 setup.override_level_music == AUTO)
5728 redefined_ce_found =
5729 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5730 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5731 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5734 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5737 if (redefined_ce_found)
5739 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5740 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5741 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5742 gfx.override_level_music = (setup.override_level_music == TRUE);
5746 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5747 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5748 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5749 gfx.override_level_music = (setup.override_level_music != FALSE);
5753 printf("::: => %d, %d, %d\n",
5754 gfx.override_level_graphics,
5755 gfx.override_level_sounds,
5756 gfx.override_level_music);
5760 static char *getNewArtworkIdentifier(int type)
5762 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5763 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5764 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5765 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5766 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5767 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5768 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5769 char *leveldir_identifier = leveldir_current->identifier;
5770 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5771 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5772 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5773 char *artwork_current_identifier;
5774 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5776 /* leveldir_current may be invalid (level group, parent link) */
5777 if (!validLevelSeries(leveldir_current))
5780 /* 1st step: determine artwork set to be activated in descending order:
5781 --------------------------------------------------------------------
5782 1. setup artwork (when configured to override everything else)
5783 2. artwork set configured in "levelinfo.conf" of current level set
5784 (artwork in level directory will have priority when loading later)
5785 3. artwork in level directory (stored in artwork sub-directory)
5786 4. setup artwork (currently configured in setup menu) */
5788 if (setup_override_artwork)
5789 artwork_current_identifier = setup_artwork_set;
5790 else if (leveldir_artwork_set != NULL)
5791 artwork_current_identifier = leveldir_artwork_set;
5792 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5793 artwork_current_identifier = leveldir_identifier;
5795 artwork_current_identifier = setup_artwork_set;
5798 /* 2nd step: check if it is really needed to reload artwork set
5799 ------------------------------------------------------------ */
5801 /* ---------- reload if level set and also artwork set has changed ------- */
5802 if (leveldir_current_identifier[type] != leveldir_identifier &&
5803 (last_has_level_artwork_set[type] || has_level_artwork_set))
5804 artwork_new_identifier = artwork_current_identifier;
5806 leveldir_current_identifier[type] = leveldir_identifier;
5807 last_has_level_artwork_set[type] = has_level_artwork_set;
5809 /* ---------- reload if "override artwork" setting has changed ----------- */
5810 if (last_override_level_artwork[type] != setup_override_artwork)
5811 artwork_new_identifier = artwork_current_identifier;
5813 last_override_level_artwork[type] = setup_override_artwork;
5815 /* ---------- reload if current artwork identifier has changed ----------- */
5816 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5817 artwork_current_identifier))
5818 artwork_new_identifier = artwork_current_identifier;
5820 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5822 /* ---------- do not reload directly after starting ---------------------- */
5823 if (!initialized[type])
5824 artwork_new_identifier = NULL;
5826 initialized[type] = TRUE;
5828 return artwork_new_identifier;
5831 void ReloadCustomArtwork(int force_reload)
5833 int last_game_status = game_status; /* save current game status */
5834 char *gfx_new_identifier;
5835 char *snd_new_identifier;
5836 char *mus_new_identifier;
5837 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5838 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5839 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5840 boolean reload_needed;
5842 InitOverrideArtwork();
5844 force_reload_gfx |= AdjustGraphicsForEMC();
5846 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5847 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5848 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5850 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5851 snd_new_identifier != NULL || force_reload_snd ||
5852 mus_new_identifier != NULL || force_reload_mus);
5857 print_timestamp_init("ReloadCustomArtwork");
5859 SetGameStatus(GAME_MODE_LOADING);
5861 FadeOut(REDRAW_ALL);
5863 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5864 print_timestamp_time("ClearRectangle");
5868 if (gfx_new_identifier != NULL || force_reload_gfx)
5871 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5872 artwork.gfx_current_identifier,
5874 artwork.gfx_current->identifier,
5875 leveldir_current->graphics_set);
5879 print_timestamp_time("InitImages");
5882 if (snd_new_identifier != NULL || force_reload_snd)
5884 InitSound(snd_new_identifier);
5885 print_timestamp_time("InitSound");
5888 if (mus_new_identifier != NULL || force_reload_mus)
5890 InitMusic(mus_new_identifier);
5891 print_timestamp_time("InitMusic");
5896 SetGameStatus(last_game_status); /* restore current game status */
5898 init_last = init; /* switch to new busy animation */
5900 FadeOut(REDRAW_ALL);
5902 RedrawGlobalBorder();
5904 /* force redraw of (open or closed) door graphics */
5905 SetDoorState(DOOR_OPEN_ALL);
5906 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5908 FadeSetEnterScreen();
5909 FadeSkipNextFadeOut();
5911 print_timestamp_done("ReloadCustomArtwork");
5913 LimitScreenUpdates(FALSE);
5916 void KeyboardAutoRepeatOffUnlessAutoplay()
5918 if (global.autoplay_leveldir == NULL)
5919 KeyboardAutoRepeatOff();
5922 void DisplayExitMessage(char *format, va_list ap)
5924 // also check for initialized video (headless flag may be temporarily unset)
5925 if (program.headless || !video.initialized)
5928 // check if draw buffer and fonts for exit message are already available
5929 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5932 int font_1 = FC_RED;
5933 int font_2 = FC_YELLOW;
5934 int font_3 = FC_BLUE;
5935 int font_width = getFontWidth(font_2);
5936 int font_height = getFontHeight(font_2);
5939 int sxsize = WIN_XSIZE - 2 * sx;
5940 int sysize = WIN_YSIZE - 2 * sy;
5941 int line_length = sxsize / font_width;
5942 int max_lines = sysize / font_height;
5943 int num_lines_printed;
5947 gfx.sxsize = sxsize;
5948 gfx.sysize = sysize;
5952 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5954 DrawTextSCentered(sy, font_1, "Fatal error:");
5955 sy += 3 * font_height;;
5958 DrawTextBufferVA(sx, sy, format, ap, font_2,
5959 line_length, line_length, max_lines,
5960 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5961 sy += (num_lines_printed + 3) * font_height;
5963 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5964 sy += 3 * font_height;
5967 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5968 line_length, line_length, max_lines,
5969 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5971 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5973 redraw_mask = REDRAW_ALL;
5975 /* force drawing exit message even if screen updates are currently limited */
5976 LimitScreenUpdates(FALSE);
5980 /* deactivate toons on error message screen */
5981 setup.toons = FALSE;
5983 WaitForEventToContinue();
5987 /* ========================================================================= */
5989 /* ========================================================================= */
5993 print_timestamp_init("OpenAll");
5995 SetGameStatus(GAME_MODE_LOADING);
5999 InitGlobal(); /* initialize some global variables */
6001 print_timestamp_time("[init global stuff]");
6005 print_timestamp_time("[init setup/config stuff (1)]");
6009 if (options.execute_command)
6010 Execute_Command(options.execute_command);
6012 InitNetworkSettings();
6014 if (network.serveronly)
6016 #if defined(PLATFORM_UNIX)
6017 NetworkServer(network.server_port, TRUE);
6019 Error(ERR_WARN, "networking only supported in Unix version");
6022 exit(0); /* never reached, server loops forever */
6026 print_timestamp_time("[init setup/config stuff (2)]");
6028 print_timestamp_time("[init setup/config stuff (3)]");
6029 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6030 print_timestamp_time("[init setup/config stuff (4)]");
6031 InitArtworkConfig(); /* needed before forking sound child process */
6032 print_timestamp_time("[init setup/config stuff (5)]");
6034 print_timestamp_time("[init setup/config stuff (6)]");
6036 InitRND(NEW_RANDOMIZE);
6037 InitSimpleRandom(NEW_RANDOMIZE);
6041 print_timestamp_time("[init setup/config stuff]");
6043 InitVideoDefaults();
6045 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6048 print_timestamp_time("[init video stuff]");
6050 InitElementPropertiesStatic();
6051 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6052 InitElementPropertiesGfxElement();
6054 print_timestamp_time("[init element properties stuff]");
6058 print_timestamp_time("InitGfx");
6061 print_timestamp_time("InitLevelInfo");
6063 InitLevelArtworkInfo();
6064 print_timestamp_time("InitLevelArtworkInfo");
6066 InitOverrideArtwork(); /* needs to know current level directory */
6067 print_timestamp_time("InitOverrideArtwork");
6069 InitImages(); /* needs to know current level directory */
6070 print_timestamp_time("InitImages");
6072 InitSound(NULL); /* needs to know current level directory */
6073 print_timestamp_time("InitSound");
6075 InitMusic(NULL); /* needs to know current level directory */
6076 print_timestamp_time("InitMusic");
6080 InitGfxBackground();
6086 if (global.autoplay_leveldir)
6091 else if (global.convert_leveldir)
6096 else if (global.create_images_dir)
6098 CreateLevelSketchImages();
6102 InitNetworkServer();
6104 SetGameStatus(GAME_MODE_MAIN);
6106 FadeSetEnterScreen();
6107 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6108 FadeSkipNextFadeOut();
6110 print_timestamp_time("[post-artwork]");
6112 print_timestamp_done("OpenAll");
6117 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6119 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6120 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6121 #if defined(PLATFORM_ANDROID)
6122 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6123 SDL_AndroidGetInternalStoragePath());
6124 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6125 SDL_AndroidGetExternalStoragePath());
6126 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6127 (SDL_AndroidGetExternalStorageState() &
6128 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6129 SDL_AndroidGetExternalStorageState() &
6130 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6135 void CloseAllAndExit(int exit_value)
6140 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6147 #if defined(TARGET_SDL)
6148 #if defined(TARGET_SDL2)
6150 // set a flag to tell the network server thread to quit and wait for it
6151 // using SDL_WaitThread()
6153 if (network_server) /* terminate network server */
6154 SDL_KillThread(server_thread);
6158 CloseVideoDisplay();
6159 ClosePlatformDependentStuff();
6161 if (exit_value != 0 && !options.execute_command)
6163 /* fall back to default level set (current set may have caused an error) */
6164 SaveLevelSetup_LastSeries_Deactivate();
6166 /* tell user where to find error log file which may contain more details */
6167 // (error notification now directly displayed on screen inside R'n'D
6168 // NotifyUserAboutErrorFile(); /* currently only works for Windows */