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->draw_masked = FALSE;
1294 g->fade_mode = FADE_MODE_DEFAULT;
1298 g->align = ALIGN_CENTER; /* default for title screens */
1299 g->valign = VALIGN_MIDDLE; /* default for title screens */
1300 g->sort_priority = 0; /* default for title screens */
1302 g->style = STYLE_DEFAULT;
1304 g->bitmaps = src_bitmaps;
1305 g->bitmap = src_bitmap;
1307 /* optional zoom factor for scaling up the image to a larger size */
1308 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1309 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1310 if (g->scale_up_factor < 1)
1311 g->scale_up_factor = 1; /* no scaling */
1313 /* optional tile size for using non-standard image size */
1314 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1316 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1319 // CHECK: should tile sizes less than standard tile size be allowed?
1320 if (g->tile_size < TILESIZE)
1321 g->tile_size = TILESIZE; /* standard tile size */
1324 // when setting tile size, also set width and height accordingly
1325 g->width = g->tile_size;
1326 g->height = g->tile_size;
1329 if (g->use_image_size)
1331 /* set new default bitmap size (with scaling, but without small images) */
1332 g->width = get_scaled_graphic_width(graphic);
1333 g->height = get_scaled_graphic_height(graphic);
1336 /* optional width and height of each animation frame */
1337 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1338 g->width = parameter[GFX_ARG_WIDTH];
1339 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1340 g->height = parameter[GFX_ARG_HEIGHT];
1342 /* optional x and y tile position of animation frame sequence */
1343 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1344 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1345 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1346 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1348 /* optional x and y pixel position of animation frame sequence */
1349 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1350 g->src_x = parameter[GFX_ARG_X];
1351 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1352 g->src_y = parameter[GFX_ARG_Y];
1358 Error(ERR_INFO_LINE, "-");
1359 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1360 g->width, getTokenFromImageID(graphic), TILEX);
1361 Error(ERR_INFO_LINE, "-");
1363 g->width = TILEX; /* will be checked to be inside bitmap later */
1368 Error(ERR_INFO_LINE, "-");
1369 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1370 g->height, getTokenFromImageID(graphic), TILEY);
1371 Error(ERR_INFO_LINE, "-");
1373 g->height = TILEY; /* will be checked to be inside bitmap later */
1379 /* get final bitmap size (with scaling, but without small images) */
1380 int src_image_width = get_scaled_graphic_width(graphic);
1381 int src_image_height = get_scaled_graphic_height(graphic);
1383 if (src_image_width == 0 || src_image_height == 0)
1385 /* only happens when loaded outside artwork system (like "global.busy") */
1386 src_image_width = src_bitmap->width;
1387 src_image_height = src_bitmap->height;
1390 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1392 anim_frames_per_row = MAX(1, src_image_width / g->tile_size);
1393 anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1397 anim_frames_per_row = MAX(1, src_image_width / g->width);
1398 anim_frames_per_col = MAX(1, src_image_height / g->height);
1401 g->src_image_width = src_image_width;
1402 g->src_image_height = src_image_height;
1405 /* correct x or y offset dependent of vertical or horizontal frame order */
1406 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1408 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1409 parameter[GFX_ARG_OFFSET] : g->height);
1410 anim_frames_per_line = anim_frames_per_col;
1412 else /* frames are ordered horizontally */
1414 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1415 parameter[GFX_ARG_OFFSET] : g->width);
1416 anim_frames_per_line = anim_frames_per_row;
1419 /* optionally, the x and y offset of frames can be specified directly */
1420 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1421 g->offset_x = parameter[GFX_ARG_XOFFSET];
1422 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1423 g->offset_y = parameter[GFX_ARG_YOFFSET];
1425 /* optionally, moving animations may have separate start and end graphics */
1426 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1428 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1429 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1431 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1432 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1433 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1434 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1435 else /* frames are ordered horizontally */
1436 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1437 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1439 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1440 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1441 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1442 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1443 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1445 /* optionally, the second movement tile can be specified as start tile */
1446 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1447 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1449 /* automatically determine correct number of frames, if not defined */
1450 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1451 g->anim_frames = parameter[GFX_ARG_FRAMES];
1452 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1453 g->anim_frames = anim_frames_per_row;
1454 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1455 g->anim_frames = anim_frames_per_col;
1459 if (g->anim_frames == 0) /* frames must be at least 1 */
1462 g->anim_frames_per_line =
1463 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1464 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1466 g->anim_delay = parameter[GFX_ARG_DELAY];
1467 if (g->anim_delay == 0) /* delay must be at least 1 */
1470 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1472 /* automatically determine correct start frame, if not defined */
1473 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1474 g->anim_start_frame = 0;
1475 else if (g->anim_mode & ANIM_REVERSE)
1476 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1478 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1480 /* animation synchronized with global frame counter, not move position */
1481 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1483 /* optional element for cloning crumble graphics */
1484 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1485 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1487 /* optional element for cloning digging graphics */
1488 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1489 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1491 /* optional border size for "crumbling" diggable graphics */
1492 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1493 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1495 /* used for global animations and player "boring" and "sleeping" actions */
1496 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1497 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1498 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1499 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1500 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1501 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1502 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1503 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1504 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1505 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1506 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1507 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1509 /* used for global animations */
1510 if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1511 g->init_event = parameter[GFX_ARG_INIT_EVENT];
1512 if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1513 g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1515 /* used for toon animations and global animations */
1516 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1517 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1518 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1519 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1520 g->direction = parameter[GFX_ARG_DIRECTION];
1521 g->position = parameter[GFX_ARG_POSITION];
1522 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1523 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1525 /* this is only used for drawing font characters */
1526 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1527 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1529 /* use a different default value for global animations and toons */
1530 if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
1531 (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20))
1532 g->draw_masked = TRUE;
1534 /* this is used for drawing envelopes, global animations and toons */
1535 if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1536 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1538 /* used for toon animations and global animations */
1539 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1540 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1542 /* optional graphic for cloning all graphics settings */
1543 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1544 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1546 /* optional settings for drawing title screens and title messages */
1547 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1548 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1549 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1550 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1551 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1552 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1553 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1554 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1555 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1556 g->align = parameter[GFX_ARG_ALIGN];
1557 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1558 g->valign = parameter[GFX_ARG_VALIGN];
1559 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1560 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1562 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1563 g->class = parameter[GFX_ARG_CLASS];
1564 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1565 g->style = parameter[GFX_ARG_STYLE];
1567 /* this is only used for drawing menu buttons and text */
1568 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1569 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1570 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1571 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1574 static void set_graphic_parameters(int graphic)
1576 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1577 char **parameter_raw = image->parameter;
1578 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1579 int parameter[NUM_GFX_ARGS];
1582 /* if fallback to default artwork is done, also use the default parameters */
1583 if (image->fallback_to_default)
1584 parameter_raw = image->default_parameter;
1586 /* get integer values from string parameters */
1587 for (i = 0; i < NUM_GFX_ARGS; i++)
1588 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1589 image_config_suffix[i].token,
1590 image_config_suffix[i].type);
1592 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1594 UPDATE_BUSY_STATE();
1597 static void set_cloned_graphic_parameters(int graphic)
1599 int fallback_graphic = IMG_CHAR_EXCLAM;
1600 int max_num_images = getImageListSize();
1601 int clone_graphic = graphic_info[graphic].clone_from;
1602 int num_references_followed = 1;
1604 while (graphic_info[clone_graphic].clone_from != -1 &&
1605 num_references_followed < max_num_images)
1607 clone_graphic = graphic_info[clone_graphic].clone_from;
1609 num_references_followed++;
1612 if (num_references_followed >= max_num_images)
1614 Error(ERR_INFO_LINE, "-");
1615 Error(ERR_INFO, "warning: error found in config file:");
1616 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1617 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1618 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1619 Error(ERR_INFO, "custom graphic rejected for this element/action");
1621 if (graphic == fallback_graphic)
1622 Error(ERR_EXIT, "no fallback graphic available");
1624 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1625 Error(ERR_INFO_LINE, "-");
1627 graphic_info[graphic] = graphic_info[fallback_graphic];
1631 graphic_info[graphic] = graphic_info[clone_graphic];
1632 graphic_info[graphic].clone_from = clone_graphic;
1636 static void InitGraphicInfo()
1638 int fallback_graphic = IMG_CHAR_EXCLAM;
1639 int num_images = getImageListSize();
1642 /* use image size as default values for width and height for these images */
1643 static int full_size_graphics[] =
1646 IMG_GLOBAL_BORDER_MAIN,
1647 IMG_GLOBAL_BORDER_SCORES,
1648 IMG_GLOBAL_BORDER_EDITOR,
1649 IMG_GLOBAL_BORDER_PLAYING,
1652 IMG_BACKGROUND_ENVELOPE_1,
1653 IMG_BACKGROUND_ENVELOPE_2,
1654 IMG_BACKGROUND_ENVELOPE_3,
1655 IMG_BACKGROUND_ENVELOPE_4,
1656 IMG_BACKGROUND_REQUEST,
1659 IMG_BACKGROUND_TITLE_INITIAL,
1660 IMG_BACKGROUND_TITLE,
1661 IMG_BACKGROUND_MAIN,
1662 IMG_BACKGROUND_LEVELS,
1663 IMG_BACKGROUND_LEVELNR,
1664 IMG_BACKGROUND_SCORES,
1665 IMG_BACKGROUND_EDITOR,
1666 IMG_BACKGROUND_INFO,
1667 IMG_BACKGROUND_INFO_ELEMENTS,
1668 IMG_BACKGROUND_INFO_MUSIC,
1669 IMG_BACKGROUND_INFO_CREDITS,
1670 IMG_BACKGROUND_INFO_PROGRAM,
1671 IMG_BACKGROUND_INFO_VERSION,
1672 IMG_BACKGROUND_INFO_LEVELSET,
1673 IMG_BACKGROUND_SETUP,
1674 IMG_BACKGROUND_PLAYING,
1675 IMG_BACKGROUND_DOOR,
1676 IMG_BACKGROUND_TAPE,
1677 IMG_BACKGROUND_PANEL,
1678 IMG_BACKGROUND_PALETTE,
1679 IMG_BACKGROUND_TOOLBOX,
1681 IMG_TITLESCREEN_INITIAL_1,
1682 IMG_TITLESCREEN_INITIAL_2,
1683 IMG_TITLESCREEN_INITIAL_3,
1684 IMG_TITLESCREEN_INITIAL_4,
1685 IMG_TITLESCREEN_INITIAL_5,
1692 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1693 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1694 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1695 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1696 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1697 IMG_BACKGROUND_TITLEMESSAGE_1,
1698 IMG_BACKGROUND_TITLEMESSAGE_2,
1699 IMG_BACKGROUND_TITLEMESSAGE_3,
1700 IMG_BACKGROUND_TITLEMESSAGE_4,
1701 IMG_BACKGROUND_TITLEMESSAGE_5,
1706 checked_free(graphic_info);
1708 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1710 /* initialize "use_image_size" flag with default value */
1711 for (i = 0; i < num_images; i++)
1712 graphic_info[i].use_image_size = FALSE;
1714 /* initialize "use_image_size" flag from static configuration above */
1715 for (i = 0; full_size_graphics[i] != -1; i++)
1716 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1718 /* first set all graphic paramaters ... */
1719 for (i = 0; i < num_images; i++)
1720 set_graphic_parameters(i);
1722 /* ... then copy these parameters for cloned graphics */
1723 for (i = 0; i < num_images; i++)
1724 if (graphic_info[i].clone_from != -1)
1725 set_cloned_graphic_parameters(i);
1727 for (i = 0; i < num_images; i++)
1729 Bitmap *src_bitmap = graphic_info[i].bitmap;
1733 int src_bitmap_width, src_bitmap_height;
1735 /* now check if no animation frames are outside of the loaded image */
1737 if (graphic_info[i].bitmap == NULL)
1738 continue; /* skip check for optional images that are undefined */
1740 /* get image size (this can differ from the standard element tile size!) */
1741 width = graphic_info[i].width;
1742 height = graphic_info[i].height;
1744 /* get final bitmap size (with scaling, but without small images) */
1745 src_bitmap_width = graphic_info[i].src_image_width;
1746 src_bitmap_height = graphic_info[i].src_image_height;
1748 /* check if first animation frame is inside specified bitmap */
1750 /* do not use getGraphicSourceXY() here to get position of first frame; */
1751 /* this avoids calculating wrong start position for out-of-bounds frame */
1752 src_x = graphic_info[i].src_x;
1753 src_y = graphic_info[i].src_y;
1755 if (program.headless)
1758 if (src_x < 0 || src_y < 0 ||
1759 src_x + width > src_bitmap_width ||
1760 src_y + height > src_bitmap_height)
1762 Error(ERR_INFO_LINE, "-");
1763 Error(ERR_INFO, "warning: error found in config file:");
1764 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1765 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1766 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1767 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1769 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1770 src_x, src_y, src_bitmap_width, src_bitmap_height);
1771 Error(ERR_INFO, "custom graphic rejected for this element/action");
1773 if (i == fallback_graphic)
1774 Error(ERR_EXIT, "no fallback graphic available");
1776 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1777 Error(ERR_INFO_LINE, "-");
1779 graphic_info[i] = graphic_info[fallback_graphic];
1781 /* if first frame out of bounds, do not check last frame anymore */
1785 /* check if last animation frame is inside specified bitmap */
1787 last_frame = graphic_info[i].anim_frames - 1;
1788 getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1790 if (src_x < 0 || src_y < 0 ||
1791 src_x + width > src_bitmap_width ||
1792 src_y + height > src_bitmap_height)
1794 Error(ERR_INFO_LINE, "-");
1795 Error(ERR_INFO, "warning: error found in config file:");
1796 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1797 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1798 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1799 Error(ERR_INFO, "- frame size: %d, %d", width, height);
1801 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1802 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1803 Error(ERR_INFO, "custom graphic rejected for this element/action");
1805 if (i == fallback_graphic)
1806 Error(ERR_EXIT, "no fallback graphic available");
1808 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1809 Error(ERR_INFO_LINE, "-");
1811 graphic_info[i] = graphic_info[fallback_graphic];
1816 static void InitGraphicCompatibilityInfo()
1818 struct FileInfo *fi_global_door =
1819 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1820 int num_images = getImageListSize();
1823 /* the following compatibility handling is needed for the following case:
1824 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1825 graphics mainly used for door and panel graphics, like editor, tape and
1826 in-game buttons with hard-coded bitmap positions and button sizes; as
1827 these graphics now have individual definitions, redefining "global.door"
1828 to change all these graphics at once like before does not work anymore
1829 (because all those individual definitions still have their default values);
1830 to solve this, remap all those individual definitions that are not
1831 redefined to the new bitmap of "global.door" if it was redefined */
1833 /* special compatibility handling if image "global.door" was redefined */
1834 if (fi_global_door->redefined)
1836 for (i = 0; i < num_images; i++)
1838 struct FileInfo *fi = getImageListEntryFromImageID(i);
1840 /* process only those images that still use the default settings */
1843 /* process all images which default to same image as "global.door" */
1844 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1846 // printf("::: special treatment needed for token '%s'\n", fi->token);
1848 graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1849 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1855 InitGraphicCompatibilityInfo_Doors();
1858 static void InitElementSoundInfo()
1860 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1861 int num_property_mappings = getSoundListPropertyMappingSize();
1864 /* set values to -1 to identify later as "uninitialized" values */
1865 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1866 for (act = 0; act < NUM_ACTIONS; act++)
1867 element_info[i].sound[act] = -1;
1869 /* initialize element/sound mapping from static configuration */
1870 for (i = 0; element_to_sound[i].element > -1; i++)
1872 int element = element_to_sound[i].element;
1873 int action = element_to_sound[i].action;
1874 int sound = element_to_sound[i].sound;
1875 boolean is_class = element_to_sound[i].is_class;
1878 action = ACTION_DEFAULT;
1881 element_info[element].sound[action] = sound;
1883 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1884 if (strEqual(element_info[j].class_name,
1885 element_info[element].class_name))
1886 element_info[j].sound[action] = sound;
1889 /* initialize element class/sound mapping from dynamic configuration */
1890 for (i = 0; i < num_property_mappings; i++)
1892 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1893 int action = property_mapping[i].ext1_index;
1894 int sound = property_mapping[i].artwork_index;
1896 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1900 action = ACTION_DEFAULT;
1902 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1903 if (strEqual(element_info[j].class_name,
1904 element_info[element_class].class_name))
1905 element_info[j].sound[action] = sound;
1908 /* initialize element/sound mapping from dynamic configuration */
1909 for (i = 0; i < num_property_mappings; i++)
1911 int element = property_mapping[i].base_index;
1912 int action = property_mapping[i].ext1_index;
1913 int sound = property_mapping[i].artwork_index;
1915 if (element >= MAX_NUM_ELEMENTS)
1919 action = ACTION_DEFAULT;
1921 element_info[element].sound[action] = sound;
1924 /* now set all '-1' values to element specific default values */
1925 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1927 for (act = 0; act < NUM_ACTIONS; act++)
1929 /* generic default action sound (defined by "[default]" directive) */
1930 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1932 /* look for special default action sound (classic game specific) */
1933 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1934 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1935 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1936 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1937 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1938 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1939 if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
1940 default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
1942 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1943 /* !!! make this better !!! */
1944 if (i == EL_EMPTY_SPACE)
1945 default_action_sound = element_info[EL_DEFAULT].sound[act];
1947 /* no sound for this specific action -- use default action sound */
1948 if (element_info[i].sound[act] == -1)
1949 element_info[i].sound[act] = default_action_sound;
1953 /* copy sound settings to some elements that are only stored in level file
1954 in native R'n'D levels, but are used by game engine in native EM levels */
1955 for (i = 0; copy_properties[i][0] != -1; i++)
1956 for (j = 1; j <= 4; j++)
1957 for (act = 0; act < NUM_ACTIONS; act++)
1958 element_info[copy_properties[i][j]].sound[act] =
1959 element_info[copy_properties[i][0]].sound[act];
1962 static void InitGameModeSoundInfo()
1966 /* set values to -1 to identify later as "uninitialized" values */
1967 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1970 /* initialize gamemode/sound mapping from static configuration */
1971 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1973 int gamemode = gamemode_to_sound[i].gamemode;
1974 int sound = gamemode_to_sound[i].sound;
1977 gamemode = GAME_MODE_DEFAULT;
1979 menu.sound[gamemode] = sound;
1982 /* now set all '-1' values to levelset specific default values */
1983 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1984 if (menu.sound[i] == -1)
1985 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1988 static void set_sound_parameters(int sound, char **parameter_raw)
1990 int parameter[NUM_SND_ARGS];
1993 /* get integer values from string parameters */
1994 for (i = 0; i < NUM_SND_ARGS; i++)
1996 get_parameter_value(parameter_raw[i],
1997 sound_config_suffix[i].token,
1998 sound_config_suffix[i].type);
2000 /* explicit loop mode setting in configuration overrides default value */
2001 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2002 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2004 /* sound volume to change the original volume when loading the sound file */
2005 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2007 /* sound priority to give certain sounds a higher or lower priority */
2008 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2011 static void InitSoundInfo()
2013 int *sound_effect_properties;
2014 int num_sounds = getSoundListSize();
2017 checked_free(sound_info);
2019 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2020 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2022 /* initialize sound effect for all elements to "no sound" */
2023 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2024 for (j = 0; j < NUM_ACTIONS; j++)
2025 element_info[i].sound[j] = SND_UNDEFINED;
2027 for (i = 0; i < num_sounds; i++)
2029 struct FileInfo *sound = getSoundListEntry(i);
2030 int len_effect_text = strlen(sound->token);
2032 sound_effect_properties[i] = ACTION_OTHER;
2033 sound_info[i].loop = FALSE; /* default: play sound only once */
2035 /* determine all loop sounds and identify certain sound classes */
2037 for (j = 0; element_action_info[j].suffix; j++)
2039 int len_action_text = strlen(element_action_info[j].suffix);
2041 if (len_action_text < len_effect_text &&
2042 strEqual(&sound->token[len_effect_text - len_action_text],
2043 element_action_info[j].suffix))
2045 sound_effect_properties[i] = element_action_info[j].value;
2046 sound_info[i].loop = element_action_info[j].is_loop_sound;
2052 /* associate elements and some selected sound actions */
2054 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2056 if (element_info[j].class_name)
2058 int len_class_text = strlen(element_info[j].class_name);
2060 if (len_class_text + 1 < len_effect_text &&
2061 strncmp(sound->token,
2062 element_info[j].class_name, len_class_text) == 0 &&
2063 sound->token[len_class_text] == '.')
2065 int sound_action_value = sound_effect_properties[i];
2067 element_info[j].sound[sound_action_value] = i;
2072 set_sound_parameters(i, sound->parameter);
2075 free(sound_effect_properties);
2078 static void InitGameModeMusicInfo()
2080 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2081 int num_property_mappings = getMusicListPropertyMappingSize();
2082 int default_levelset_music = -1;
2085 /* set values to -1 to identify later as "uninitialized" values */
2086 for (i = 0; i < MAX_LEVELS; i++)
2087 levelset.music[i] = -1;
2088 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2091 /* initialize gamemode/music mapping from static configuration */
2092 for (i = 0; gamemode_to_music[i].music > -1; i++)
2094 int gamemode = gamemode_to_music[i].gamemode;
2095 int music = gamemode_to_music[i].music;
2098 gamemode = GAME_MODE_DEFAULT;
2100 menu.music[gamemode] = music;
2103 /* initialize gamemode/music mapping from dynamic configuration */
2104 for (i = 0; i < num_property_mappings; i++)
2106 int prefix = property_mapping[i].base_index;
2107 int gamemode = property_mapping[i].ext2_index;
2108 int level = property_mapping[i].ext3_index;
2109 int music = property_mapping[i].artwork_index;
2111 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2115 gamemode = GAME_MODE_DEFAULT;
2117 /* level specific music only allowed for in-game music */
2118 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2119 gamemode = GAME_MODE_PLAYING;
2124 default_levelset_music = music;
2127 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2128 levelset.music[level] = music;
2129 if (gamemode != GAME_MODE_PLAYING)
2130 menu.music[gamemode] = music;
2133 /* now set all '-1' values to menu specific default values */
2134 /* (undefined values of "levelset.music[]" might stay at "-1" to
2135 allow dynamic selection of music files from music directory!) */
2136 for (i = 0; i < MAX_LEVELS; i++)
2137 if (levelset.music[i] == -1)
2138 levelset.music[i] = default_levelset_music;
2139 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2140 if (menu.music[i] == -1)
2141 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2144 static void set_music_parameters(int music, char **parameter_raw)
2146 int parameter[NUM_MUS_ARGS];
2149 /* get integer values from string parameters */
2150 for (i = 0; i < NUM_MUS_ARGS; i++)
2152 get_parameter_value(parameter_raw[i],
2153 music_config_suffix[i].token,
2154 music_config_suffix[i].type);
2156 /* explicit loop mode setting in configuration overrides default value */
2157 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2158 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2161 static void InitMusicInfo()
2163 int num_music = getMusicListSize();
2166 checked_free(music_info);
2168 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2170 for (i = 0; i < num_music; i++)
2172 struct FileInfo *music = getMusicListEntry(i);
2173 int len_music_text = strlen(music->token);
2175 music_info[i].loop = TRUE; /* default: play music in loop mode */
2177 /* determine all loop music */
2179 for (j = 0; music_prefix_info[j].prefix; j++)
2181 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2183 if (len_prefix_text < len_music_text &&
2184 strncmp(music->token,
2185 music_prefix_info[j].prefix, len_prefix_text) == 0)
2187 music_info[i].loop = music_prefix_info[j].is_loop_music;
2193 set_music_parameters(i, music->parameter);
2197 static void ReinitializeGraphics()
2199 print_timestamp_init("ReinitializeGraphics");
2201 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2203 InitGraphicInfo(); /* graphic properties mapping */
2204 print_timestamp_time("InitGraphicInfo");
2205 InitElementGraphicInfo(); /* element game graphic mapping */
2206 print_timestamp_time("InitElementGraphicInfo");
2207 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2208 print_timestamp_time("InitElementSpecialGraphicInfo");
2210 InitElementSmallImages(); /* scale elements to all needed sizes */
2211 print_timestamp_time("InitElementSmallImages");
2212 InitScaledImages(); /* scale all other images, if needed */
2213 print_timestamp_time("InitScaledImages");
2214 InitBitmapPointers(); /* set standard size bitmap pointers */
2215 print_timestamp_time("InitBitmapPointers");
2216 InitFontGraphicInfo(); /* initialize text drawing functions */
2217 print_timestamp_time("InitFontGraphicInfo");
2218 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2219 print_timestamp_time("InitGlobalAnimGraphicInfo");
2221 InitImageTextures(); /* create textures for certain images */
2222 print_timestamp_time("InitImageTextures");
2224 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2225 print_timestamp_time("InitGraphicInfo_EM");
2227 InitGraphicCompatibilityInfo();
2228 print_timestamp_time("InitGraphicCompatibilityInfo");
2230 SetMainBackgroundImage(IMG_BACKGROUND);
2231 print_timestamp_time("SetMainBackgroundImage");
2232 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2233 print_timestamp_time("SetDoorBackgroundImage");
2236 print_timestamp_time("InitGadgets");
2238 print_timestamp_time("InitDoors");
2240 print_timestamp_done("ReinitializeGraphics");
2243 static void ReinitializeSounds()
2245 InitSoundInfo(); /* sound properties mapping */
2246 InitElementSoundInfo(); /* element game sound mapping */
2247 InitGameModeSoundInfo(); /* game mode sound mapping */
2248 InitGlobalAnimSoundInfo(); /* global animation sound settings */
2250 InitPlayLevelSound(); /* internal game sound settings */
2253 static void ReinitializeMusic()
2255 InitMusicInfo(); /* music properties mapping */
2256 InitGameModeMusicInfo(); /* game mode music mapping */
2257 InitGlobalAnimMusicInfo(); /* global animation music settings */
2260 static int get_special_property_bit(int element, int property_bit_nr)
2262 struct PropertyBitInfo
2268 static struct PropertyBitInfo pb_can_move_into_acid[] =
2270 /* the player may be able fall into acid when gravity is activated */
2275 { EL_SP_MURPHY, 0 },
2276 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2278 /* all elements that can move may be able to also move into acid */
2281 { EL_BUG_RIGHT, 1 },
2284 { EL_SPACESHIP, 2 },
2285 { EL_SPACESHIP_LEFT, 2 },
2286 { EL_SPACESHIP_RIGHT, 2 },
2287 { EL_SPACESHIP_UP, 2 },
2288 { EL_SPACESHIP_DOWN, 2 },
2289 { EL_BD_BUTTERFLY, 3 },
2290 { EL_BD_BUTTERFLY_LEFT, 3 },
2291 { EL_BD_BUTTERFLY_RIGHT, 3 },
2292 { EL_BD_BUTTERFLY_UP, 3 },
2293 { EL_BD_BUTTERFLY_DOWN, 3 },
2294 { EL_BD_FIREFLY, 4 },
2295 { EL_BD_FIREFLY_LEFT, 4 },
2296 { EL_BD_FIREFLY_RIGHT, 4 },
2297 { EL_BD_FIREFLY_UP, 4 },
2298 { EL_BD_FIREFLY_DOWN, 4 },
2300 { EL_YAMYAM_LEFT, 5 },
2301 { EL_YAMYAM_RIGHT, 5 },
2302 { EL_YAMYAM_UP, 5 },
2303 { EL_YAMYAM_DOWN, 5 },
2304 { EL_DARK_YAMYAM, 6 },
2307 { EL_PACMAN_LEFT, 8 },
2308 { EL_PACMAN_RIGHT, 8 },
2309 { EL_PACMAN_UP, 8 },
2310 { EL_PACMAN_DOWN, 8 },
2312 { EL_MOLE_LEFT, 9 },
2313 { EL_MOLE_RIGHT, 9 },
2315 { EL_MOLE_DOWN, 9 },
2319 { EL_SATELLITE, 13 },
2320 { EL_SP_SNIKSNAK, 14 },
2321 { EL_SP_ELECTRON, 15 },
2324 { EL_EMC_ANDROID, 18 },
2329 static struct PropertyBitInfo pb_dont_collide_with[] =
2331 { EL_SP_SNIKSNAK, 0 },
2332 { EL_SP_ELECTRON, 1 },
2340 struct PropertyBitInfo *pb_info;
2343 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2344 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2349 struct PropertyBitInfo *pb_info = NULL;
2352 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2353 if (pb_definition[i].bit_nr == property_bit_nr)
2354 pb_info = pb_definition[i].pb_info;
2356 if (pb_info == NULL)
2359 for (i = 0; pb_info[i].element != -1; i++)
2360 if (pb_info[i].element == element)
2361 return pb_info[i].bit_nr;
2366 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2367 boolean property_value)
2369 int bit_nr = get_special_property_bit(element, property_bit_nr);
2374 *bitfield |= (1 << bit_nr);
2376 *bitfield &= ~(1 << bit_nr);
2380 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2382 int bit_nr = get_special_property_bit(element, property_bit_nr);
2385 return ((*bitfield & (1 << bit_nr)) != 0);
2390 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2392 static int group_nr;
2393 static struct ElementGroupInfo *group;
2394 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2397 if (actual_group == NULL) /* not yet initialized */
2400 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2402 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2403 group_element - EL_GROUP_START + 1);
2405 /* replace element which caused too deep recursion by question mark */
2406 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2411 if (recursion_depth == 0) /* initialization */
2413 group = actual_group;
2414 group_nr = GROUP_NR(group_element);
2416 group->num_elements_resolved = 0;
2417 group->choice_pos = 0;
2419 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2420 element_info[i].in_group[group_nr] = FALSE;
2423 for (i = 0; i < actual_group->num_elements; i++)
2425 int element = actual_group->element[i];
2427 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2430 if (IS_GROUP_ELEMENT(element))
2431 ResolveGroupElementExt(element, recursion_depth + 1);
2434 group->element_resolved[group->num_elements_resolved++] = element;
2435 element_info[element].in_group[group_nr] = TRUE;
2440 void ResolveGroupElement(int group_element)
2442 ResolveGroupElementExt(group_element, 0);
2445 void InitElementPropertiesStatic()
2447 static boolean clipboard_elements_initialized = FALSE;
2449 static int ep_diggable[] =
2454 EL_SP_BUGGY_BASE_ACTIVATING,
2457 EL_INVISIBLE_SAND_ACTIVE,
2460 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2461 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2466 EL_SP_BUGGY_BASE_ACTIVE,
2473 static int ep_collectible_only[] =
2495 EL_DYNABOMB_INCREASE_NUMBER,
2496 EL_DYNABOMB_INCREASE_SIZE,
2497 EL_DYNABOMB_INCREASE_POWER,
2515 /* !!! handle separately !!! */
2516 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2522 static int ep_dont_run_into[] =
2524 /* same elements as in 'ep_dont_touch' */
2530 /* same elements as in 'ep_dont_collide_with' */
2542 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2547 EL_SP_BUGGY_BASE_ACTIVE,
2554 static int ep_dont_collide_with[] =
2556 /* same elements as in 'ep_dont_touch' */
2573 static int ep_dont_touch[] =
2583 static int ep_indestructible[] =
2587 EL_ACID_POOL_TOPLEFT,
2588 EL_ACID_POOL_TOPRIGHT,
2589 EL_ACID_POOL_BOTTOMLEFT,
2590 EL_ACID_POOL_BOTTOM,
2591 EL_ACID_POOL_BOTTOMRIGHT,
2592 EL_SP_HARDWARE_GRAY,
2593 EL_SP_HARDWARE_GREEN,
2594 EL_SP_HARDWARE_BLUE,
2596 EL_SP_HARDWARE_YELLOW,
2597 EL_SP_HARDWARE_BASE_1,
2598 EL_SP_HARDWARE_BASE_2,
2599 EL_SP_HARDWARE_BASE_3,
2600 EL_SP_HARDWARE_BASE_4,
2601 EL_SP_HARDWARE_BASE_5,
2602 EL_SP_HARDWARE_BASE_6,
2603 EL_INVISIBLE_STEELWALL,
2604 EL_INVISIBLE_STEELWALL_ACTIVE,
2605 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2606 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2607 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2608 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2609 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2610 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2611 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2612 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2613 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2614 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2615 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2616 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2618 EL_LIGHT_SWITCH_ACTIVE,
2619 EL_SIGN_EXCLAMATION,
2620 EL_SIGN_RADIOACTIVITY,
2627 EL_SIGN_ENTRY_FORBIDDEN,
2628 EL_SIGN_EMERGENCY_EXIT,
2636 EL_STEEL_EXIT_CLOSED,
2638 EL_STEEL_EXIT_OPENING,
2639 EL_STEEL_EXIT_CLOSING,
2640 EL_EM_STEEL_EXIT_CLOSED,
2641 EL_EM_STEEL_EXIT_OPEN,
2642 EL_EM_STEEL_EXIT_OPENING,
2643 EL_EM_STEEL_EXIT_CLOSING,
2644 EL_DC_STEELWALL_1_LEFT,
2645 EL_DC_STEELWALL_1_RIGHT,
2646 EL_DC_STEELWALL_1_TOP,
2647 EL_DC_STEELWALL_1_BOTTOM,
2648 EL_DC_STEELWALL_1_HORIZONTAL,
2649 EL_DC_STEELWALL_1_VERTICAL,
2650 EL_DC_STEELWALL_1_TOPLEFT,
2651 EL_DC_STEELWALL_1_TOPRIGHT,
2652 EL_DC_STEELWALL_1_BOTTOMLEFT,
2653 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2654 EL_DC_STEELWALL_1_TOPLEFT_2,
2655 EL_DC_STEELWALL_1_TOPRIGHT_2,
2656 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2657 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2658 EL_DC_STEELWALL_2_LEFT,
2659 EL_DC_STEELWALL_2_RIGHT,
2660 EL_DC_STEELWALL_2_TOP,
2661 EL_DC_STEELWALL_2_BOTTOM,
2662 EL_DC_STEELWALL_2_HORIZONTAL,
2663 EL_DC_STEELWALL_2_VERTICAL,
2664 EL_DC_STEELWALL_2_MIDDLE,
2665 EL_DC_STEELWALL_2_SINGLE,
2666 EL_STEELWALL_SLIPPERY,
2680 EL_GATE_1_GRAY_ACTIVE,
2681 EL_GATE_2_GRAY_ACTIVE,
2682 EL_GATE_3_GRAY_ACTIVE,
2683 EL_GATE_4_GRAY_ACTIVE,
2692 EL_EM_GATE_1_GRAY_ACTIVE,
2693 EL_EM_GATE_2_GRAY_ACTIVE,
2694 EL_EM_GATE_3_GRAY_ACTIVE,
2695 EL_EM_GATE_4_GRAY_ACTIVE,
2704 EL_EMC_GATE_5_GRAY_ACTIVE,
2705 EL_EMC_GATE_6_GRAY_ACTIVE,
2706 EL_EMC_GATE_7_GRAY_ACTIVE,
2707 EL_EMC_GATE_8_GRAY_ACTIVE,
2709 EL_DC_GATE_WHITE_GRAY,
2710 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2711 EL_DC_GATE_FAKE_GRAY,
2713 EL_SWITCHGATE_OPENING,
2714 EL_SWITCHGATE_CLOSED,
2715 EL_SWITCHGATE_CLOSING,
2716 EL_DC_SWITCHGATE_SWITCH_UP,
2717 EL_DC_SWITCHGATE_SWITCH_DOWN,
2719 EL_TIMEGATE_OPENING,
2721 EL_TIMEGATE_CLOSING,
2722 EL_DC_TIMEGATE_SWITCH,
2723 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2727 EL_TUBE_VERTICAL_LEFT,
2728 EL_TUBE_VERTICAL_RIGHT,
2729 EL_TUBE_HORIZONTAL_UP,
2730 EL_TUBE_HORIZONTAL_DOWN,
2735 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2736 EL_EXPANDABLE_STEELWALL_VERTICAL,
2737 EL_EXPANDABLE_STEELWALL_ANY,
2742 static int ep_slippery[] =
2756 EL_ROBOT_WHEEL_ACTIVE,
2762 EL_ACID_POOL_TOPLEFT,
2763 EL_ACID_POOL_TOPRIGHT,
2773 EL_STEELWALL_SLIPPERY,
2776 EL_EMC_WALL_SLIPPERY_1,
2777 EL_EMC_WALL_SLIPPERY_2,
2778 EL_EMC_WALL_SLIPPERY_3,
2779 EL_EMC_WALL_SLIPPERY_4,
2781 EL_EMC_MAGIC_BALL_ACTIVE,
2786 static int ep_can_change[] =
2791 static int ep_can_move[] =
2793 /* same elements as in 'pb_can_move_into_acid' */
2816 static int ep_can_fall[] =
2830 EL_QUICKSAND_FAST_FULL,
2832 EL_BD_MAGIC_WALL_FULL,
2833 EL_DC_MAGIC_WALL_FULL,
2847 static int ep_can_smash_player[] =
2873 static int ep_can_smash_enemies[] =
2882 static int ep_can_smash_everything[] =
2891 static int ep_explodes_by_fire[] =
2893 /* same elements as in 'ep_explodes_impact' */
2898 /* same elements as in 'ep_explodes_smashed' */
2908 EL_EM_DYNAMITE_ACTIVE,
2909 EL_DYNABOMB_PLAYER_1_ACTIVE,
2910 EL_DYNABOMB_PLAYER_2_ACTIVE,
2911 EL_DYNABOMB_PLAYER_3_ACTIVE,
2912 EL_DYNABOMB_PLAYER_4_ACTIVE,
2913 EL_DYNABOMB_INCREASE_NUMBER,
2914 EL_DYNABOMB_INCREASE_SIZE,
2915 EL_DYNABOMB_INCREASE_POWER,
2916 EL_SP_DISK_RED_ACTIVE,
2930 static int ep_explodes_smashed[] =
2932 /* same elements as in 'ep_explodes_impact' */
2946 static int ep_explodes_impact[] =
2955 static int ep_walkable_over[] =
2959 EL_SOKOBAN_FIELD_EMPTY,
2966 EL_EM_STEEL_EXIT_OPEN,
2967 EL_EM_STEEL_EXIT_OPENING,
2976 EL_GATE_1_GRAY_ACTIVE,
2977 EL_GATE_2_GRAY_ACTIVE,
2978 EL_GATE_3_GRAY_ACTIVE,
2979 EL_GATE_4_GRAY_ACTIVE,
2987 static int ep_walkable_inside[] =
2992 EL_TUBE_VERTICAL_LEFT,
2993 EL_TUBE_VERTICAL_RIGHT,
2994 EL_TUBE_HORIZONTAL_UP,
2995 EL_TUBE_HORIZONTAL_DOWN,
3004 static int ep_walkable_under[] =
3009 static int ep_passable_over[] =
3019 EL_EM_GATE_1_GRAY_ACTIVE,
3020 EL_EM_GATE_2_GRAY_ACTIVE,
3021 EL_EM_GATE_3_GRAY_ACTIVE,
3022 EL_EM_GATE_4_GRAY_ACTIVE,
3031 EL_EMC_GATE_5_GRAY_ACTIVE,
3032 EL_EMC_GATE_6_GRAY_ACTIVE,
3033 EL_EMC_GATE_7_GRAY_ACTIVE,
3034 EL_EMC_GATE_8_GRAY_ACTIVE,
3036 EL_DC_GATE_WHITE_GRAY,
3037 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3044 static int ep_passable_inside[] =
3050 EL_SP_PORT_HORIZONTAL,
3051 EL_SP_PORT_VERTICAL,
3053 EL_SP_GRAVITY_PORT_LEFT,
3054 EL_SP_GRAVITY_PORT_RIGHT,
3055 EL_SP_GRAVITY_PORT_UP,
3056 EL_SP_GRAVITY_PORT_DOWN,
3057 EL_SP_GRAVITY_ON_PORT_LEFT,
3058 EL_SP_GRAVITY_ON_PORT_RIGHT,
3059 EL_SP_GRAVITY_ON_PORT_UP,
3060 EL_SP_GRAVITY_ON_PORT_DOWN,
3061 EL_SP_GRAVITY_OFF_PORT_LEFT,
3062 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3063 EL_SP_GRAVITY_OFF_PORT_UP,
3064 EL_SP_GRAVITY_OFF_PORT_DOWN,
3069 static int ep_passable_under[] =
3074 static int ep_droppable[] =
3079 static int ep_explodes_1x1_old[] =
3084 static int ep_pushable[] =
3096 EL_SOKOBAN_FIELD_FULL,
3105 static int ep_explodes_cross_old[] =
3110 static int ep_protected[] =
3112 /* same elements as in 'ep_walkable_inside' */
3116 EL_TUBE_VERTICAL_LEFT,
3117 EL_TUBE_VERTICAL_RIGHT,
3118 EL_TUBE_HORIZONTAL_UP,
3119 EL_TUBE_HORIZONTAL_DOWN,
3125 /* same elements as in 'ep_passable_over' */
3134 EL_EM_GATE_1_GRAY_ACTIVE,
3135 EL_EM_GATE_2_GRAY_ACTIVE,
3136 EL_EM_GATE_3_GRAY_ACTIVE,
3137 EL_EM_GATE_4_GRAY_ACTIVE,
3146 EL_EMC_GATE_5_GRAY_ACTIVE,
3147 EL_EMC_GATE_6_GRAY_ACTIVE,
3148 EL_EMC_GATE_7_GRAY_ACTIVE,
3149 EL_EMC_GATE_8_GRAY_ACTIVE,
3151 EL_DC_GATE_WHITE_GRAY,
3152 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3156 /* same elements as in 'ep_passable_inside' */
3161 EL_SP_PORT_HORIZONTAL,
3162 EL_SP_PORT_VERTICAL,
3164 EL_SP_GRAVITY_PORT_LEFT,
3165 EL_SP_GRAVITY_PORT_RIGHT,
3166 EL_SP_GRAVITY_PORT_UP,
3167 EL_SP_GRAVITY_PORT_DOWN,
3168 EL_SP_GRAVITY_ON_PORT_LEFT,
3169 EL_SP_GRAVITY_ON_PORT_RIGHT,
3170 EL_SP_GRAVITY_ON_PORT_UP,
3171 EL_SP_GRAVITY_ON_PORT_DOWN,
3172 EL_SP_GRAVITY_OFF_PORT_LEFT,
3173 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3174 EL_SP_GRAVITY_OFF_PORT_UP,
3175 EL_SP_GRAVITY_OFF_PORT_DOWN,
3180 static int ep_throwable[] =
3185 static int ep_can_explode[] =
3187 /* same elements as in 'ep_explodes_impact' */
3192 /* same elements as in 'ep_explodes_smashed' */
3198 /* elements that can explode by explosion or by dragonfire */
3202 EL_EM_DYNAMITE_ACTIVE,
3203 EL_DYNABOMB_PLAYER_1_ACTIVE,
3204 EL_DYNABOMB_PLAYER_2_ACTIVE,
3205 EL_DYNABOMB_PLAYER_3_ACTIVE,
3206 EL_DYNABOMB_PLAYER_4_ACTIVE,
3207 EL_DYNABOMB_INCREASE_NUMBER,
3208 EL_DYNABOMB_INCREASE_SIZE,
3209 EL_DYNABOMB_INCREASE_POWER,
3210 EL_SP_DISK_RED_ACTIVE,
3218 /* elements that can explode only by explosion */
3224 static int ep_gravity_reachable[] =
3230 EL_INVISIBLE_SAND_ACTIVE,
3235 EL_SP_PORT_HORIZONTAL,
3236 EL_SP_PORT_VERTICAL,
3238 EL_SP_GRAVITY_PORT_LEFT,
3239 EL_SP_GRAVITY_PORT_RIGHT,
3240 EL_SP_GRAVITY_PORT_UP,
3241 EL_SP_GRAVITY_PORT_DOWN,
3242 EL_SP_GRAVITY_ON_PORT_LEFT,
3243 EL_SP_GRAVITY_ON_PORT_RIGHT,
3244 EL_SP_GRAVITY_ON_PORT_UP,
3245 EL_SP_GRAVITY_ON_PORT_DOWN,
3246 EL_SP_GRAVITY_OFF_PORT_LEFT,
3247 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3248 EL_SP_GRAVITY_OFF_PORT_UP,
3249 EL_SP_GRAVITY_OFF_PORT_DOWN,
3255 static int ep_player[] =
3262 EL_SOKOBAN_FIELD_PLAYER,
3268 static int ep_can_pass_magic_wall[] =
3282 static int ep_can_pass_dc_magic_wall[] =
3298 static int ep_switchable[] =
3302 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3303 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3304 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3305 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3306 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3307 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3308 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3309 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3310 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3311 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3312 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3313 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3314 EL_SWITCHGATE_SWITCH_UP,
3315 EL_SWITCHGATE_SWITCH_DOWN,
3316 EL_DC_SWITCHGATE_SWITCH_UP,
3317 EL_DC_SWITCHGATE_SWITCH_DOWN,
3319 EL_LIGHT_SWITCH_ACTIVE,
3321 EL_DC_TIMEGATE_SWITCH,
3322 EL_BALLOON_SWITCH_LEFT,
3323 EL_BALLOON_SWITCH_RIGHT,
3324 EL_BALLOON_SWITCH_UP,
3325 EL_BALLOON_SWITCH_DOWN,
3326 EL_BALLOON_SWITCH_ANY,
3327 EL_BALLOON_SWITCH_NONE,
3330 EL_EMC_MAGIC_BALL_SWITCH,
3331 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3336 static int ep_bd_element[] =
3370 static int ep_sp_element[] =
3372 /* should always be valid */
3375 /* standard classic Supaplex elements */
3382 EL_SP_HARDWARE_GRAY,
3390 EL_SP_GRAVITY_PORT_RIGHT,
3391 EL_SP_GRAVITY_PORT_DOWN,
3392 EL_SP_GRAVITY_PORT_LEFT,
3393 EL_SP_GRAVITY_PORT_UP,
3398 EL_SP_PORT_VERTICAL,
3399 EL_SP_PORT_HORIZONTAL,
3405 EL_SP_HARDWARE_BASE_1,
3406 EL_SP_HARDWARE_GREEN,
3407 EL_SP_HARDWARE_BLUE,
3409 EL_SP_HARDWARE_YELLOW,
3410 EL_SP_HARDWARE_BASE_2,
3411 EL_SP_HARDWARE_BASE_3,
3412 EL_SP_HARDWARE_BASE_4,
3413 EL_SP_HARDWARE_BASE_5,
3414 EL_SP_HARDWARE_BASE_6,
3418 /* additional elements that appeared in newer Supaplex levels */
3421 /* additional gravity port elements (not switching, but setting gravity) */
3422 EL_SP_GRAVITY_ON_PORT_LEFT,
3423 EL_SP_GRAVITY_ON_PORT_RIGHT,
3424 EL_SP_GRAVITY_ON_PORT_UP,
3425 EL_SP_GRAVITY_ON_PORT_DOWN,
3426 EL_SP_GRAVITY_OFF_PORT_LEFT,
3427 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3428 EL_SP_GRAVITY_OFF_PORT_UP,
3429 EL_SP_GRAVITY_OFF_PORT_DOWN,
3431 /* more than one Murphy in a level results in an inactive clone */
3434 /* runtime Supaplex elements */
3435 EL_SP_DISK_RED_ACTIVE,
3436 EL_SP_TERMINAL_ACTIVE,
3437 EL_SP_BUGGY_BASE_ACTIVATING,
3438 EL_SP_BUGGY_BASE_ACTIVE,
3445 static int ep_sb_element[] =
3450 EL_SOKOBAN_FIELD_EMPTY,
3451 EL_SOKOBAN_FIELD_FULL,
3452 EL_SOKOBAN_FIELD_PLAYER,
3457 EL_INVISIBLE_STEELWALL,
3462 static int ep_gem[] =
3474 static int ep_food_dark_yamyam[] =
3502 static int ep_food_penguin[] =
3516 static int ep_food_pig[] =
3528 static int ep_historic_wall[] =
3539 EL_GATE_1_GRAY_ACTIVE,
3540 EL_GATE_2_GRAY_ACTIVE,
3541 EL_GATE_3_GRAY_ACTIVE,
3542 EL_GATE_4_GRAY_ACTIVE,
3551 EL_EM_GATE_1_GRAY_ACTIVE,
3552 EL_EM_GATE_2_GRAY_ACTIVE,
3553 EL_EM_GATE_3_GRAY_ACTIVE,
3554 EL_EM_GATE_4_GRAY_ACTIVE,
3561 EL_EXPANDABLE_WALL_HORIZONTAL,
3562 EL_EXPANDABLE_WALL_VERTICAL,
3563 EL_EXPANDABLE_WALL_ANY,
3564 EL_EXPANDABLE_WALL_GROWING,
3565 EL_BD_EXPANDABLE_WALL,
3572 EL_SP_HARDWARE_GRAY,
3573 EL_SP_HARDWARE_GREEN,
3574 EL_SP_HARDWARE_BLUE,
3576 EL_SP_HARDWARE_YELLOW,
3577 EL_SP_HARDWARE_BASE_1,
3578 EL_SP_HARDWARE_BASE_2,
3579 EL_SP_HARDWARE_BASE_3,
3580 EL_SP_HARDWARE_BASE_4,
3581 EL_SP_HARDWARE_BASE_5,
3582 EL_SP_HARDWARE_BASE_6,
3584 EL_SP_TERMINAL_ACTIVE,
3587 EL_INVISIBLE_STEELWALL,
3588 EL_INVISIBLE_STEELWALL_ACTIVE,
3590 EL_INVISIBLE_WALL_ACTIVE,
3591 EL_STEELWALL_SLIPPERY,
3608 static int ep_historic_solid[] =
3612 EL_EXPANDABLE_WALL_HORIZONTAL,
3613 EL_EXPANDABLE_WALL_VERTICAL,
3614 EL_EXPANDABLE_WALL_ANY,
3615 EL_BD_EXPANDABLE_WALL,
3628 EL_QUICKSAND_FILLING,
3629 EL_QUICKSAND_EMPTYING,
3631 EL_MAGIC_WALL_ACTIVE,
3632 EL_MAGIC_WALL_EMPTYING,
3633 EL_MAGIC_WALL_FILLING,
3637 EL_BD_MAGIC_WALL_ACTIVE,
3638 EL_BD_MAGIC_WALL_EMPTYING,
3639 EL_BD_MAGIC_WALL_FULL,
3640 EL_BD_MAGIC_WALL_FILLING,
3641 EL_BD_MAGIC_WALL_DEAD,
3650 EL_SP_TERMINAL_ACTIVE,
3654 EL_INVISIBLE_WALL_ACTIVE,
3655 EL_SWITCHGATE_SWITCH_UP,
3656 EL_SWITCHGATE_SWITCH_DOWN,
3657 EL_DC_SWITCHGATE_SWITCH_UP,
3658 EL_DC_SWITCHGATE_SWITCH_DOWN,
3660 EL_TIMEGATE_SWITCH_ACTIVE,
3661 EL_DC_TIMEGATE_SWITCH,
3662 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3674 /* the following elements are a direct copy of "indestructible" elements,
3675 except "EL_ACID", which is "indestructible", but not "solid"! */
3680 EL_ACID_POOL_TOPLEFT,
3681 EL_ACID_POOL_TOPRIGHT,
3682 EL_ACID_POOL_BOTTOMLEFT,
3683 EL_ACID_POOL_BOTTOM,
3684 EL_ACID_POOL_BOTTOMRIGHT,
3685 EL_SP_HARDWARE_GRAY,
3686 EL_SP_HARDWARE_GREEN,
3687 EL_SP_HARDWARE_BLUE,
3689 EL_SP_HARDWARE_YELLOW,
3690 EL_SP_HARDWARE_BASE_1,
3691 EL_SP_HARDWARE_BASE_2,
3692 EL_SP_HARDWARE_BASE_3,
3693 EL_SP_HARDWARE_BASE_4,
3694 EL_SP_HARDWARE_BASE_5,
3695 EL_SP_HARDWARE_BASE_6,
3696 EL_INVISIBLE_STEELWALL,
3697 EL_INVISIBLE_STEELWALL_ACTIVE,
3698 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3699 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3700 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3701 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3702 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3703 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3704 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3705 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3706 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3707 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3708 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3709 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3711 EL_LIGHT_SWITCH_ACTIVE,
3712 EL_SIGN_EXCLAMATION,
3713 EL_SIGN_RADIOACTIVITY,
3720 EL_SIGN_ENTRY_FORBIDDEN,
3721 EL_SIGN_EMERGENCY_EXIT,
3729 EL_STEEL_EXIT_CLOSED,
3731 EL_DC_STEELWALL_1_LEFT,
3732 EL_DC_STEELWALL_1_RIGHT,
3733 EL_DC_STEELWALL_1_TOP,
3734 EL_DC_STEELWALL_1_BOTTOM,
3735 EL_DC_STEELWALL_1_HORIZONTAL,
3736 EL_DC_STEELWALL_1_VERTICAL,
3737 EL_DC_STEELWALL_1_TOPLEFT,
3738 EL_DC_STEELWALL_1_TOPRIGHT,
3739 EL_DC_STEELWALL_1_BOTTOMLEFT,
3740 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3741 EL_DC_STEELWALL_1_TOPLEFT_2,
3742 EL_DC_STEELWALL_1_TOPRIGHT_2,
3743 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3744 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3745 EL_DC_STEELWALL_2_LEFT,
3746 EL_DC_STEELWALL_2_RIGHT,
3747 EL_DC_STEELWALL_2_TOP,
3748 EL_DC_STEELWALL_2_BOTTOM,
3749 EL_DC_STEELWALL_2_HORIZONTAL,
3750 EL_DC_STEELWALL_2_VERTICAL,
3751 EL_DC_STEELWALL_2_MIDDLE,
3752 EL_DC_STEELWALL_2_SINGLE,
3753 EL_STEELWALL_SLIPPERY,
3767 EL_GATE_1_GRAY_ACTIVE,
3768 EL_GATE_2_GRAY_ACTIVE,
3769 EL_GATE_3_GRAY_ACTIVE,
3770 EL_GATE_4_GRAY_ACTIVE,
3779 EL_EM_GATE_1_GRAY_ACTIVE,
3780 EL_EM_GATE_2_GRAY_ACTIVE,
3781 EL_EM_GATE_3_GRAY_ACTIVE,
3782 EL_EM_GATE_4_GRAY_ACTIVE,
3784 EL_SWITCHGATE_OPENING,
3785 EL_SWITCHGATE_CLOSED,
3786 EL_SWITCHGATE_CLOSING,
3788 EL_TIMEGATE_OPENING,
3790 EL_TIMEGATE_CLOSING,
3794 EL_TUBE_VERTICAL_LEFT,
3795 EL_TUBE_VERTICAL_RIGHT,
3796 EL_TUBE_HORIZONTAL_UP,
3797 EL_TUBE_HORIZONTAL_DOWN,
3806 static int ep_classic_enemy[] =
3823 static int ep_belt[] =
3825 EL_CONVEYOR_BELT_1_LEFT,
3826 EL_CONVEYOR_BELT_1_MIDDLE,
3827 EL_CONVEYOR_BELT_1_RIGHT,
3828 EL_CONVEYOR_BELT_2_LEFT,
3829 EL_CONVEYOR_BELT_2_MIDDLE,
3830 EL_CONVEYOR_BELT_2_RIGHT,
3831 EL_CONVEYOR_BELT_3_LEFT,
3832 EL_CONVEYOR_BELT_3_MIDDLE,
3833 EL_CONVEYOR_BELT_3_RIGHT,
3834 EL_CONVEYOR_BELT_4_LEFT,
3835 EL_CONVEYOR_BELT_4_MIDDLE,
3836 EL_CONVEYOR_BELT_4_RIGHT,
3841 static int ep_belt_active[] =
3843 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3844 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3845 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3846 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3847 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3848 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3849 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3850 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3851 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3852 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3853 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3854 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3859 static int ep_belt_switch[] =
3861 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3862 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3863 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3864 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3865 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3866 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3867 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3868 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3869 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3870 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3871 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3872 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3877 static int ep_tube[] =
3884 EL_TUBE_HORIZONTAL_UP,
3885 EL_TUBE_HORIZONTAL_DOWN,
3887 EL_TUBE_VERTICAL_LEFT,
3888 EL_TUBE_VERTICAL_RIGHT,
3894 static int ep_acid_pool[] =
3896 EL_ACID_POOL_TOPLEFT,
3897 EL_ACID_POOL_TOPRIGHT,
3898 EL_ACID_POOL_BOTTOMLEFT,
3899 EL_ACID_POOL_BOTTOM,
3900 EL_ACID_POOL_BOTTOMRIGHT,
3905 static int ep_keygate[] =
3915 EL_GATE_1_GRAY_ACTIVE,
3916 EL_GATE_2_GRAY_ACTIVE,
3917 EL_GATE_3_GRAY_ACTIVE,
3918 EL_GATE_4_GRAY_ACTIVE,
3927 EL_EM_GATE_1_GRAY_ACTIVE,
3928 EL_EM_GATE_2_GRAY_ACTIVE,
3929 EL_EM_GATE_3_GRAY_ACTIVE,
3930 EL_EM_GATE_4_GRAY_ACTIVE,
3939 EL_EMC_GATE_5_GRAY_ACTIVE,
3940 EL_EMC_GATE_6_GRAY_ACTIVE,
3941 EL_EMC_GATE_7_GRAY_ACTIVE,
3942 EL_EMC_GATE_8_GRAY_ACTIVE,
3944 EL_DC_GATE_WHITE_GRAY,
3945 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3950 static int ep_amoeboid[] =
3962 static int ep_amoebalive[] =
3973 static int ep_has_editor_content[] =
3979 EL_SOKOBAN_FIELD_PLAYER,
3996 static int ep_can_turn_each_move[] =
3998 /* !!! do something with this one !!! */
4002 static int ep_can_grow[] =
4016 static int ep_active_bomb[] =
4019 EL_EM_DYNAMITE_ACTIVE,
4020 EL_DYNABOMB_PLAYER_1_ACTIVE,
4021 EL_DYNABOMB_PLAYER_2_ACTIVE,
4022 EL_DYNABOMB_PLAYER_3_ACTIVE,
4023 EL_DYNABOMB_PLAYER_4_ACTIVE,
4024 EL_SP_DISK_RED_ACTIVE,
4029 static int ep_inactive[] =
4039 EL_QUICKSAND_FAST_EMPTY,
4062 EL_GATE_1_GRAY_ACTIVE,
4063 EL_GATE_2_GRAY_ACTIVE,
4064 EL_GATE_3_GRAY_ACTIVE,
4065 EL_GATE_4_GRAY_ACTIVE,
4074 EL_EM_GATE_1_GRAY_ACTIVE,
4075 EL_EM_GATE_2_GRAY_ACTIVE,
4076 EL_EM_GATE_3_GRAY_ACTIVE,
4077 EL_EM_GATE_4_GRAY_ACTIVE,
4086 EL_EMC_GATE_5_GRAY_ACTIVE,
4087 EL_EMC_GATE_6_GRAY_ACTIVE,
4088 EL_EMC_GATE_7_GRAY_ACTIVE,
4089 EL_EMC_GATE_8_GRAY_ACTIVE,
4091 EL_DC_GATE_WHITE_GRAY,
4092 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4093 EL_DC_GATE_FAKE_GRAY,
4096 EL_INVISIBLE_STEELWALL,
4104 EL_WALL_EMERALD_YELLOW,
4105 EL_DYNABOMB_INCREASE_NUMBER,
4106 EL_DYNABOMB_INCREASE_SIZE,
4107 EL_DYNABOMB_INCREASE_POWER,
4111 EL_SOKOBAN_FIELD_EMPTY,
4112 EL_SOKOBAN_FIELD_FULL,
4113 EL_WALL_EMERALD_RED,
4114 EL_WALL_EMERALD_PURPLE,
4115 EL_ACID_POOL_TOPLEFT,
4116 EL_ACID_POOL_TOPRIGHT,
4117 EL_ACID_POOL_BOTTOMLEFT,
4118 EL_ACID_POOL_BOTTOM,
4119 EL_ACID_POOL_BOTTOMRIGHT,
4123 EL_BD_MAGIC_WALL_DEAD,
4125 EL_DC_MAGIC_WALL_DEAD,
4126 EL_AMOEBA_TO_DIAMOND,
4134 EL_SP_GRAVITY_PORT_RIGHT,
4135 EL_SP_GRAVITY_PORT_DOWN,
4136 EL_SP_GRAVITY_PORT_LEFT,
4137 EL_SP_GRAVITY_PORT_UP,
4138 EL_SP_PORT_HORIZONTAL,
4139 EL_SP_PORT_VERTICAL,
4150 EL_SP_HARDWARE_GRAY,
4151 EL_SP_HARDWARE_GREEN,
4152 EL_SP_HARDWARE_BLUE,
4154 EL_SP_HARDWARE_YELLOW,
4155 EL_SP_HARDWARE_BASE_1,
4156 EL_SP_HARDWARE_BASE_2,
4157 EL_SP_HARDWARE_BASE_3,
4158 EL_SP_HARDWARE_BASE_4,
4159 EL_SP_HARDWARE_BASE_5,
4160 EL_SP_HARDWARE_BASE_6,
4161 EL_SP_GRAVITY_ON_PORT_LEFT,
4162 EL_SP_GRAVITY_ON_PORT_RIGHT,
4163 EL_SP_GRAVITY_ON_PORT_UP,
4164 EL_SP_GRAVITY_ON_PORT_DOWN,
4165 EL_SP_GRAVITY_OFF_PORT_LEFT,
4166 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4167 EL_SP_GRAVITY_OFF_PORT_UP,
4168 EL_SP_GRAVITY_OFF_PORT_DOWN,
4169 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4170 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4171 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4172 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4173 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4174 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4175 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4176 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4177 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4178 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4179 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4180 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4181 EL_SIGN_EXCLAMATION,
4182 EL_SIGN_RADIOACTIVITY,
4189 EL_SIGN_ENTRY_FORBIDDEN,
4190 EL_SIGN_EMERGENCY_EXIT,
4198 EL_DC_STEELWALL_1_LEFT,
4199 EL_DC_STEELWALL_1_RIGHT,
4200 EL_DC_STEELWALL_1_TOP,
4201 EL_DC_STEELWALL_1_BOTTOM,
4202 EL_DC_STEELWALL_1_HORIZONTAL,
4203 EL_DC_STEELWALL_1_VERTICAL,
4204 EL_DC_STEELWALL_1_TOPLEFT,
4205 EL_DC_STEELWALL_1_TOPRIGHT,
4206 EL_DC_STEELWALL_1_BOTTOMLEFT,
4207 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4208 EL_DC_STEELWALL_1_TOPLEFT_2,
4209 EL_DC_STEELWALL_1_TOPRIGHT_2,
4210 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4211 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4212 EL_DC_STEELWALL_2_LEFT,
4213 EL_DC_STEELWALL_2_RIGHT,
4214 EL_DC_STEELWALL_2_TOP,
4215 EL_DC_STEELWALL_2_BOTTOM,
4216 EL_DC_STEELWALL_2_HORIZONTAL,
4217 EL_DC_STEELWALL_2_VERTICAL,
4218 EL_DC_STEELWALL_2_MIDDLE,
4219 EL_DC_STEELWALL_2_SINGLE,
4220 EL_STEELWALL_SLIPPERY,
4225 EL_EMC_WALL_SLIPPERY_1,
4226 EL_EMC_WALL_SLIPPERY_2,
4227 EL_EMC_WALL_SLIPPERY_3,
4228 EL_EMC_WALL_SLIPPERY_4,
4249 static int ep_em_slippery_wall[] =
4254 static int ep_gfx_crumbled[] =
4265 static int ep_editor_cascade_active[] =
4267 EL_INTERNAL_CASCADE_BD_ACTIVE,
4268 EL_INTERNAL_CASCADE_EM_ACTIVE,
4269 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4270 EL_INTERNAL_CASCADE_RND_ACTIVE,
4271 EL_INTERNAL_CASCADE_SB_ACTIVE,
4272 EL_INTERNAL_CASCADE_SP_ACTIVE,
4273 EL_INTERNAL_CASCADE_DC_ACTIVE,
4274 EL_INTERNAL_CASCADE_DX_ACTIVE,
4275 EL_INTERNAL_CASCADE_MM_ACTIVE,
4276 EL_INTERNAL_CASCADE_DF_ACTIVE,
4277 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4278 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4279 EL_INTERNAL_CASCADE_CE_ACTIVE,
4280 EL_INTERNAL_CASCADE_GE_ACTIVE,
4281 EL_INTERNAL_CASCADE_REF_ACTIVE,
4282 EL_INTERNAL_CASCADE_USER_ACTIVE,
4283 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4288 static int ep_editor_cascade_inactive[] =
4290 EL_INTERNAL_CASCADE_BD,
4291 EL_INTERNAL_CASCADE_EM,
4292 EL_INTERNAL_CASCADE_EMC,
4293 EL_INTERNAL_CASCADE_RND,
4294 EL_INTERNAL_CASCADE_SB,
4295 EL_INTERNAL_CASCADE_SP,
4296 EL_INTERNAL_CASCADE_DC,
4297 EL_INTERNAL_CASCADE_DX,
4298 EL_INTERNAL_CASCADE_MM,
4299 EL_INTERNAL_CASCADE_DF,
4300 EL_INTERNAL_CASCADE_CHARS,
4301 EL_INTERNAL_CASCADE_STEEL_CHARS,
4302 EL_INTERNAL_CASCADE_CE,
4303 EL_INTERNAL_CASCADE_GE,
4304 EL_INTERNAL_CASCADE_REF,
4305 EL_INTERNAL_CASCADE_USER,
4306 EL_INTERNAL_CASCADE_DYNAMIC,
4311 static int ep_obsolete[] =
4315 EL_EM_KEY_1_FILE_OBSOLETE,
4316 EL_EM_KEY_2_FILE_OBSOLETE,
4317 EL_EM_KEY_3_FILE_OBSOLETE,
4318 EL_EM_KEY_4_FILE_OBSOLETE,
4319 EL_ENVELOPE_OBSOLETE,
4328 } element_properties[] =
4330 { ep_diggable, EP_DIGGABLE },
4331 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4332 { ep_dont_run_into, EP_DONT_RUN_INTO },
4333 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4334 { ep_dont_touch, EP_DONT_TOUCH },
4335 { ep_indestructible, EP_INDESTRUCTIBLE },
4336 { ep_slippery, EP_SLIPPERY },
4337 { ep_can_change, EP_CAN_CHANGE },
4338 { ep_can_move, EP_CAN_MOVE },
4339 { ep_can_fall, EP_CAN_FALL },
4340 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4341 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4342 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4343 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4344 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4345 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4346 { ep_walkable_over, EP_WALKABLE_OVER },
4347 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4348 { ep_walkable_under, EP_WALKABLE_UNDER },
4349 { ep_passable_over, EP_PASSABLE_OVER },
4350 { ep_passable_inside, EP_PASSABLE_INSIDE },
4351 { ep_passable_under, EP_PASSABLE_UNDER },
4352 { ep_droppable, EP_DROPPABLE },
4353 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4354 { ep_pushable, EP_PUSHABLE },
4355 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4356 { ep_protected, EP_PROTECTED },
4357 { ep_throwable, EP_THROWABLE },
4358 { ep_can_explode, EP_CAN_EXPLODE },
4359 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4361 { ep_player, EP_PLAYER },
4362 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4363 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4364 { ep_switchable, EP_SWITCHABLE },
4365 { ep_bd_element, EP_BD_ELEMENT },
4366 { ep_sp_element, EP_SP_ELEMENT },
4367 { ep_sb_element, EP_SB_ELEMENT },
4369 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4370 { ep_food_penguin, EP_FOOD_PENGUIN },
4371 { ep_food_pig, EP_FOOD_PIG },
4372 { ep_historic_wall, EP_HISTORIC_WALL },
4373 { ep_historic_solid, EP_HISTORIC_SOLID },
4374 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4375 { ep_belt, EP_BELT },
4376 { ep_belt_active, EP_BELT_ACTIVE },
4377 { ep_belt_switch, EP_BELT_SWITCH },
4378 { ep_tube, EP_TUBE },
4379 { ep_acid_pool, EP_ACID_POOL },
4380 { ep_keygate, EP_KEYGATE },
4381 { ep_amoeboid, EP_AMOEBOID },
4382 { ep_amoebalive, EP_AMOEBALIVE },
4383 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4384 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4385 { ep_can_grow, EP_CAN_GROW },
4386 { ep_active_bomb, EP_ACTIVE_BOMB },
4387 { ep_inactive, EP_INACTIVE },
4389 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4391 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4393 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4394 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4396 { ep_obsolete, EP_OBSOLETE },
4403 /* always start with reliable default values (element has no properties) */
4404 /* (but never initialize clipboard elements after the very first time) */
4405 /* (to be able to use clipboard elements between several levels) */
4406 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4407 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4408 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4409 SET_PROPERTY(i, j, FALSE);
4411 /* set all base element properties from above array definitions */
4412 for (i = 0; element_properties[i].elements != NULL; i++)
4413 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4414 SET_PROPERTY((element_properties[i].elements)[j],
4415 element_properties[i].property, TRUE);
4417 /* copy properties to some elements that are only stored in level file */
4418 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4419 for (j = 0; copy_properties[j][0] != -1; j++)
4420 if (HAS_PROPERTY(copy_properties[j][0], i))
4421 for (k = 1; k <= 4; k++)
4422 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4424 /* set static element properties that are not listed in array definitions */
4425 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4426 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4428 clipboard_elements_initialized = TRUE;
4431 void InitElementPropertiesEngine(int engine_version)
4433 static int no_wall_properties[] =
4436 EP_COLLECTIBLE_ONLY,
4438 EP_DONT_COLLIDE_WITH,
4441 EP_CAN_SMASH_PLAYER,
4442 EP_CAN_SMASH_ENEMIES,
4443 EP_CAN_SMASH_EVERYTHING,
4448 EP_FOOD_DARK_YAMYAM,
4464 /* important: after initialization in InitElementPropertiesStatic(), the
4465 elements are not again initialized to a default value; therefore all
4466 changes have to make sure that they leave the element with a defined
4467 property (which means that conditional property changes must be set to
4468 a reliable default value before) */
4470 /* resolve group elements */
4471 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4472 ResolveGroupElement(EL_GROUP_START + i);
4474 /* set all special, combined or engine dependent element properties */
4475 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4477 /* do not change (already initialized) clipboard elements here */
4478 if (IS_CLIPBOARD_ELEMENT(i))
4481 /* ---------- INACTIVE ------------------------------------------------- */
4482 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4483 i <= EL_CHAR_END) ||
4484 (i >= EL_STEEL_CHAR_START &&
4485 i <= EL_STEEL_CHAR_END)));
4487 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4488 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4489 IS_WALKABLE_INSIDE(i) ||
4490 IS_WALKABLE_UNDER(i)));
4492 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4493 IS_PASSABLE_INSIDE(i) ||
4494 IS_PASSABLE_UNDER(i)));
4496 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4497 IS_PASSABLE_OVER(i)));
4499 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4500 IS_PASSABLE_INSIDE(i)));
4502 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4503 IS_PASSABLE_UNDER(i)));
4505 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4508 /* ---------- COLLECTIBLE ---------------------------------------------- */
4509 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4513 /* ---------- SNAPPABLE ------------------------------------------------ */
4514 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4515 IS_COLLECTIBLE(i) ||
4519 /* ---------- WALL ----------------------------------------------------- */
4520 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4522 for (j = 0; no_wall_properties[j] != -1; j++)
4523 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4524 i >= EL_FIRST_RUNTIME_UNREAL)
4525 SET_PROPERTY(i, EP_WALL, FALSE);
4527 if (IS_HISTORIC_WALL(i))
4528 SET_PROPERTY(i, EP_WALL, TRUE);
4530 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4531 if (engine_version < VERSION_IDENT(2,2,0,0))
4532 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4534 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4536 !IS_COLLECTIBLE(i)));
4538 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4539 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4540 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4542 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4543 IS_INDESTRUCTIBLE(i)));
4545 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4547 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4548 else if (engine_version < VERSION_IDENT(2,2,0,0))
4549 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4551 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4555 if (IS_CUSTOM_ELEMENT(i))
4557 /* these are additional properties which are initially false when set */
4559 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4561 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4562 if (DONT_COLLIDE_WITH(i))
4563 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4565 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4566 if (CAN_SMASH_EVERYTHING(i))
4567 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4568 if (CAN_SMASH_ENEMIES(i))
4569 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4572 /* ---------- CAN_SMASH ------------------------------------------------ */
4573 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4574 CAN_SMASH_ENEMIES(i) ||
4575 CAN_SMASH_EVERYTHING(i)));
4577 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4578 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4579 EXPLODES_BY_FIRE(i)));
4581 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4582 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4583 EXPLODES_SMASHED(i)));
4585 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4586 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4587 EXPLODES_IMPACT(i)));
4589 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4590 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4592 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4593 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4594 i == EL_BLACK_ORB));
4596 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4597 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4599 IS_CUSTOM_ELEMENT(i)));
4601 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4602 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4603 i == EL_SP_ELECTRON));
4605 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4606 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4607 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4608 getMoveIntoAcidProperty(&level, i));
4610 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4611 if (MAYBE_DONT_COLLIDE_WITH(i))
4612 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4613 getDontCollideWithProperty(&level, i));
4615 /* ---------- SP_PORT -------------------------------------------------- */
4616 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4617 IS_PASSABLE_INSIDE(i)));
4619 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4620 for (j = 0; j < level.num_android_clone_elements; j++)
4621 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4623 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4625 /* ---------- CAN_CHANGE ----------------------------------------------- */
4626 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4627 for (j = 0; j < element_info[i].num_change_pages; j++)
4628 if (element_info[i].change_page[j].can_change)
4629 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4631 /* ---------- HAS_ACTION ----------------------------------------------- */
4632 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4633 for (j = 0; j < element_info[i].num_change_pages; j++)
4634 if (element_info[i].change_page[j].has_action)
4635 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4637 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4638 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4641 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4642 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4643 element_info[i].crumbled[ACTION_DEFAULT] !=
4644 element_info[i].graphic[ACTION_DEFAULT]);
4646 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4647 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4648 IS_EDITOR_CASCADE_INACTIVE(i)));
4651 /* dynamically adjust element properties according to game engine version */
4653 static int ep_em_slippery_wall[] =
4658 EL_EXPANDABLE_WALL_HORIZONTAL,
4659 EL_EXPANDABLE_WALL_VERTICAL,
4660 EL_EXPANDABLE_WALL_ANY,
4661 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4662 EL_EXPANDABLE_STEELWALL_VERTICAL,
4663 EL_EXPANDABLE_STEELWALL_ANY,
4664 EL_EXPANDABLE_STEELWALL_GROWING,
4668 static int ep_em_explodes_by_fire[] =
4671 EL_EM_DYNAMITE_ACTIVE,
4676 /* special EM style gems behaviour */
4677 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4678 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4679 level.em_slippery_gems);
4681 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4682 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4683 (level.em_slippery_gems &&
4684 engine_version > VERSION_IDENT(2,0,1,0)));
4686 /* special EM style explosion behaviour regarding chain reactions */
4687 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4688 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4689 level.em_explodes_by_fire);
4692 /* this is needed because some graphics depend on element properties */
4693 if (game_status == GAME_MODE_PLAYING)
4694 InitElementGraphicInfo();
4697 void InitElementPropertiesGfxElement()
4701 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4703 struct ElementInfo *ei = &element_info[i];
4705 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4709 static void InitGlobal()
4714 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4716 /* check if element_name_info entry defined for each element in "main.h" */
4717 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4718 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4720 element_info[i].token_name = element_name_info[i].token_name;
4721 element_info[i].class_name = element_name_info[i].class_name;
4722 element_info[i].editor_description= element_name_info[i].editor_description;
4725 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4727 /* check if global_anim_name_info defined for each entry in "main.h" */
4728 if (i < NUM_GLOBAL_ANIM_TOKENS &&
4729 global_anim_name_info[i].token_name == NULL)
4730 Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4732 global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4735 /* create hash from image config list */
4736 image_config_hash = newSetupFileHash();
4737 for (i = 0; image_config[i].token != NULL; i++)
4738 setHashEntry(image_config_hash,
4739 image_config[i].token,
4740 image_config[i].value);
4742 /* create hash from element token list */
4743 element_token_hash = newSetupFileHash();
4744 for (i = 0; element_name_info[i].token_name != NULL; i++)
4745 setHashEntry(element_token_hash,
4746 element_name_info[i].token_name,
4749 /* create hash from graphic token list */
4750 graphic_token_hash = newSetupFileHash();
4751 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4752 if (strSuffix(image_config[i].value, ".png") ||
4753 strSuffix(image_config[i].value, ".pcx") ||
4754 strSuffix(image_config[i].value, ".wav") ||
4755 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4756 setHashEntry(graphic_token_hash,
4757 image_config[i].token,
4758 int2str(graphic++, 0));
4760 /* create hash from font token list */
4761 font_token_hash = newSetupFileHash();
4762 for (i = 0; font_info[i].token_name != NULL; i++)
4763 setHashEntry(font_token_hash,
4764 font_info[i].token_name,
4767 /* set default filenames for all cloned graphics in static configuration */
4768 for (i = 0; image_config[i].token != NULL; i++)
4770 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4772 char *token = image_config[i].token;
4773 char *token_clone_from = getStringCat2(token, ".clone_from");
4774 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4776 if (token_cloned != NULL)
4778 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4780 if (value_cloned != NULL)
4782 /* set default filename in static configuration */
4783 image_config[i].value = value_cloned;
4785 /* set default filename in image config hash */
4786 setHashEntry(image_config_hash, token, value_cloned);
4790 free(token_clone_from);
4794 /* always start with reliable default values (all elements) */
4795 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4796 ActiveElement[i] = i;
4798 /* now add all entries that have an active state (active elements) */
4799 for (i = 0; element_with_active_state[i].element != -1; i++)
4801 int element = element_with_active_state[i].element;
4802 int element_active = element_with_active_state[i].element_active;
4804 ActiveElement[element] = element_active;
4807 /* always start with reliable default values (all buttons) */
4808 for (i = 0; i < NUM_IMAGE_FILES; i++)
4809 ActiveButton[i] = i;
4811 /* now add all entries that have an active state (active buttons) */
4812 for (i = 0; button_with_active_state[i].button != -1; i++)
4814 int button = button_with_active_state[i].button;
4815 int button_active = button_with_active_state[i].button_active;
4817 ActiveButton[button] = button_active;
4820 /* always start with reliable default values (all fonts) */
4821 for (i = 0; i < NUM_FONTS; i++)
4824 /* now add all entries that have an active state (active fonts) */
4825 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4827 int font = font_with_active_state[i].font_nr;
4828 int font_active = font_with_active_state[i].font_nr_active;
4830 ActiveFont[font] = font_active;
4833 global.autoplay_leveldir = NULL;
4834 global.convert_leveldir = NULL;
4835 global.create_images_dir = NULL;
4837 global.frames_per_second = 0;
4838 global.show_frames_per_second = FALSE;
4840 global.border_status = GAME_MODE_LOADING;
4841 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4843 global.use_envelope_request = FALSE;
4846 void Execute_Command(char *command)
4850 if (strEqual(command, "print graphicsinfo.conf"))
4852 Print("# You can configure additional/alternative image files here.\n");
4853 Print("# (The entries below are default and therefore commented out.)\n");
4855 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4857 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4860 for (i = 0; image_config[i].token != NULL; i++)
4861 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4862 image_config[i].value));
4866 else if (strEqual(command, "print soundsinfo.conf"))
4868 Print("# You can configure additional/alternative sound files here.\n");
4869 Print("# (The entries below are default and therefore commented out.)\n");
4871 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4873 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4876 for (i = 0; sound_config[i].token != NULL; i++)
4877 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4878 sound_config[i].value));
4882 else if (strEqual(command, "print musicinfo.conf"))
4884 Print("# You can configure additional/alternative music files here.\n");
4885 Print("# (The entries below are default and therefore commented out.)\n");
4887 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4889 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4892 for (i = 0; music_config[i].token != NULL; i++)
4893 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4894 music_config[i].value));
4898 else if (strEqual(command, "print editorsetup.conf"))
4900 Print("# You can configure your personal editor element list here.\n");
4901 Print("# (The entries below are default and therefore commented out.)\n");
4904 /* this is needed to be able to check element list for cascade elements */
4905 InitElementPropertiesStatic();
4906 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4908 PrintEditorElementList();
4912 else if (strEqual(command, "print helpanim.conf"))
4914 Print("# You can configure different element help animations here.\n");
4915 Print("# (The entries below are default and therefore commented out.)\n");
4918 for (i = 0; helpanim_config[i].token != NULL; i++)
4920 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4921 helpanim_config[i].value));
4923 if (strEqual(helpanim_config[i].token, "end"))
4929 else if (strEqual(command, "print helptext.conf"))
4931 Print("# You can configure different element help text here.\n");
4932 Print("# (The entries below are default and therefore commented out.)\n");
4935 for (i = 0; helptext_config[i].token != NULL; i++)
4936 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4937 helptext_config[i].value));
4941 else if (strPrefix(command, "dump level "))
4943 char *filename = &command[11];
4945 if (!fileExists(filename))
4946 Error(ERR_EXIT, "cannot open file '%s'", filename);
4948 LoadLevelFromFilename(&level, filename);
4953 else if (strPrefix(command, "dump tape "))
4955 char *filename = &command[10];
4957 if (!fileExists(filename))
4958 Error(ERR_EXIT, "cannot open file '%s'", filename);
4960 LoadTapeFromFilename(filename);
4965 else if (strPrefix(command, "autotest ") ||
4966 strPrefix(command, "autoplay ") ||
4967 strPrefix(command, "autoffwd ") ||
4968 strPrefix(command, "autowarp "))
4970 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4972 global.autoplay_mode =
4973 (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
4974 strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
4975 strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
4976 strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
4977 AUTOPLAY_MODE_NONE);
4979 while (*str_ptr != '\0') /* continue parsing string */
4981 /* cut leading whitespace from string, replace it by string terminator */
4982 while (*str_ptr == ' ' || *str_ptr == '\t')
4985 if (*str_ptr == '\0') /* end of string reached */
4988 if (global.autoplay_leveldir == NULL) /* read level set string */
4990 global.autoplay_leveldir = str_ptr;
4991 global.autoplay_all = TRUE; /* default: play all tapes */
4993 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4994 global.autoplay_level[i] = FALSE;
4996 else /* read level number string */
4998 int level_nr = atoi(str_ptr); /* get level_nr value */
5000 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5001 global.autoplay_level[level_nr] = TRUE;
5003 global.autoplay_all = FALSE;
5006 /* advance string pointer to the next whitespace (or end of string) */
5007 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5011 if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5012 program.headless = TRUE;
5014 else if (strPrefix(command, "convert "))
5016 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5017 char *str_ptr = strchr(str_copy, ' ');
5019 global.convert_leveldir = str_copy;
5020 global.convert_level_nr = -1;
5022 if (str_ptr != NULL) /* level number follows */
5024 *str_ptr++ = '\0'; /* terminate leveldir string */
5025 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5028 program.headless = TRUE;
5030 else if (strPrefix(command, "create images "))
5032 global.create_images_dir = getStringCopy(&command[14]);
5034 if (access(global.create_images_dir, W_OK) != 0)
5035 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5036 global.create_images_dir);
5038 else if (strPrefix(command, "create CE image "))
5040 CreateCustomElementImages(&command[16]);
5046 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5050 static void InitSetup()
5052 LoadSetup(); /* global setup info */
5053 LoadSetup_AutoSetup(); /* global auto setup info */
5055 /* set some options from setup file */
5057 if (setup.options.verbose)
5058 options.verbose = TRUE;
5060 if (setup.debug.show_frames_per_second)
5061 global.show_frames_per_second = TRUE;
5064 static void InitGameInfo()
5066 game.restart_level = FALSE;
5069 static void InitPlayerInfo()
5073 /* choose default local player */
5074 local_player = &stored_player[0];
5076 for (i = 0; i < MAX_PLAYERS; i++)
5077 stored_player[i].connected = FALSE;
5079 local_player->connected = TRUE;
5082 static void InitArtworkInfo()
5087 static char *get_string_in_brackets(char *string)
5089 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5091 sprintf(string_in_brackets, "[%s]", string);
5093 return string_in_brackets;
5096 static char *get_level_id_suffix(int id_nr)
5098 char *id_suffix = checked_malloc(1 + 3 + 1);
5100 if (id_nr < 0 || id_nr > 999)
5103 sprintf(id_suffix, ".%03d", id_nr);
5108 static void InitArtworkConfig()
5110 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5112 NUM_GLOBAL_ANIM_TOKENS + 1];
5113 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5114 NUM_GLOBAL_ANIM_TOKENS + 1];
5115 static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5116 NUM_GLOBAL_ANIM_TOKENS + 1];
5117 static char *action_id_suffix[NUM_ACTIONS + 1];
5118 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5119 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5120 static char *level_id_suffix[MAX_LEVELS + 1];
5121 static char *dummy[1] = { NULL };
5122 static char *ignore_generic_tokens[] =
5128 static char **ignore_image_tokens;
5129 static char **ignore_sound_tokens;
5130 static char **ignore_music_tokens;
5131 int num_ignore_generic_tokens;
5132 int num_ignore_image_tokens;
5133 int num_ignore_sound_tokens;
5134 int num_ignore_music_tokens;
5137 /* dynamically determine list of generic tokens to be ignored */
5138 num_ignore_generic_tokens = 0;
5139 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5140 num_ignore_generic_tokens++;
5142 /* dynamically determine list of image tokens to be ignored */
5143 num_ignore_image_tokens = num_ignore_generic_tokens;
5144 for (i = 0; image_config_vars[i].token != NULL; i++)
5145 num_ignore_image_tokens++;
5146 ignore_image_tokens =
5147 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5148 for (i = 0; i < num_ignore_generic_tokens; i++)
5149 ignore_image_tokens[i] = ignore_generic_tokens[i];
5150 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5151 ignore_image_tokens[num_ignore_generic_tokens + i] =
5152 image_config_vars[i].token;
5153 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5155 /* dynamically determine list of sound tokens to be ignored */
5156 num_ignore_sound_tokens = num_ignore_generic_tokens;
5157 ignore_sound_tokens =
5158 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5159 for (i = 0; i < num_ignore_generic_tokens; i++)
5160 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5161 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5163 /* dynamically determine list of music tokens to be ignored */
5164 num_ignore_music_tokens = num_ignore_generic_tokens;
5165 ignore_music_tokens =
5166 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5167 for (i = 0; i < num_ignore_generic_tokens; i++)
5168 ignore_music_tokens[i] = ignore_generic_tokens[i];
5169 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5171 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5172 image_id_prefix[i] = element_info[i].token_name;
5173 for (i = 0; i < NUM_FONTS; i++)
5174 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5175 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5176 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5177 global_anim_info[i].token_name;
5178 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5180 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5181 sound_id_prefix[i] = element_info[i].token_name;
5182 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5183 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5184 get_string_in_brackets(element_info[i].class_name);
5185 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5186 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5187 global_anim_info[i].token_name;
5188 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5190 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5191 music_id_prefix[i] = music_prefix_info[i].prefix;
5192 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5193 music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5194 global_anim_info[i].token_name;
5195 music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5197 for (i = 0; i < NUM_ACTIONS; i++)
5198 action_id_suffix[i] = element_action_info[i].suffix;
5199 action_id_suffix[NUM_ACTIONS] = NULL;
5201 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5202 direction_id_suffix[i] = element_direction_info[i].suffix;
5203 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5205 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5206 special_id_suffix[i] = special_suffix_info[i].suffix;
5207 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5209 for (i = 0; i < MAX_LEVELS; i++)
5210 level_id_suffix[i] = get_level_id_suffix(i);
5211 level_id_suffix[MAX_LEVELS] = NULL;
5213 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5214 image_id_prefix, action_id_suffix, direction_id_suffix,
5215 special_id_suffix, ignore_image_tokens);
5216 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5217 sound_id_prefix, action_id_suffix, dummy,
5218 special_id_suffix, ignore_sound_tokens);
5219 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5220 music_id_prefix, action_id_suffix, special_id_suffix,
5221 level_id_suffix, ignore_music_tokens);
5224 static void InitMixer()
5231 void InitGfxBuffers()
5233 static int win_xsize_last = -1;
5234 static int win_ysize_last = -1;
5236 /* create additional image buffers for double-buffering and cross-fading */
5238 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5240 /* used to temporarily store the backbuffer -- only re-create if changed */
5241 ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5242 ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5244 win_xsize_last = WIN_XSIZE;
5245 win_ysize_last = WIN_YSIZE;
5248 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5249 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5250 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5251 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5253 /* initialize screen properties */
5254 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5255 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5257 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5258 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5259 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5260 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5261 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5262 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5264 /* required if door size definitions have changed */
5265 InitGraphicCompatibilityInfo_Doors();
5267 InitGfxBuffers_EM();
5268 InitGfxBuffers_SP();
5273 struct GraphicInfo *graphic_info_last = graphic_info;
5274 char *filename_font_initial = NULL;
5275 char *filename_anim_initial = NULL;
5276 Bitmap *bitmap_font_initial = NULL;
5280 /* determine settings for initial font (for displaying startup messages) */
5281 for (i = 0; image_config[i].token != NULL; i++)
5283 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5285 char font_token[128];
5288 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5289 len_font_token = strlen(font_token);
5291 if (strEqual(image_config[i].token, font_token))
5292 filename_font_initial = image_config[i].value;
5293 else if (strlen(image_config[i].token) > len_font_token &&
5294 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5296 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5297 font_initial[j].src_x = atoi(image_config[i].value);
5298 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5299 font_initial[j].src_y = atoi(image_config[i].value);
5300 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5301 font_initial[j].width = atoi(image_config[i].value);
5302 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5303 font_initial[j].height = atoi(image_config[i].value);
5308 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5310 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5311 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5314 if (filename_font_initial == NULL) /* should not happen */
5315 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5318 InitGfxCustomArtworkInfo();
5319 InitGfxOtherSettings();
5321 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5323 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5324 font_initial[j].bitmap = bitmap_font_initial;
5326 InitFontGraphicInfo();
5328 font_height = getFontHeight(FC_RED);
5330 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5331 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5332 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5335 DrawInitText("Loading graphics", 120, FC_GREEN);
5337 /* initialize settings for busy animation with default values */
5338 int parameter[NUM_GFX_ARGS];
5339 for (i = 0; i < NUM_GFX_ARGS; i++)
5340 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5341 image_config_suffix[i].token,
5342 image_config_suffix[i].type);
5344 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5345 int len_anim_token = strlen(anim_token);
5347 /* read settings for busy animation from default custom artwork config */
5348 char *gfx_config_filename = getPath3(options.graphics_directory,
5350 GRAPHICSINFO_FILENAME);
5352 if (fileExists(gfx_config_filename))
5354 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5356 if (setup_file_hash)
5358 char *filename = getHashEntry(setup_file_hash, anim_token);
5362 filename_anim_initial = getStringCopy(filename);
5364 for (j = 0; image_config_suffix[j].token != NULL; j++)
5366 int type = image_config_suffix[j].type;
5367 char *suffix = image_config_suffix[j].token;
5368 char *token = getStringCat2(anim_token, suffix);
5369 char *value = getHashEntry(setup_file_hash, token);
5371 checked_free(token);
5374 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5378 freeSetupFileHash(setup_file_hash);
5382 if (filename_anim_initial == NULL)
5384 /* read settings for busy animation from static default artwork config */
5385 for (i = 0; image_config[i].token != NULL; i++)
5387 if (strEqual(image_config[i].token, anim_token))
5388 filename_anim_initial = getStringCopy(image_config[i].value);
5389 else if (strlen(image_config[i].token) > len_anim_token &&
5390 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5392 for (j = 0; image_config_suffix[j].token != NULL; j++)
5394 if (strEqual(&image_config[i].token[len_anim_token],
5395 image_config_suffix[j].token))
5397 get_graphic_parameter_value(image_config[i].value,
5398 image_config_suffix[j].token,
5399 image_config_suffix[j].type);
5405 if (filename_anim_initial == NULL) /* should not happen */
5406 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5408 anim_initial.bitmaps =
5409 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5411 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5412 LoadCustomImage(filename_anim_initial);
5414 checked_free(filename_anim_initial);
5416 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5418 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5420 graphic_info = graphic_info_last;
5422 init.busy.width = anim_initial.width;
5423 init.busy.height = anim_initial.height;
5425 InitMenuDesignSettings_Static();
5427 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5428 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5429 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5431 gfx.fade_border_source_status = global.border_status;
5432 gfx.fade_border_target_status = global.border_status;
5433 gfx.masked_border_bitmap_ptr = backbuffer;
5435 /* use copy of busy animation to prevent change while reloading artwork */
5439 void InitGfxBackground()
5441 fieldbuffer = bitmap_db_field;
5442 SetDrawtoField(DRAW_TO_BACKBUFFER);
5444 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5446 redraw_mask = REDRAW_ALL;
5449 static void InitLevelInfo()
5451 LoadLevelInfo(); /* global level info */
5452 LoadLevelSetup_LastSeries(); /* last played series info */
5453 LoadLevelSetup_SeriesInfo(); /* last played level info */
5455 if (global.autoplay_leveldir &&
5456 global.autoplay_mode != AUTOPLAY_MODE_TEST)
5458 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5459 global.autoplay_leveldir);
5460 if (leveldir_current == NULL)
5461 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5465 static void InitLevelArtworkInfo()
5467 LoadLevelArtworkInfo();
5470 static void InitImages()
5472 print_timestamp_init("InitImages");
5475 printf("::: leveldir_current->identifier == '%s'\n",
5476 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5477 printf("::: leveldir_current->graphics_path == '%s'\n",
5478 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5479 printf("::: leveldir_current->graphics_set == '%s'\n",
5480 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5481 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5482 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5485 setLevelArtworkDir(artwork.gfx_first);
5488 printf("::: leveldir_current->identifier == '%s'\n",
5489 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5490 printf("::: leveldir_current->graphics_path == '%s'\n",
5491 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5492 printf("::: leveldir_current->graphics_set == '%s'\n",
5493 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5494 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5495 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5499 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5500 leveldir_current->identifier,
5501 artwork.gfx_current_identifier,
5502 artwork.gfx_current->identifier,
5503 leveldir_current->graphics_set,
5504 leveldir_current->graphics_path);
5507 UPDATE_BUSY_STATE();
5509 ReloadCustomImages();
5510 print_timestamp_time("ReloadCustomImages");
5512 UPDATE_BUSY_STATE();
5514 LoadCustomElementDescriptions();
5515 print_timestamp_time("LoadCustomElementDescriptions");
5517 UPDATE_BUSY_STATE();
5519 LoadMenuDesignSettings();
5520 print_timestamp_time("LoadMenuDesignSettings");
5522 UPDATE_BUSY_STATE();
5524 ReinitializeGraphics();
5525 print_timestamp_time("ReinitializeGraphics");
5527 LoadMenuDesignSettings_AfterGraphics();
5528 print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5530 UPDATE_BUSY_STATE();
5532 print_timestamp_done("InitImages");
5535 static void InitSound(char *identifier)
5537 print_timestamp_init("InitSound");
5539 if (identifier == NULL)
5540 identifier = artwork.snd_current->identifier;
5542 /* set artwork path to send it to the sound server process */
5543 setLevelArtworkDir(artwork.snd_first);
5545 InitReloadCustomSounds(identifier);
5546 print_timestamp_time("InitReloadCustomSounds");
5548 ReinitializeSounds();
5549 print_timestamp_time("ReinitializeSounds");
5551 print_timestamp_done("InitSound");
5554 static void InitMusic(char *identifier)
5556 print_timestamp_init("InitMusic");
5558 if (identifier == NULL)
5559 identifier = artwork.mus_current->identifier;
5561 /* set artwork path to send it to the sound server process */
5562 setLevelArtworkDir(artwork.mus_first);
5564 InitReloadCustomMusic(identifier);
5565 print_timestamp_time("InitReloadCustomMusic");
5567 ReinitializeMusic();
5568 print_timestamp_time("ReinitializeMusic");
5570 print_timestamp_done("InitMusic");
5573 static void InitArtworkDone()
5575 if (program.headless)
5578 InitGlobalAnimations();
5581 void InitNetworkServer()
5583 #if defined(NETWORK_AVALIABLE)
5587 if (!options.network)
5590 #if defined(NETWORK_AVALIABLE)
5591 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5593 if (!ConnectToServer(options.server_host, options.server_port))
5594 Error(ERR_EXIT, "cannot connect to network game server");
5596 SendToServer_PlayerName(setup.player_name);
5597 SendToServer_ProtocolVersion();
5600 SendToServer_NrWanted(nr_wanted);
5604 static boolean CheckArtworkConfigForCustomElements(char *filename)
5606 SetupFileHash *setup_file_hash;
5607 boolean redefined_ce_found = FALSE;
5609 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5611 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5613 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5615 char *token = HASH_ITERATION_TOKEN(itr);
5617 if (strPrefix(token, "custom_"))
5619 redefined_ce_found = TRUE;
5624 END_HASH_ITERATION(setup_file_hash, itr)
5626 freeSetupFileHash(setup_file_hash);
5629 return redefined_ce_found;
5632 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5634 char *filename_base, *filename_local;
5635 boolean redefined_ce_found = FALSE;
5637 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5640 printf("::: leveldir_current->identifier == '%s'\n",
5641 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5642 printf("::: leveldir_current->graphics_path == '%s'\n",
5643 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5644 printf("::: leveldir_current->graphics_set == '%s'\n",
5645 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5646 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5647 leveldir_current == NULL ? "[NULL]" :
5648 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5651 /* first look for special artwork configured in level series config */
5652 filename_base = getCustomArtworkLevelConfigFilename(type);
5655 printf("::: filename_base == '%s'\n", filename_base);
5658 if (fileExists(filename_base))
5659 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5661 filename_local = getCustomArtworkConfigFilename(type);
5664 printf("::: filename_local == '%s'\n", filename_local);
5667 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5668 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5671 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5674 return redefined_ce_found;
5677 static void InitOverrideArtwork()
5679 boolean redefined_ce_found = FALSE;
5681 /* to check if this level set redefines any CEs, do not use overriding */
5682 gfx.override_level_graphics = FALSE;
5683 gfx.override_level_sounds = FALSE;
5684 gfx.override_level_music = FALSE;
5686 /* now check if this level set has definitions for custom elements */
5687 if (setup.override_level_graphics == AUTO ||
5688 setup.override_level_sounds == AUTO ||
5689 setup.override_level_music == AUTO)
5690 redefined_ce_found =
5691 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5692 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5693 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5696 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5699 if (redefined_ce_found)
5701 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5702 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5703 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5704 gfx.override_level_music = (setup.override_level_music == TRUE);
5708 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5709 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5710 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5711 gfx.override_level_music = (setup.override_level_music != FALSE);
5715 printf("::: => %d, %d, %d\n",
5716 gfx.override_level_graphics,
5717 gfx.override_level_sounds,
5718 gfx.override_level_music);
5722 static char *getNewArtworkIdentifier(int type)
5724 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5725 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5726 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5727 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5728 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5729 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5730 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5731 char *leveldir_identifier = leveldir_current->identifier;
5732 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5733 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5734 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5735 char *artwork_current_identifier;
5736 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5738 /* leveldir_current may be invalid (level group, parent link) */
5739 if (!validLevelSeries(leveldir_current))
5742 /* 1st step: determine artwork set to be activated in descending order:
5743 --------------------------------------------------------------------
5744 1. setup artwork (when configured to override everything else)
5745 2. artwork set configured in "levelinfo.conf" of current level set
5746 (artwork in level directory will have priority when loading later)
5747 3. artwork in level directory (stored in artwork sub-directory)
5748 4. setup artwork (currently configured in setup menu) */
5750 if (setup_override_artwork)
5751 artwork_current_identifier = setup_artwork_set;
5752 else if (leveldir_artwork_set != NULL)
5753 artwork_current_identifier = leveldir_artwork_set;
5754 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5755 artwork_current_identifier = leveldir_identifier;
5757 artwork_current_identifier = setup_artwork_set;
5760 /* 2nd step: check if it is really needed to reload artwork set
5761 ------------------------------------------------------------ */
5763 /* ---------- reload if level set and also artwork set has changed ------- */
5764 if (leveldir_current_identifier[type] != leveldir_identifier &&
5765 (last_has_level_artwork_set[type] || has_level_artwork_set))
5766 artwork_new_identifier = artwork_current_identifier;
5768 leveldir_current_identifier[type] = leveldir_identifier;
5769 last_has_level_artwork_set[type] = has_level_artwork_set;
5771 /* ---------- reload if "override artwork" setting has changed ----------- */
5772 if (last_override_level_artwork[type] != setup_override_artwork)
5773 artwork_new_identifier = artwork_current_identifier;
5775 last_override_level_artwork[type] = setup_override_artwork;
5777 /* ---------- reload if current artwork identifier has changed ----------- */
5778 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5779 artwork_current_identifier))
5780 artwork_new_identifier = artwork_current_identifier;
5782 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5784 /* ---------- do not reload directly after starting ---------------------- */
5785 if (!initialized[type])
5786 artwork_new_identifier = NULL;
5788 initialized[type] = TRUE;
5790 return artwork_new_identifier;
5793 void ReloadCustomArtwork(int force_reload)
5795 int last_game_status = game_status; /* save current game status */
5796 char *gfx_new_identifier;
5797 char *snd_new_identifier;
5798 char *mus_new_identifier;
5799 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5800 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5801 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5802 boolean reload_needed;
5804 InitOverrideArtwork();
5806 force_reload_gfx |= AdjustGraphicsForEMC();
5808 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5809 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5810 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5812 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5813 snd_new_identifier != NULL || force_reload_snd ||
5814 mus_new_identifier != NULL || force_reload_mus);
5819 print_timestamp_init("ReloadCustomArtwork");
5821 SetGameStatus(GAME_MODE_LOADING);
5823 FadeOut(REDRAW_ALL);
5825 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5826 print_timestamp_time("ClearRectangle");
5830 if (gfx_new_identifier != NULL || force_reload_gfx)
5833 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5834 artwork.gfx_current_identifier,
5836 artwork.gfx_current->identifier,
5837 leveldir_current->graphics_set);
5841 print_timestamp_time("InitImages");
5844 if (snd_new_identifier != NULL || force_reload_snd)
5846 InitSound(snd_new_identifier);
5847 print_timestamp_time("InitSound");
5850 if (mus_new_identifier != NULL || force_reload_mus)
5852 InitMusic(mus_new_identifier);
5853 print_timestamp_time("InitMusic");
5858 SetGameStatus(last_game_status); /* restore current game status */
5860 init_last = init; /* switch to new busy animation */
5862 FadeOut(REDRAW_ALL);
5864 RedrawGlobalBorder();
5866 /* force redraw of (open or closed) door graphics */
5867 SetDoorState(DOOR_OPEN_ALL);
5868 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5870 FadeSetEnterScreen();
5871 FadeSkipNextFadeOut();
5873 print_timestamp_done("ReloadCustomArtwork");
5875 LimitScreenUpdates(FALSE);
5878 void KeyboardAutoRepeatOffUnlessAutoplay()
5880 if (global.autoplay_leveldir == NULL)
5881 KeyboardAutoRepeatOff();
5884 void DisplayExitMessage(char *format, va_list ap)
5886 // also check for initialized video (headless flag may be temporarily unset)
5887 if (program.headless || !video.initialized)
5890 // check if draw buffer and fonts for exit message are already available
5891 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5894 int font_1 = FC_RED;
5895 int font_2 = FC_YELLOW;
5896 int font_3 = FC_BLUE;
5897 int font_width = getFontWidth(font_2);
5898 int font_height = getFontHeight(font_2);
5901 int sxsize = WIN_XSIZE - 2 * sx;
5902 int sysize = WIN_YSIZE - 2 * sy;
5903 int line_length = sxsize / font_width;
5904 int max_lines = sysize / font_height;
5905 int num_lines_printed;
5909 gfx.sxsize = sxsize;
5910 gfx.sysize = sysize;
5914 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5916 DrawTextSCentered(sy, font_1, "Fatal error:");
5917 sy += 3 * font_height;;
5920 DrawTextBufferVA(sx, sy, format, ap, font_2,
5921 line_length, line_length, max_lines,
5922 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5923 sy += (num_lines_printed + 3) * font_height;
5925 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5926 sy += 3 * font_height;
5929 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5930 line_length, line_length, max_lines,
5931 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5933 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5935 redraw_mask = REDRAW_ALL;
5937 /* force drawing exit message even if screen updates are currently limited */
5938 LimitScreenUpdates(FALSE);
5942 /* deactivate toons on error message screen */
5943 setup.toons = FALSE;
5945 WaitForEventToContinue();
5949 /* ========================================================================= */
5951 /* ========================================================================= */
5955 print_timestamp_init("OpenAll");
5957 SetGameStatus(GAME_MODE_LOADING);
5961 InitGlobal(); /* initialize some global variables */
5963 print_timestamp_time("[init global stuff]");
5967 print_timestamp_time("[init setup/config stuff (1)]");
5971 if (options.execute_command)
5972 Execute_Command(options.execute_command);
5974 if (options.serveronly)
5976 #if defined(PLATFORM_UNIX)
5977 NetworkServer(options.server_port, options.serveronly);
5979 Error(ERR_WARN, "networking only supported in Unix version");
5982 exit(0); /* never reached, server loops forever */
5986 print_timestamp_time("[init setup/config stuff (2)]");
5988 print_timestamp_time("[init setup/config stuff (3)]");
5989 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5990 print_timestamp_time("[init setup/config stuff (4)]");
5991 InitArtworkConfig(); /* needed before forking sound child process */
5992 print_timestamp_time("[init setup/config stuff (5)]");
5994 print_timestamp_time("[init setup/config stuff (6)]");
5996 InitRND(NEW_RANDOMIZE);
5997 InitSimpleRandom(NEW_RANDOMIZE);
6001 print_timestamp_time("[init setup/config stuff]");
6003 InitVideoDefaults();
6005 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6009 print_timestamp_time("[init video stuff]");
6011 InitElementPropertiesStatic();
6012 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6013 InitElementPropertiesGfxElement();
6015 print_timestamp_time("[init element properties stuff]");
6019 print_timestamp_time("InitGfx");
6022 print_timestamp_time("InitLevelInfo");
6024 InitLevelArtworkInfo();
6025 print_timestamp_time("InitLevelArtworkInfo");
6027 InitOverrideArtwork(); /* needs to know current level directory */
6028 print_timestamp_time("InitOverrideArtwork");
6030 InitImages(); /* needs to know current level directory */
6031 print_timestamp_time("InitImages");
6033 InitSound(NULL); /* needs to know current level directory */
6034 print_timestamp_time("InitSound");
6036 InitMusic(NULL); /* needs to know current level directory */
6037 print_timestamp_time("InitMusic");
6041 InitGfxBackground();
6047 if (global.autoplay_leveldir)
6052 else if (global.convert_leveldir)
6057 else if (global.create_images_dir)
6059 CreateLevelSketchImages();
6063 SetGameStatus(GAME_MODE_MAIN);
6065 FadeSetEnterScreen();
6066 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6067 FadeSkipNextFadeOut();
6069 print_timestamp_time("[post-artwork]");
6071 print_timestamp_done("OpenAll");
6075 InitNetworkServer();
6078 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6080 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6081 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6082 #if defined(PLATFORM_ANDROID)
6083 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6084 SDL_AndroidGetInternalStoragePath());
6085 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6086 SDL_AndroidGetExternalStoragePath());
6087 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6088 (SDL_AndroidGetExternalStorageState() &
6089 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6090 SDL_AndroidGetExternalStorageState() &
6091 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6096 void CloseAllAndExit(int exit_value)
6101 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6108 #if defined(TARGET_SDL)
6109 #if defined(TARGET_SDL2)
6111 // set a flag to tell the network server thread to quit and wait for it
6112 // using SDL_WaitThread()
6114 if (network_server) /* terminate network server */
6115 SDL_KillThread(server_thread);
6119 CloseVideoDisplay();
6120 ClosePlatformDependentStuff();
6122 if (exit_value != 0 && !options.execute_command)
6124 /* fall back to default level set (current set may have caused an error) */
6125 SaveLevelSetup_LastSeries_Deactivate();
6127 /* tell user where to find error log file which may contain more details */
6128 // (error notification now directly displayed on screen inside R'n'D
6129 // NotifyUserAboutErrorFile(); /* currently only works for Windows */