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);
5055 /* disable networking if any valid command was recognized */
5056 options.network = setup.network_mode = FALSE;
5059 static void InitSetup()
5061 LoadSetup(); /* global setup info */
5062 LoadSetup_AutoSetup(); /* global auto setup info */
5064 /* set some options from setup file */
5066 if (setup.options.verbose)
5067 options.verbose = TRUE;
5069 if (setup.debug.show_frames_per_second)
5070 global.show_frames_per_second = TRUE;
5073 static void InitGameInfo()
5075 game.restart_level = FALSE;
5076 game.restart_game_message = NULL;
5079 static void InitPlayerInfo()
5083 /* choose default local player */
5084 local_player = &stored_player[0];
5086 for (i = 0; i < MAX_PLAYERS; i++)
5088 stored_player[i].connected_locally = FALSE;
5089 stored_player[i].connected_network = FALSE;
5092 local_player->connected_locally = TRUE;
5095 static void InitArtworkInfo()
5100 static char *get_string_in_brackets(char *string)
5102 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5104 sprintf(string_in_brackets, "[%s]", string);
5106 return string_in_brackets;
5109 static char *get_level_id_suffix(int id_nr)
5111 char *id_suffix = checked_malloc(1 + 3 + 1);
5113 if (id_nr < 0 || id_nr > 999)
5116 sprintf(id_suffix, ".%03d", id_nr);
5121 static void InitArtworkConfig()
5123 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5125 NUM_GLOBAL_ANIM_TOKENS + 1];
5126 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5127 NUM_GLOBAL_ANIM_TOKENS + 1];
5128 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5129 NUM_GLOBAL_ANIM_TOKENS + 1];
5130 static char *action_id_suffix[NUM_ACTIONS + 1];
5131 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5132 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5133 static char *level_id_suffix[MAX_LEVELS + 1];
5134 static char *dummy[1] = { NULL };
5135 static char *ignore_generic_tokens[] =
5140 "program_copyright",
5145 static char **ignore_image_tokens;
5146 static char **ignore_sound_tokens;
5147 static char **ignore_music_tokens;
5148 int num_ignore_generic_tokens;
5149 int num_ignore_image_tokens;
5150 int num_ignore_sound_tokens;
5151 int num_ignore_music_tokens;
5154 /* dynamically determine list of generic tokens to be ignored */
5155 num_ignore_generic_tokens = 0;
5156 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5157 num_ignore_generic_tokens++;
5159 /* dynamically determine list of image tokens to be ignored */
5160 num_ignore_image_tokens = num_ignore_generic_tokens;
5161 for (i = 0; image_config_vars[i].token != NULL; i++)
5162 num_ignore_image_tokens++;
5163 ignore_image_tokens =
5164 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5165 for (i = 0; i < num_ignore_generic_tokens; i++)
5166 ignore_image_tokens[i] = ignore_generic_tokens[i];
5167 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5168 ignore_image_tokens[num_ignore_generic_tokens + i] =
5169 image_config_vars[i].token;
5170 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5172 /* dynamically determine list of sound tokens to be ignored */
5173 num_ignore_sound_tokens = num_ignore_generic_tokens;
5174 ignore_sound_tokens =
5175 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5176 for (i = 0; i < num_ignore_generic_tokens; i++)
5177 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5178 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5180 /* dynamically determine list of music tokens to be ignored */
5181 num_ignore_music_tokens = num_ignore_generic_tokens;
5182 ignore_music_tokens =
5183 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5184 for (i = 0; i < num_ignore_generic_tokens; i++)
5185 ignore_music_tokens[i] = ignore_generic_tokens[i];
5186 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5188 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5189 image_id_prefix[i] = element_info[i].token_name;
5190 for (i = 0; i < NUM_FONTS; i++)
5191 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5192 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5193 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5194 global_anim_info[i].token_name;
5195 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5197 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5198 sound_id_prefix[i] = element_info[i].token_name;
5199 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5200 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5201 get_string_in_brackets(element_info[i].class_name);
5202 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5203 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5204 global_anim_info[i].token_name;
5205 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5207 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5208 music_id_prefix[i] = music_prefix_info[i].prefix;
5209 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5210 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5211 global_anim_info[i].token_name;
5212 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5214 for (i = 0; i < NUM_ACTIONS; i++)
5215 action_id_suffix[i] = element_action_info[i].suffix;
5216 action_id_suffix[NUM_ACTIONS] = NULL;
5218 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5219 direction_id_suffix[i] = element_direction_info[i].suffix;
5220 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5222 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5223 special_id_suffix[i] = special_suffix_info[i].suffix;
5224 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5226 for (i = 0; i < MAX_LEVELS; i++)
5227 level_id_suffix[i] = get_level_id_suffix(i);
5228 level_id_suffix[MAX_LEVELS] = NULL;
5230 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5231 image_id_prefix, action_id_suffix, direction_id_suffix,
5232 special_id_suffix, ignore_image_tokens);
5233 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5234 sound_id_prefix, action_id_suffix, dummy,
5235 special_id_suffix, ignore_sound_tokens);
5236 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5237 music_id_prefix, action_id_suffix, special_id_suffix,
5238 level_id_suffix, ignore_music_tokens);
5241 static void InitMixer()
5248 static void InitVideoOverlay()
5250 // if virtual buttons are not loaded from setup file, repeat initializing
5251 // virtual buttons grid with default values now that video is initialized
5252 if (!setup.touch.grid_initialized)
5255 InitTileCursorInfo();
5259 void InitGfxBuffers()
5261 static int win_xsize_last = -1;
5262 static int win_ysize_last = -1;
5264 /* create additional image buffers for double-buffering and cross-fading */
5266 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5268 /* used to temporarily store the backbuffer -- only re-create if changed */
5269 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5270 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5272 win_xsize_last = WIN_XSIZE;
5273 win_ysize_last = WIN_YSIZE;
5276 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5277 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5278 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5279 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5281 /* initialize screen properties */
5282 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5283 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5285 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5286 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5287 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5288 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5289 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5290 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5292 /* required if door size definitions have changed */
5293 InitGraphicCompatibilityInfo_Doors();
5295 InitGfxBuffers_EM();
5296 InitGfxBuffers_SP();
5301 struct GraphicInfo *graphic_info_last = graphic_info;
5302 char *filename_font_initial = NULL;
5303 char *filename_anim_initial = NULL;
5304 Bitmap *bitmap_font_initial = NULL;
5308 /* determine settings for initial font (for displaying startup messages) */
5309 for (i = 0; image_config[i].token != NULL; i++)
5311 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5313 char font_token[128];
5316 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5317 len_font_token = strlen(font_token);
5319 if (strEqual(image_config[i].token, font_token))
5320 filename_font_initial = image_config[i].value;
5321 else if (strlen(image_config[i].token) > len_font_token &&
5322 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5324 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5325 font_initial[j].src_x = atoi(image_config[i].value);
5326 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5327 font_initial[j].src_y = atoi(image_config[i].value);
5328 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5329 font_initial[j].width = atoi(image_config[i].value);
5330 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5331 font_initial[j].height = atoi(image_config[i].value);
5336 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5338 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5339 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5342 if (filename_font_initial == NULL) /* should not happen */
5343 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5346 InitGfxCustomArtworkInfo();
5347 InitGfxOtherSettings();
5349 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5351 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5352 font_initial[j].bitmap = bitmap_font_initial;
5354 InitFontGraphicInfo();
5356 font_height = getFontHeight(FC_RED);
5358 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5359 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5360 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5363 DrawInitText("Loading graphics", 120, FC_GREEN);
5365 /* initialize settings for busy animation with default values */
5366 int parameter[NUM_GFX_ARGS];
5367 for (i = 0; i < NUM_GFX_ARGS; i++)
5368 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5369 image_config_suffix[i].token,
5370 image_config_suffix[i].type);
5372 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5373 int len_anim_token = strlen(anim_token);
5375 /* read settings for busy animation from default custom artwork config */
5376 char *gfx_config_filename = getPath3(options.graphics_directory,
5378 GRAPHICSINFO_FILENAME);
5380 if (fileExists(gfx_config_filename))
5382 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5384 if (setup_file_hash)
5386 char *filename = getHashEntry(setup_file_hash, anim_token);
5390 filename_anim_initial = getStringCopy(filename);
5392 for (j = 0; image_config_suffix[j].token != NULL; j++)
5394 int type = image_config_suffix[j].type;
5395 char *suffix = image_config_suffix[j].token;
5396 char *token = getStringCat2(anim_token, suffix);
5397 char *value = getHashEntry(setup_file_hash, token);
5399 checked_free(token);
5402 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5406 freeSetupFileHash(setup_file_hash);
5410 if (filename_anim_initial == NULL)
5412 /* read settings for busy animation from static default artwork config */
5413 for (i = 0; image_config[i].token != NULL; i++)
5415 if (strEqual(image_config[i].token, anim_token))
5416 filename_anim_initial = getStringCopy(image_config[i].value);
5417 else if (strlen(image_config[i].token) > len_anim_token &&
5418 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5420 for (j = 0; image_config_suffix[j].token != NULL; j++)
5422 if (strEqual(&image_config[i].token[len_anim_token],
5423 image_config_suffix[j].token))
5425 get_graphic_parameter_value(image_config[i].value,
5426 image_config_suffix[j].token,
5427 image_config_suffix[j].type);
5433 if (filename_anim_initial == NULL) /* should not happen */
5434 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5436 anim_initial.bitmaps =
5437 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5439 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5440 LoadCustomImage(filename_anim_initial);
5442 checked_free(filename_anim_initial);
5444 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5446 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5448 graphic_info = graphic_info_last;
5450 init.busy.width = anim_initial.width;
5451 init.busy.height = anim_initial.height;
5453 InitMenuDesignSettings_Static();
5455 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5456 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5457 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5458 InitGfxDrawTileCursorFunction(DrawTileCursor);
5460 gfx.fade_border_source_status = global.border_status;
5461 gfx.fade_border_target_status = global.border_status;
5462 gfx.masked_border_bitmap_ptr = backbuffer;
5464 /* use copy of busy animation to prevent change while reloading artwork */
5468 void InitGfxBackground()
5470 fieldbuffer = bitmap_db_field;
5471 SetDrawtoField(DRAW_TO_BACKBUFFER);
5473 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5475 redraw_mask = REDRAW_ALL;
5478 static void InitLevelInfo()
5480 LoadLevelInfo(); /* global level info */
5481 LoadLevelSetup_LastSeries(); /* last played series info */
5482 LoadLevelSetup_SeriesInfo(); /* last played level info */
5484 if (global.autoplay_leveldir &&
5485 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5487 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5488 global.autoplay_leveldir);
5489 if (leveldir_current == NULL)
5490 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5494 static void InitLevelArtworkInfo()
5496 LoadLevelArtworkInfo();
5499 static void InitImages()
5501 print_timestamp_init("InitImages");
5504 printf("::: leveldir_current->identifier == '%s'\n",
5505 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5506 printf("::: leveldir_current->graphics_path == '%s'\n",
5507 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5508 printf("::: leveldir_current->graphics_set == '%s'\n",
5509 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5510 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5511 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5514 setLevelArtworkDir(artwork.gfx_first);
5517 printf("::: leveldir_current->identifier == '%s'\n",
5518 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5519 printf("::: leveldir_current->graphics_path == '%s'\n",
5520 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5521 printf("::: leveldir_current->graphics_set == '%s'\n",
5522 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5523 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5524 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5528 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5529 leveldir_current->identifier,
5530 artwork.gfx_current_identifier,
5531 artwork.gfx_current->identifier,
5532 leveldir_current->graphics_set,
5533 leveldir_current->graphics_path);
5536 UPDATE_BUSY_STATE();
5538 ReloadCustomImages();
5539 print_timestamp_time("ReloadCustomImages");
5541 UPDATE_BUSY_STATE();
5543 LoadCustomElementDescriptions();
5544 print_timestamp_time("LoadCustomElementDescriptions");
5546 UPDATE_BUSY_STATE();
5548 LoadMenuDesignSettings();
5549 print_timestamp_time("LoadMenuDesignSettings");
5551 UPDATE_BUSY_STATE();
5553 ReinitializeGraphics();
5554 print_timestamp_time("ReinitializeGraphics");
5556 LoadMenuDesignSettings_AfterGraphics();
5557 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5559 UPDATE_BUSY_STATE();
5561 print_timestamp_done("InitImages");
5564 static void InitSound(char *identifier)
5566 print_timestamp_init("InitSound");
5568 if (identifier == NULL)
5569 identifier = artwork.snd_current->identifier;
5571 /* set artwork path to send it to the sound server process */
5572 setLevelArtworkDir(artwork.snd_first);
5574 InitReloadCustomSounds(identifier);
5575 print_timestamp_time("InitReloadCustomSounds");
5577 ReinitializeSounds();
5578 print_timestamp_time("ReinitializeSounds");
5580 print_timestamp_done("InitSound");
5583 static void InitMusic(char *identifier)
5585 print_timestamp_init("InitMusic");
5587 if (identifier == NULL)
5588 identifier = artwork.mus_current->identifier;
5590 /* set artwork path to send it to the sound server process */
5591 setLevelArtworkDir(artwork.mus_first);
5593 InitReloadCustomMusic(identifier);
5594 print_timestamp_time("InitReloadCustomMusic");
5596 ReinitializeMusic();
5597 print_timestamp_time("ReinitializeMusic");
5599 print_timestamp_done("InitMusic");
5602 static void InitArtworkDone()
5604 if (program.headless)
5607 InitGlobalAnimations();
5610 void InitNetworkSettings()
5612 InitNetworkInfo(options.network || setup.network_mode,
5615 options.server_host,
5616 options.server_port);
5619 void InitNetworkServer()
5621 if (!network.enabled || network.connected)
5624 LimitScreenUpdates(FALSE);
5626 if (!ConnectToServer(network.server_host, network.server_port))
5628 network.enabled = FALSE;
5630 setup.network_mode = FALSE;
5634 SendToServer_ProtocolVersion();
5635 SendToServer_PlayerName(setup.player_name);
5636 SendToServer_NrWanted(setup.network_player_nr + 1);
5638 network.connected = TRUE;
5641 /* short time to recognize result of network initialization */
5642 Delay_WithScreenUpdates(1000);
5645 static boolean CheckArtworkConfigForCustomElements(char *filename)
5647 SetupFileHash *setup_file_hash;
5648 boolean redefined_ce_found = FALSE;
5650 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5652 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5654 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5656 char *token = HASH_ITERATION_TOKEN(itr);
5658 if (strPrefix(token, "custom_"))
5660 redefined_ce_found = TRUE;
5665 END_HASH_ITERATION(setup_file_hash, itr)
5667 freeSetupFileHash(setup_file_hash);
5670 return redefined_ce_found;
5673 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5675 char *filename_base, *filename_local;
5676 boolean redefined_ce_found = FALSE;
5678 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5681 printf("::: leveldir_current->identifier == '%s'\n",
5682 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5683 printf("::: leveldir_current->graphics_path == '%s'\n",
5684 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5685 printf("::: leveldir_current->graphics_set == '%s'\n",
5686 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5687 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5688 leveldir_current == NULL ? "[NULL]" :
5689 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5692 /* first look for special artwork configured in level series config */
5693 filename_base = getCustomArtworkLevelConfigFilename(type);
5696 printf("::: filename_base == '%s'\n", filename_base);
5699 if (fileExists(filename_base))
5700 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5702 filename_local = getCustomArtworkConfigFilename(type);
5705 printf("::: filename_local == '%s'\n", filename_local);
5708 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5709 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5712 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5715 return redefined_ce_found;
5718 static void InitOverrideArtwork()
5720 boolean redefined_ce_found = FALSE;
5722 /* to check if this level set redefines any CEs, do not use overriding */
5723 gfx.override_level_graphics = FALSE;
5724 gfx.override_level_sounds = FALSE;
5725 gfx.override_level_music = FALSE;
5727 /* now check if this level set has definitions for custom elements */
5728 if (setup.override_level_graphics == AUTO ||
5729 setup.override_level_sounds == AUTO ||
5730 setup.override_level_music == AUTO)
5731 redefined_ce_found =
5732 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5733 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5734 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5737 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5740 if (redefined_ce_found)
5742 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5743 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5744 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5745 gfx.override_level_music = (setup.override_level_music == TRUE);
5749 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5750 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5751 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5752 gfx.override_level_music = (setup.override_level_music != FALSE);
5756 printf("::: => %d, %d, %d\n",
5757 gfx.override_level_graphics,
5758 gfx.override_level_sounds,
5759 gfx.override_level_music);
5763 static char *getNewArtworkIdentifier(int type)
5765 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5766 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5767 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5768 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5769 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5770 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5771 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5772 char *leveldir_identifier = leveldir_current->identifier;
5773 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5774 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5775 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5776 char *artwork_current_identifier;
5777 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5779 /* leveldir_current may be invalid (level group, parent link) */
5780 if (!validLevelSeries(leveldir_current))
5783 /* 1st step: determine artwork set to be activated in descending order:
5784 --------------------------------------------------------------------
5785 1. setup artwork (when configured to override everything else)
5786 2. artwork set configured in "levelinfo.conf" of current level set
5787 (artwork in level directory will have priority when loading later)
5788 3. artwork in level directory (stored in artwork sub-directory)
5789 4. setup artwork (currently configured in setup menu) */
5791 if (setup_override_artwork)
5792 artwork_current_identifier = setup_artwork_set;
5793 else if (leveldir_artwork_set != NULL)
5794 artwork_current_identifier = leveldir_artwork_set;
5795 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5796 artwork_current_identifier = leveldir_identifier;
5798 artwork_current_identifier = setup_artwork_set;
5801 /* 2nd step: check if it is really needed to reload artwork set
5802 ------------------------------------------------------------ */
5804 /* ---------- reload if level set and also artwork set has changed ------- */
5805 if (leveldir_current_identifier[type] != leveldir_identifier &&
5806 (last_has_level_artwork_set[type] || has_level_artwork_set))
5807 artwork_new_identifier = artwork_current_identifier;
5809 leveldir_current_identifier[type] = leveldir_identifier;
5810 last_has_level_artwork_set[type] = has_level_artwork_set;
5812 /* ---------- reload if "override artwork" setting has changed ----------- */
5813 if (last_override_level_artwork[type] != setup_override_artwork)
5814 artwork_new_identifier = artwork_current_identifier;
5816 last_override_level_artwork[type] = setup_override_artwork;
5818 /* ---------- reload if current artwork identifier has changed ----------- */
5819 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5820 artwork_current_identifier))
5821 artwork_new_identifier = artwork_current_identifier;
5823 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5825 /* ---------- do not reload directly after starting ---------------------- */
5826 if (!initialized[type])
5827 artwork_new_identifier = NULL;
5829 initialized[type] = TRUE;
5831 return artwork_new_identifier;
5834 void ReloadCustomArtwork(int force_reload)
5836 int last_game_status = game_status; /* save current game status */
5837 char *gfx_new_identifier;
5838 char *snd_new_identifier;
5839 char *mus_new_identifier;
5840 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5841 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5842 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5843 boolean reload_needed;
5845 InitOverrideArtwork();
5847 force_reload_gfx |= AdjustGraphicsForEMC();
5849 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5850 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5851 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5853 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5854 snd_new_identifier != NULL || force_reload_snd ||
5855 mus_new_identifier != NULL || force_reload_mus);
5860 print_timestamp_init("ReloadCustomArtwork");
5862 SetGameStatus(GAME_MODE_LOADING);
5864 FadeOut(REDRAW_ALL);
5866 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5867 print_timestamp_time("ClearRectangle");
5871 if (gfx_new_identifier != NULL || force_reload_gfx)
5874 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5875 artwork.gfx_current_identifier,
5877 artwork.gfx_current->identifier,
5878 leveldir_current->graphics_set);
5882 print_timestamp_time("InitImages");
5885 if (snd_new_identifier != NULL || force_reload_snd)
5887 InitSound(snd_new_identifier);
5888 print_timestamp_time("InitSound");
5891 if (mus_new_identifier != NULL || force_reload_mus)
5893 InitMusic(mus_new_identifier);
5894 print_timestamp_time("InitMusic");
5899 SetGameStatus(last_game_status); /* restore current game status */
5901 init_last = init; /* switch to new busy animation */
5903 FadeOut(REDRAW_ALL);
5905 RedrawGlobalBorder();
5907 /* force redraw of (open or closed) door graphics */
5908 SetDoorState(DOOR_OPEN_ALL);
5909 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5911 FadeSetEnterScreen();
5912 FadeSkipNextFadeOut();
5914 print_timestamp_done("ReloadCustomArtwork");
5916 LimitScreenUpdates(FALSE);
5919 void KeyboardAutoRepeatOffUnlessAutoplay()
5921 if (global.autoplay_leveldir == NULL)
5922 KeyboardAutoRepeatOff();
5925 void DisplayExitMessage(char *format, va_list ap)
5927 // also check for initialized video (headless flag may be temporarily unset)
5928 if (program.headless || !video.initialized)
5931 // check if draw buffer and fonts for exit message are already available
5932 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5935 int font_1 = FC_RED;
5936 int font_2 = FC_YELLOW;
5937 int font_3 = FC_BLUE;
5938 int font_width = getFontWidth(font_2);
5939 int font_height = getFontHeight(font_2);
5942 int sxsize = WIN_XSIZE - 2 * sx;
5943 int sysize = WIN_YSIZE - 2 * sy;
5944 int line_length = sxsize / font_width;
5945 int max_lines = sysize / font_height;
5946 int num_lines_printed;
5950 gfx.sxsize = sxsize;
5951 gfx.sysize = sysize;
5955 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5957 DrawTextSCentered(sy, font_1, "Fatal error:");
5958 sy += 3 * font_height;;
5961 DrawTextBufferVA(sx, sy, format, ap, font_2,
5962 line_length, line_length, max_lines,
5963 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5964 sy += (num_lines_printed + 3) * font_height;
5966 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5967 sy += 3 * font_height;
5970 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5971 line_length, line_length, max_lines,
5972 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5974 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5976 redraw_mask = REDRAW_ALL;
5978 /* force drawing exit message even if screen updates are currently limited */
5979 LimitScreenUpdates(FALSE);
5983 /* deactivate toons on error message screen */
5984 setup.toons = FALSE;
5986 WaitForEventToContinue();
5990 /* ========================================================================= */
5992 /* ========================================================================= */
5996 print_timestamp_init("OpenAll");
5998 SetGameStatus(GAME_MODE_LOADING);
6002 InitGlobal(); /* initialize some global variables */
6004 print_timestamp_time("[init global stuff]");
6008 print_timestamp_time("[init setup/config stuff (1)]");
6012 if (options.execute_command)
6013 Execute_Command(options.execute_command);
6015 InitNetworkSettings();
6017 if (network.serveronly)
6019 #if defined(PLATFORM_UNIX)
6020 NetworkServer(network.server_port, TRUE);
6022 Error(ERR_WARN, "networking only supported in Unix version");
6025 exit(0); /* never reached, server loops forever */
6029 print_timestamp_time("[init setup/config stuff (2)]");
6031 print_timestamp_time("[init setup/config stuff (3)]");
6032 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6033 print_timestamp_time("[init setup/config stuff (4)]");
6034 InitArtworkConfig(); /* needed before forking sound child process */
6035 print_timestamp_time("[init setup/config stuff (5)]");
6037 print_timestamp_time("[init setup/config stuff (6)]");
6039 InitRND(NEW_RANDOMIZE);
6040 InitSimpleRandom(NEW_RANDOMIZE);
6044 print_timestamp_time("[init setup/config stuff]");
6046 InitVideoDefaults();
6048 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6051 print_timestamp_time("[init video stuff]");
6053 InitElementPropertiesStatic();
6054 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6055 InitElementPropertiesGfxElement();
6057 print_timestamp_time("[init element properties stuff]");
6061 print_timestamp_time("InitGfx");
6064 print_timestamp_time("InitLevelInfo");
6066 InitLevelArtworkInfo();
6067 print_timestamp_time("InitLevelArtworkInfo");
6069 InitOverrideArtwork(); /* needs to know current level directory */
6070 print_timestamp_time("InitOverrideArtwork");
6072 InitImages(); /* needs to know current level directory */
6073 print_timestamp_time("InitImages");
6075 InitSound(NULL); /* needs to know current level directory */
6076 print_timestamp_time("InitSound");
6078 InitMusic(NULL); /* needs to know current level directory */
6079 print_timestamp_time("InitMusic");
6083 InitGfxBackground();
6089 if (global.autoplay_leveldir)
6094 else if (global.convert_leveldir)
6099 else if (global.create_images_dir)
6101 CreateLevelSketchImages();
6105 InitNetworkServer();
6107 SetGameStatus(GAME_MODE_MAIN);
6109 FadeSetEnterScreen();
6110 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6111 FadeSkipNextFadeOut();
6113 print_timestamp_time("[post-artwork]");
6115 print_timestamp_done("OpenAll");
6120 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6122 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6123 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6124 #if defined(PLATFORM_ANDROID)
6125 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6126 SDL_AndroidGetInternalStoragePath());
6127 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6128 SDL_AndroidGetExternalStoragePath());
6129 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6130 (SDL_AndroidGetExternalStorageState() &
6131 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6132 SDL_AndroidGetExternalStorageState() &
6133 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6138 void CloseAllAndExit(int exit_value)
6143 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6150 #if defined(TARGET_SDL)
6151 #if defined(TARGET_SDL2)
6153 // set a flag to tell the network server thread to quit and wait for it
6154 // using SDL_WaitThread()
6156 if (network_server) /* terminate network server */
6157 SDL_KillThread(server_thread);
6161 CloseVideoDisplay();
6162 ClosePlatformDependentStuff();
6164 if (exit_value != 0 && !options.execute_command)
6166 /* fall back to default level set (current set may have caused an error) */
6167 SaveLevelSetup_LastSeries_Deactivate();
6169 /* tell user where to find error log file which may contain more details */
6170 // (error notification now directly displayed on screen inside R'n'D
6171 // NotifyUserAboutErrorFile(); /* currently only works for Windows */