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
89 struct GraphicInfo *graphic_info_last = graphic_info;
91 static unsigned int action_delay = 0;
92 unsigned int action_delay_value = GameFrameDelay;
93 int sync_frame = FrameCounter;
96 if (game_status != GAME_MODE_LOADING)
99 if (anim_initial.bitmap == NULL || window == NULL)
102 if (!DelayReached(&action_delay, action_delay_value))
105 if (init_last.busy.x == -1)
106 init_last.busy.x = WIN_XSIZE / 2;
107 if (init_last.busy.y == -1)
108 init_last.busy.y = WIN_YSIZE / 2;
110 x = ALIGNED_TEXT_XPOS(&init_last.busy);
111 y = ALIGNED_TEXT_YPOS(&init_last.busy);
113 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
115 if (sync_frame % anim_initial.anim_delay == 0)
119 int width = graphic_info[graphic].width;
120 int height = graphic_info[graphic].height;
121 int frame = getGraphicAnimationFrame(graphic, sync_frame);
123 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
124 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
127 graphic_info = graphic_info_last;
134 FreeLevelEditorGadgets();
143 static boolean gadgets_initialized = FALSE;
145 if (gadgets_initialized)
148 CreateLevelEditorGadgets();
152 CreateScreenGadgets();
154 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
156 gadgets_initialized = TRUE;
159 inline static void InitElementSmallImagesScaledUp(int graphic)
161 struct GraphicInfo *g = &graphic_info[graphic];
163 // create small and game tile sized bitmaps (and scale up, if needed)
164 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
167 void InitElementSmallImages()
169 print_timestamp_init("InitElementSmallImages");
171 static int special_graphics[] =
173 IMG_EDITOR_ELEMENT_BORDER,
174 IMG_EDITOR_ELEMENT_BORDER_INPUT,
175 IMG_EDITOR_CASCADE_LIST,
176 IMG_EDITOR_CASCADE_LIST_ACTIVE,
179 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
180 int num_property_mappings = getImageListPropertyMappingSize();
183 print_timestamp_time("getImageListPropertyMapping/Size");
185 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
186 /* initialize normal images from static configuration */
187 for (i = 0; element_to_graphic[i].element > -1; i++)
188 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
189 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
191 /* initialize special images from static configuration */
192 for (i = 0; element_to_special_graphic[i].element > -1; i++)
193 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
194 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
196 /* initialize images from dynamic configuration (may be elements or other) */
197 for (i = 0; i < num_property_mappings; i++)
198 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
199 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
201 /* initialize special images from above list (non-element images) */
202 for (i = 0; special_graphics[i] > -1; i++)
203 InitElementSmallImagesScaledUp(special_graphics[i]);
204 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
206 print_timestamp_done("InitElementSmallImages");
209 void InitScaledImages()
213 /* scale normal images from static configuration, if not already scaled */
214 for (i = 0; i < NUM_IMAGE_FILES; i++)
215 ScaleImage(i, graphic_info[i].scale_up_factor);
218 void InitBitmapPointers()
220 int num_images = getImageListSize();
223 // standard size bitmap may have changed -- update default bitmap pointer
224 for (i = 0; i < num_images; i++)
225 if (graphic_info[i].bitmaps)
226 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
229 void InitImageTextures()
233 FreeAllImageTextures();
235 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
236 CreateImageTextures(i);
238 for (i = 0; i < MAX_NUM_TOONS; i++)
239 CreateImageTextures(IMG_TOON_1 + i);
241 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
243 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
245 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
247 int graphic = global_anim_info[i].graphic[j][k];
249 if (graphic == IMG_UNDEFINED)
252 CreateImageTextures(graphic);
259 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
260 void SetBitmaps_EM(Bitmap **em_bitmap)
262 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
263 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
268 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
269 void SetBitmaps_SP(Bitmap **sp_bitmap)
271 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
275 static int getFontBitmapID(int font_nr)
279 /* (special case: do not use special font for GAME_MODE_LOADING) */
280 if (game_status >= GAME_MODE_TITLE_INITIAL &&
281 game_status <= GAME_MODE_PSEUDO_PREVIEW)
282 special = game_status;
283 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
284 special = GFX_SPECIAL_ARG_MAIN;
287 return font_info[font_nr].special_bitmap_id[special];
292 static int getFontFromToken(char *token)
294 char *value = getHashEntry(font_token_hash, token);
299 /* if font not found, use reliable default value */
300 return FONT_INITIAL_1;
303 void InitFontGraphicInfo()
305 static struct FontBitmapInfo *font_bitmap_info = NULL;
306 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
307 int num_property_mappings = getImageListPropertyMappingSize();
308 int num_font_bitmaps = NUM_FONTS;
311 if (graphic_info == NULL) /* still at startup phase */
313 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
314 getFontBitmapID, getFontFromToken);
319 /* ---------- initialize font graphic definitions ---------- */
321 /* always start with reliable default values (normal font graphics) */
322 for (i = 0; i < NUM_FONTS; i++)
323 font_info[i].graphic = IMG_FONT_INITIAL_1;
325 /* initialize normal font/graphic mapping from static configuration */
326 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
328 int font_nr = font_to_graphic[i].font_nr;
329 int special = font_to_graphic[i].special;
330 int graphic = font_to_graphic[i].graphic;
335 font_info[font_nr].graphic = graphic;
338 /* always start with reliable default values (special font graphics) */
339 for (i = 0; i < NUM_FONTS; i++)
341 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
343 font_info[i].special_graphic[j] = font_info[i].graphic;
344 font_info[i].special_bitmap_id[j] = i;
348 /* initialize special font/graphic mapping from static configuration */
349 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
351 int font_nr = font_to_graphic[i].font_nr;
352 int special = font_to_graphic[i].special;
353 int graphic = font_to_graphic[i].graphic;
354 int base_graphic = font2baseimg(font_nr);
356 if (IS_SPECIAL_GFX_ARG(special))
358 boolean base_redefined =
359 getImageListEntryFromImageID(base_graphic)->redefined;
360 boolean special_redefined =
361 getImageListEntryFromImageID(graphic)->redefined;
362 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
364 /* if the base font ("font.title_1", for example) has been redefined,
365 but not the special font ("font.title_1.LEVELS", for example), do not
366 use an existing (in this case considered obsolete) special font
367 anymore, but use the automatically determined default font */
368 /* special case: cloned special fonts must be explicitly redefined,
369 but are not automatically redefined by redefining base font */
370 if (base_redefined && !special_redefined && !special_cloned)
373 font_info[font_nr].special_graphic[special] = graphic;
374 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
379 /* initialize special font/graphic mapping from dynamic configuration */
380 for (i = 0; i < num_property_mappings; i++)
382 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
383 int special = property_mapping[i].ext3_index;
384 int graphic = property_mapping[i].artwork_index;
389 if (IS_SPECIAL_GFX_ARG(special))
391 font_info[font_nr].special_graphic[special] = graphic;
392 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
397 /* correct special font/graphic mapping for cloned fonts for downwards
398 compatibility of PREVIEW fonts -- this is only needed for implicit
399 redefinition of special font by redefined base font, and only if other
400 fonts are cloned from this special font (like in the "Zelda" level set) */
401 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
403 int font_nr = font_to_graphic[i].font_nr;
404 int special = font_to_graphic[i].special;
405 int graphic = font_to_graphic[i].graphic;
407 if (IS_SPECIAL_GFX_ARG(special))
409 boolean special_redefined =
410 getImageListEntryFromImageID(graphic)->redefined;
411 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
413 if (special_cloned && !special_redefined)
417 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
419 int font_nr2 = font_to_graphic[j].font_nr;
420 int special2 = font_to_graphic[j].special;
421 int graphic2 = font_to_graphic[j].graphic;
423 if (IS_SPECIAL_GFX_ARG(special2) &&
424 graphic2 == graphic_info[graphic].clone_from)
426 font_info[font_nr].special_graphic[special] =
427 font_info[font_nr2].special_graphic[special2];
428 font_info[font_nr].special_bitmap_id[special] =
429 font_info[font_nr2].special_bitmap_id[special2];
436 /* reset non-redefined ".active" font graphics if normal font is redefined */
437 /* (this different treatment is needed because normal and active fonts are
438 independently defined ("active" is not a property of font definitions!) */
439 for (i = 0; i < NUM_FONTS; i++)
441 int font_nr_base = i;
442 int font_nr_active = FONT_ACTIVE(font_nr_base);
444 /* check only those fonts with exist as normal and ".active" variant */
445 if (font_nr_base != font_nr_active)
447 int base_graphic = font_info[font_nr_base].graphic;
448 int active_graphic = font_info[font_nr_active].graphic;
449 boolean base_redefined =
450 getImageListEntryFromImageID(base_graphic)->redefined;
451 boolean active_redefined =
452 getImageListEntryFromImageID(active_graphic)->redefined;
454 /* if the base font ("font.menu_1", for example) has been redefined,
455 but not the active font ("font.menu_1.active", for example), do not
456 use an existing (in this case considered obsolete) active font
457 anymore, but use the automatically determined default font */
458 if (base_redefined && !active_redefined)
459 font_info[font_nr_active].graphic = base_graphic;
461 /* now also check each "special" font (which may be the same as above) */
462 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
464 int base_graphic = font_info[font_nr_base].special_graphic[j];
465 int active_graphic = font_info[font_nr_active].special_graphic[j];
466 boolean base_redefined =
467 getImageListEntryFromImageID(base_graphic)->redefined;
468 boolean active_redefined =
469 getImageListEntryFromImageID(active_graphic)->redefined;
471 /* same as above, but check special graphic definitions, for example:
472 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
473 if (base_redefined && !active_redefined)
475 font_info[font_nr_active].special_graphic[j] =
476 font_info[font_nr_base].special_graphic[j];
477 font_info[font_nr_active].special_bitmap_id[j] =
478 font_info[font_nr_base].special_bitmap_id[j];
484 /* ---------- initialize font bitmap array ---------- */
486 if (font_bitmap_info != NULL)
487 FreeFontInfo(font_bitmap_info);
490 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
492 /* ---------- initialize font bitmap definitions ---------- */
494 for (i = 0; i < NUM_FONTS; i++)
496 if (i < NUM_INITIAL_FONTS)
498 font_bitmap_info[i] = font_initial[i];
502 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
504 int font_bitmap_id = font_info[i].special_bitmap_id[j];
505 int graphic = font_info[i].special_graphic[j];
507 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
508 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
510 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
511 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
514 /* copy font relevant information from graphics information */
515 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
516 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
517 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
518 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
519 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
521 font_bitmap_info[font_bitmap_id].draw_xoffset =
522 graphic_info[graphic].draw_xoffset;
523 font_bitmap_info[font_bitmap_id].draw_yoffset =
524 graphic_info[graphic].draw_yoffset;
526 font_bitmap_info[font_bitmap_id].num_chars =
527 graphic_info[graphic].anim_frames;
528 font_bitmap_info[font_bitmap_id].num_chars_per_line =
529 graphic_info[graphic].anim_frames_per_line;
533 InitFontInfo(font_bitmap_info, num_font_bitmaps,
534 getFontBitmapID, getFontFromToken);
537 void InitGlobalAnimGraphicInfo()
539 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
540 int num_property_mappings = getImageListPropertyMappingSize();
543 if (graphic_info == NULL) /* still at startup phase */
546 /* always start with reliable default values (no global animations) */
547 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
548 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
549 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
550 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
552 /* initialize global animation definitions from static configuration */
553 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
555 int j = GLOBAL_ANIM_ID_PART_BASE;
556 int k = GFX_SPECIAL_ARG_DEFAULT;
558 global_anim_info[i].graphic[j][k] = IMG_GLOBAL_ANIM_1_GFX + i;
561 /* initialize global animation definitions from dynamic configuration */
562 for (i = 0; i < num_property_mappings; i++)
564 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
565 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
566 int special = property_mapping[i].ext3_index;
567 int graphic = property_mapping[i].artwork_index;
569 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
572 /* set animation part to base part, if not specified */
573 if (!IS_GLOBAL_ANIM_PART(part_nr))
574 part_nr = GLOBAL_ANIM_ID_PART_BASE;
576 /* set animation screen to default, if not specified */
577 if (!IS_SPECIAL_GFX_ARG(special))
578 special = GFX_SPECIAL_ARG_DEFAULT;
580 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
584 printf("::: InitGlobalAnimGraphicInfo\n");
586 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
587 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
588 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
589 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
590 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
591 printf("::: - anim %d, part %d, mode %d => %d\n",
592 i, j, k, global_anim_info[i].graphic[j][k]);
596 void InitGlobalAnimSoundInfo()
598 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
599 int num_property_mappings = getSoundListPropertyMappingSize();
602 /* always start with reliable default values (no global animation sounds) */
603 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
604 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
605 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
606 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
608 /* initialize global animation sound definitions from dynamic configuration */
609 for (i = 0; i < num_property_mappings; i++)
611 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
612 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
613 int special = property_mapping[i].ext3_index;
614 int sound = property_mapping[i].artwork_index;
616 // sound uses control definition; map it to position of graphic (artwork)
617 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
619 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
622 /* set animation part to base part, if not specified */
623 if (!IS_GLOBAL_ANIM_PART(part_nr))
624 part_nr = GLOBAL_ANIM_ID_PART_BASE;
626 /* set animation screen to default, if not specified */
627 if (!IS_SPECIAL_GFX_ARG(special))
628 special = GFX_SPECIAL_ARG_DEFAULT;
630 global_anim_info[anim_nr].sound[part_nr][special] = sound;
634 printf("::: InitGlobalAnimSoundInfo\n");
636 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
637 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
638 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
639 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
640 printf("::: - anim %d, part %d, mode %d => %d\n",
641 i, j, k, global_anim_info[i].sound[j][k]);
645 void InitElementGraphicInfo()
647 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
648 int num_property_mappings = getImageListPropertyMappingSize();
651 if (graphic_info == NULL) /* still at startup phase */
654 /* set values to -1 to identify later as "uninitialized" values */
655 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
657 for (act = 0; act < NUM_ACTIONS; act++)
659 element_info[i].graphic[act] = -1;
660 element_info[i].crumbled[act] = -1;
662 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
664 element_info[i].direction_graphic[act][dir] = -1;
665 element_info[i].direction_crumbled[act][dir] = -1;
672 /* initialize normal element/graphic mapping from static configuration */
673 for (i = 0; element_to_graphic[i].element > -1; i++)
675 int element = element_to_graphic[i].element;
676 int action = element_to_graphic[i].action;
677 int direction = element_to_graphic[i].direction;
678 boolean crumbled = element_to_graphic[i].crumbled;
679 int graphic = element_to_graphic[i].graphic;
680 int base_graphic = el2baseimg(element);
682 if (graphic_info[graphic].bitmap == NULL)
685 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
688 boolean base_redefined =
689 getImageListEntryFromImageID(base_graphic)->redefined;
690 boolean act_dir_redefined =
691 getImageListEntryFromImageID(graphic)->redefined;
693 /* if the base graphic ("emerald", for example) has been redefined,
694 but not the action graphic ("emerald.falling", for example), do not
695 use an existing (in this case considered obsolete) action graphic
696 anymore, but use the automatically determined default graphic */
697 if (base_redefined && !act_dir_redefined)
702 action = ACTION_DEFAULT;
707 element_info[element].direction_crumbled[action][direction] = graphic;
709 element_info[element].crumbled[action] = graphic;
714 element_info[element].direction_graphic[action][direction] = graphic;
716 element_info[element].graphic[action] = graphic;
720 /* initialize normal element/graphic mapping from dynamic configuration */
721 for (i = 0; i < num_property_mappings; i++)
723 int element = property_mapping[i].base_index;
724 int action = property_mapping[i].ext1_index;
725 int direction = property_mapping[i].ext2_index;
726 int special = property_mapping[i].ext3_index;
727 int graphic = property_mapping[i].artwork_index;
728 boolean crumbled = FALSE;
730 if (special == GFX_SPECIAL_ARG_CRUMBLED)
736 if (graphic_info[graphic].bitmap == NULL)
739 if (element >= MAX_NUM_ELEMENTS || special != -1)
743 action = ACTION_DEFAULT;
748 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
749 element_info[element].direction_crumbled[action][dir] = -1;
752 element_info[element].direction_crumbled[action][direction] = graphic;
754 element_info[element].crumbled[action] = graphic;
759 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
760 element_info[element].direction_graphic[action][dir] = -1;
763 element_info[element].direction_graphic[action][direction] = graphic;
765 element_info[element].graphic[action] = graphic;
769 /* now copy all graphics that are defined to be cloned from other graphics */
770 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
772 int graphic = element_info[i].graphic[ACTION_DEFAULT];
773 int crumbled_like, diggable_like;
778 crumbled_like = graphic_info[graphic].crumbled_like;
779 diggable_like = graphic_info[graphic].diggable_like;
781 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
783 for (act = 0; act < NUM_ACTIONS; act++)
784 element_info[i].crumbled[act] =
785 element_info[crumbled_like].crumbled[act];
786 for (act = 0; act < NUM_ACTIONS; act++)
787 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
788 element_info[i].direction_crumbled[act][dir] =
789 element_info[crumbled_like].direction_crumbled[act][dir];
792 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
794 element_info[i].graphic[ACTION_DIGGING] =
795 element_info[diggable_like].graphic[ACTION_DIGGING];
796 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
797 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
798 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
802 /* set hardcoded definitions for some runtime elements without graphic */
803 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
805 /* set hardcoded definitions for some internal elements without graphic */
806 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
808 if (IS_EDITOR_CASCADE_INACTIVE(i))
809 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
810 else if (IS_EDITOR_CASCADE_ACTIVE(i))
811 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
814 /* now set all undefined/invalid graphics to -1 to set to default after it */
815 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
817 for (act = 0; act < NUM_ACTIONS; act++)
821 graphic = element_info[i].graphic[act];
822 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
823 element_info[i].graphic[act] = -1;
825 graphic = element_info[i].crumbled[act];
826 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
827 element_info[i].crumbled[act] = -1;
829 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
831 graphic = element_info[i].direction_graphic[act][dir];
832 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
833 element_info[i].direction_graphic[act][dir] = -1;
835 graphic = element_info[i].direction_crumbled[act][dir];
836 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
837 element_info[i].direction_crumbled[act][dir] = -1;
844 /* adjust graphics with 2nd tile for movement according to direction
845 (do this before correcting '-1' values to minimize calculations) */
846 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
848 for (act = 0; act < NUM_ACTIONS; act++)
850 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
852 int graphic = element_info[i].direction_graphic[act][dir];
853 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
855 if (act == ACTION_FALLING) /* special case */
856 graphic = element_info[i].graphic[act];
859 graphic_info[graphic].double_movement &&
860 graphic_info[graphic].swap_double_tiles != 0)
862 struct GraphicInfo *g = &graphic_info[graphic];
863 int src_x_front = g->src_x;
864 int src_y_front = g->src_y;
865 int src_x_back = g->src_x + g->offset2_x;
866 int src_y_back = g->src_y + g->offset2_y;
867 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
869 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
870 src_y_front < src_y_back);
871 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
872 boolean swap_movement_tiles_autodetected =
873 (!frames_are_ordered_diagonally &&
874 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
875 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
876 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
877 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
880 /* swap frontside and backside graphic tile coordinates, if needed */
881 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
883 /* get current (wrong) backside tile coordinates */
884 getFixedGraphicSourceExt(graphic, 0, &dummy,
885 &src_x_back, &src_y_back, TRUE);
887 /* set frontside tile coordinates to backside tile coordinates */
888 g->src_x = src_x_back;
889 g->src_y = src_y_back;
891 /* invert tile offset to point to new backside tile coordinates */
895 /* do not swap front and backside tiles again after correction */
896 g->swap_double_tiles = 0;
905 /* now set all '-1' values to element specific default values */
906 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
908 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
909 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
910 int default_direction_graphic[NUM_DIRECTIONS_FULL];
911 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
913 if (default_graphic == -1)
914 default_graphic = IMG_UNKNOWN;
916 if (default_crumbled == -1)
917 default_crumbled = default_graphic;
919 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
921 default_direction_graphic[dir] =
922 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
923 default_direction_crumbled[dir] =
924 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
926 if (default_direction_graphic[dir] == -1)
927 default_direction_graphic[dir] = default_graphic;
929 if (default_direction_crumbled[dir] == -1)
930 default_direction_crumbled[dir] = default_direction_graphic[dir];
933 for (act = 0; act < NUM_ACTIONS; act++)
935 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
936 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
937 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
938 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
939 act == ACTION_TURNING_FROM_RIGHT ||
940 act == ACTION_TURNING_FROM_UP ||
941 act == ACTION_TURNING_FROM_DOWN);
943 /* generic default action graphic (defined by "[default]" directive) */
944 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
945 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
946 int default_remove_graphic = IMG_EMPTY;
948 if (act_remove && default_action_graphic != -1)
949 default_remove_graphic = default_action_graphic;
951 /* look for special default action graphic (classic game specific) */
952 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
953 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
954 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
955 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
956 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
957 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
959 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
960 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
961 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
962 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
963 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
964 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
966 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
967 /* !!! make this better !!! */
968 if (i == EL_EMPTY_SPACE)
970 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
971 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
974 if (default_action_graphic == -1)
975 default_action_graphic = default_graphic;
977 if (default_action_crumbled == -1)
978 default_action_crumbled = default_action_graphic;
980 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
982 /* use action graphic as the default direction graphic, if undefined */
983 int default_action_direction_graphic = element_info[i].graphic[act];
984 int default_action_direction_crumbled = element_info[i].crumbled[act];
986 /* no graphic for current action -- use default direction graphic */
987 if (default_action_direction_graphic == -1)
988 default_action_direction_graphic =
989 (act_remove ? default_remove_graphic :
991 element_info[i].direction_graphic[ACTION_TURNING][dir] :
992 default_action_graphic != default_graphic ?
993 default_action_graphic :
994 default_direction_graphic[dir]);
996 if (element_info[i].direction_graphic[act][dir] == -1)
997 element_info[i].direction_graphic[act][dir] =
998 default_action_direction_graphic;
1000 if (default_action_direction_crumbled == -1)
1001 default_action_direction_crumbled =
1002 element_info[i].direction_graphic[act][dir];
1004 if (element_info[i].direction_crumbled[act][dir] == -1)
1005 element_info[i].direction_crumbled[act][dir] =
1006 default_action_direction_crumbled;
1009 /* no graphic for this specific action -- use default action graphic */
1010 if (element_info[i].graphic[act] == -1)
1011 element_info[i].graphic[act] =
1012 (act_remove ? default_remove_graphic :
1013 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1014 default_action_graphic);
1016 if (element_info[i].crumbled[act] == -1)
1017 element_info[i].crumbled[act] = element_info[i].graphic[act];
1021 UPDATE_BUSY_STATE();
1024 void InitElementSpecialGraphicInfo()
1026 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1027 int num_property_mappings = getImageListPropertyMappingSize();
1030 /* always start with reliable default values */
1031 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1032 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1033 element_info[i].special_graphic[j] =
1034 element_info[i].graphic[ACTION_DEFAULT];
1036 /* initialize special element/graphic mapping from static configuration */
1037 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1039 int element = element_to_special_graphic[i].element;
1040 int special = element_to_special_graphic[i].special;
1041 int graphic = element_to_special_graphic[i].graphic;
1042 int base_graphic = el2baseimg(element);
1043 boolean base_redefined =
1044 getImageListEntryFromImageID(base_graphic)->redefined;
1045 boolean special_redefined =
1046 getImageListEntryFromImageID(graphic)->redefined;
1048 /* if the base graphic ("emerald", for example) has been redefined,
1049 but not the special graphic ("emerald.EDITOR", for example), do not
1050 use an existing (in this case considered obsolete) special graphic
1051 anymore, but use the automatically created (down-scaled) graphic */
1052 if (base_redefined && !special_redefined)
1055 element_info[element].special_graphic[special] = graphic;
1058 /* initialize special element/graphic mapping from dynamic configuration */
1059 for (i = 0; i < num_property_mappings; i++)
1061 int element = property_mapping[i].base_index;
1062 int action = property_mapping[i].ext1_index;
1063 int direction = property_mapping[i].ext2_index;
1064 int special = property_mapping[i].ext3_index;
1065 int graphic = property_mapping[i].artwork_index;
1067 /* for action ".active", replace element with active element, if exists */
1068 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1070 element = ELEMENT_ACTIVE(element);
1074 if (element >= MAX_NUM_ELEMENTS)
1077 /* do not change special graphic if action or direction was specified */
1078 if (action != -1 || direction != -1)
1081 if (IS_SPECIAL_GFX_ARG(special))
1082 element_info[element].special_graphic[special] = graphic;
1085 /* now set all undefined/invalid graphics to default */
1086 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1087 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1088 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1089 element_info[i].special_graphic[j] =
1090 element_info[i].graphic[ACTION_DEFAULT];
1093 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1095 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1096 return get_parameter_value(value_raw, suffix, type);
1098 if (strEqual(value_raw, ARG_UNDEFINED))
1099 return ARG_UNDEFINED_VALUE;
1101 if (type == TYPE_ELEMENT)
1103 char *value = getHashEntry(element_token_hash, value_raw);
1107 Error(ERR_INFO_LINE, "-");
1108 Error(ERR_INFO, "warning: error found in config file:");
1109 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1110 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1111 Error(ERR_INFO, "custom graphic rejected for this element/action");
1112 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1113 Error(ERR_INFO_LINE, "-");
1116 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1118 else if (type == TYPE_GRAPHIC)
1120 char *value = getHashEntry(graphic_token_hash, value_raw);
1121 int fallback_graphic = IMG_CHAR_EXCLAM;
1125 Error(ERR_INFO_LINE, "-");
1126 Error(ERR_INFO, "warning: error found in config file:");
1127 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1128 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1129 Error(ERR_INFO, "custom graphic rejected for this element/action");
1130 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1131 Error(ERR_INFO_LINE, "-");
1134 return (value != NULL ? atoi(value) : fallback_graphic);
1140 static int get_scaled_graphic_width(int graphic)
1142 int original_width = getOriginalImageWidthFromImageID(graphic);
1143 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1145 return original_width * scale_up_factor;
1148 static int get_scaled_graphic_height(int graphic)
1150 int original_height = getOriginalImageHeightFromImageID(graphic);
1151 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1153 return original_height * scale_up_factor;
1156 static void set_graphic_parameters_ext(int graphic, int *parameter,
1157 Bitmap **src_bitmaps)
1159 struct GraphicInfo *g = &graphic_info[graphic];
1160 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1161 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1162 int anim_frames_per_line = 1;
1164 /* always start with reliable default values */
1165 g->src_image_width = 0;
1166 g->src_image_height = 0;
1169 g->width = TILEX; /* default for element graphics */
1170 g->height = TILEY; /* default for element graphics */
1171 g->offset_x = 0; /* one or both of these values ... */
1172 g->offset_y = 0; /* ... will be corrected later */
1173 g->offset2_x = 0; /* one or both of these values ... */
1174 g->offset2_y = 0; /* ... will be corrected later */
1175 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1176 g->crumbled_like = -1; /* do not use clone element */
1177 g->diggable_like = -1; /* do not use clone element */
1178 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1179 g->scale_up_factor = 1; /* default: no scaling up */
1180 g->tile_size = TILESIZE; /* default: standard tile size */
1181 g->clone_from = -1; /* do not use clone graphic */
1182 g->init_delay_fixed = 0;
1183 g->init_delay_random = 0;
1184 g->anim_delay_fixed = 0;
1185 g->anim_delay_random = 0;
1186 g->post_delay_fixed = 0;
1187 g->post_delay_random = 0;
1189 g->fade_mode = FADE_MODE_DEFAULT;
1193 g->align = ALIGN_CENTER; /* default for title screens */
1194 g->valign = VALIGN_MIDDLE; /* default for title screens */
1195 g->sort_priority = 0; /* default for title screens */
1197 g->style = STYLE_DEFAULT;
1199 g->bitmaps = src_bitmaps;
1200 g->bitmap = src_bitmap;
1202 /* optional zoom factor for scaling up the image to a larger size */
1203 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1204 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1205 if (g->scale_up_factor < 1)
1206 g->scale_up_factor = 1; /* no scaling */
1208 /* optional tile size for using non-standard image size */
1209 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1211 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1214 // CHECK: should tile sizes less than standard tile size be allowed?
1215 if (g->tile_size < TILESIZE)
1216 g->tile_size = TILESIZE; /* standard tile size */
1219 // when setting tile size, also set width and height accordingly
1220 g->width = g->tile_size;
1221 g->height = g->tile_size;
1224 if (g->use_image_size)
1226 /* set new default bitmap size (with scaling, but without small images) */
1227 g->width = get_scaled_graphic_width(graphic);
1228 g->height = get_scaled_graphic_height(graphic);
1231 /* optional width and height of each animation frame */
1232 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1233 g->width = parameter[GFX_ARG_WIDTH];
1234 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1235 g->height = parameter[GFX_ARG_HEIGHT];
1237 /* optional x and y tile position of animation frame sequence */
1238 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1239 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1240 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1241 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1243 /* optional x and y pixel position of animation frame sequence */
1244 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1245 g->src_x = parameter[GFX_ARG_X];
1246 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1247 g->src_y = parameter[GFX_ARG_Y];
1253 Error(ERR_INFO_LINE, "-");
1254 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1255 g->width, getTokenFromImageID(graphic), TILEX);
1256 Error(ERR_INFO_LINE, "-");
1258 g->width = TILEX; /* will be checked to be inside bitmap later */
1263 Error(ERR_INFO_LINE, "-");
1264 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1265 g->height, getTokenFromImageID(graphic), TILEY);
1266 Error(ERR_INFO_LINE, "-");
1268 g->height = TILEY; /* will be checked to be inside bitmap later */
1274 /* get final bitmap size (with scaling, but without small images) */
1275 int src_image_width = get_scaled_graphic_width(graphic);
1276 int src_image_height = get_scaled_graphic_height(graphic);
1278 if (src_image_width == 0 || src_image_height == 0)
1280 /* only happens when loaded outside artwork system (like "global.busy") */
1281 src_image_width = src_bitmap->width;
1282 src_image_height = src_bitmap->height;
1285 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1287 anim_frames_per_row = src_image_width / g->tile_size;
1288 anim_frames_per_col = src_image_height / g->tile_size;
1292 anim_frames_per_row = src_image_width / g->width;
1293 anim_frames_per_col = src_image_height / g->height;
1296 g->src_image_width = src_image_width;
1297 g->src_image_height = src_image_height;
1300 /* correct x or y offset dependent of vertical or horizontal frame order */
1301 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1303 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1304 parameter[GFX_ARG_OFFSET] : g->height);
1305 anim_frames_per_line = anim_frames_per_col;
1307 else /* frames are ordered horizontally */
1309 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1310 parameter[GFX_ARG_OFFSET] : g->width);
1311 anim_frames_per_line = anim_frames_per_row;
1314 /* optionally, the x and y offset of frames can be specified directly */
1315 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1316 g->offset_x = parameter[GFX_ARG_XOFFSET];
1317 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1318 g->offset_y = parameter[GFX_ARG_YOFFSET];
1320 /* optionally, moving animations may have separate start and end graphics */
1321 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1323 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1324 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1326 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1327 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1328 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1329 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1330 else /* frames are ordered horizontally */
1331 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1332 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1334 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1335 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1336 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1337 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1338 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1340 /* optionally, the second movement tile can be specified as start tile */
1341 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1342 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1344 /* automatically determine correct number of frames, if not defined */
1345 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1346 g->anim_frames = parameter[GFX_ARG_FRAMES];
1347 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1348 g->anim_frames = anim_frames_per_row;
1349 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1350 g->anim_frames = anim_frames_per_col;
1354 if (g->anim_frames == 0) /* frames must be at least 1 */
1357 g->anim_frames_per_line =
1358 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1359 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1361 g->anim_delay = parameter[GFX_ARG_DELAY];
1362 if (g->anim_delay == 0) /* delay must be at least 1 */
1365 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1367 /* automatically determine correct start frame, if not defined */
1368 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1369 g->anim_start_frame = 0;
1370 else if (g->anim_mode & ANIM_REVERSE)
1371 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1373 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1375 /* animation synchronized with global frame counter, not move position */
1376 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1378 /* optional element for cloning crumble graphics */
1379 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1380 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1382 /* optional element for cloning digging graphics */
1383 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1384 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1386 /* optional border size for "crumbling" diggable graphics */
1387 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1388 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1390 /* used for global animations and player "boring" and "sleeping" actions */
1391 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1392 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1393 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1394 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1395 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1396 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1397 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1398 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1399 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1400 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1401 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1402 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1404 /* used for toon animations and global animations */
1405 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1406 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1407 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1408 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1409 g->direction = parameter[GFX_ARG_DIRECTION];
1410 g->position = parameter[GFX_ARG_POSITION];
1411 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1412 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1414 /* this is only used for drawing font characters */
1415 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1416 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1418 /* this is only used for drawing envelope graphics */
1419 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1421 /* used for toon animations and global animations */
1422 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1423 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1425 /* optional graphic for cloning all graphics settings */
1426 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1427 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1429 /* optional settings for drawing title screens and title messages */
1430 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1431 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1432 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1433 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1434 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1435 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1436 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1437 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1438 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1439 g->align = parameter[GFX_ARG_ALIGN];
1440 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1441 g->valign = parameter[GFX_ARG_VALIGN];
1442 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1443 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1445 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1446 g->class = parameter[GFX_ARG_CLASS];
1447 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1448 g->style = parameter[GFX_ARG_STYLE];
1450 /* this is only used for drawing menu buttons and text */
1451 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1452 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1453 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1454 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1457 static void set_graphic_parameters(int graphic)
1459 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1460 char **parameter_raw = image->parameter;
1461 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1462 int parameter[NUM_GFX_ARGS];
1465 /* if fallback to default artwork is done, also use the default parameters */
1466 if (image->fallback_to_default)
1467 parameter_raw = image->default_parameter;
1469 /* get integer values from string parameters */
1470 for (i = 0; i < NUM_GFX_ARGS; i++)
1471 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1472 image_config_suffix[i].token,
1473 image_config_suffix[i].type);
1475 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1477 UPDATE_BUSY_STATE();
1480 static void set_cloned_graphic_parameters(int graphic)
1482 int fallback_graphic = IMG_CHAR_EXCLAM;
1483 int max_num_images = getImageListSize();
1484 int clone_graphic = graphic_info[graphic].clone_from;
1485 int num_references_followed = 1;
1487 while (graphic_info[clone_graphic].clone_from != -1 &&
1488 num_references_followed < max_num_images)
1490 clone_graphic = graphic_info[clone_graphic].clone_from;
1492 num_references_followed++;
1495 if (num_references_followed >= max_num_images)
1497 Error(ERR_INFO_LINE, "-");
1498 Error(ERR_INFO, "warning: error found in config file:");
1499 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1500 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1501 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1502 Error(ERR_INFO, "custom graphic rejected for this element/action");
1504 if (graphic == fallback_graphic)
1505 Error(ERR_EXIT, "no fallback graphic available");
1507 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1508 Error(ERR_INFO_LINE, "-");
1510 graphic_info[graphic] = graphic_info[fallback_graphic];
1514 graphic_info[graphic] = graphic_info[clone_graphic];
1515 graphic_info[graphic].clone_from = clone_graphic;
1519 static void InitGraphicInfo()
1521 int fallback_graphic = IMG_CHAR_EXCLAM;
1522 int num_images = getImageListSize();
1525 /* use image size as default values for width and height for these images */
1526 static int full_size_graphics[] =
1529 IMG_GLOBAL_BORDER_MAIN,
1530 IMG_GLOBAL_BORDER_SCORES,
1531 IMG_GLOBAL_BORDER_EDITOR,
1532 IMG_GLOBAL_BORDER_PLAYING,
1535 IMG_BACKGROUND_ENVELOPE_1,
1536 IMG_BACKGROUND_ENVELOPE_2,
1537 IMG_BACKGROUND_ENVELOPE_3,
1538 IMG_BACKGROUND_ENVELOPE_4,
1539 IMG_BACKGROUND_REQUEST,
1542 IMG_BACKGROUND_TITLE_INITIAL,
1543 IMG_BACKGROUND_TITLE,
1544 IMG_BACKGROUND_MAIN,
1545 IMG_BACKGROUND_LEVELS,
1546 IMG_BACKGROUND_LEVELNR,
1547 IMG_BACKGROUND_SCORES,
1548 IMG_BACKGROUND_EDITOR,
1549 IMG_BACKGROUND_INFO,
1550 IMG_BACKGROUND_INFO_ELEMENTS,
1551 IMG_BACKGROUND_INFO_MUSIC,
1552 IMG_BACKGROUND_INFO_CREDITS,
1553 IMG_BACKGROUND_INFO_PROGRAM,
1554 IMG_BACKGROUND_INFO_VERSION,
1555 IMG_BACKGROUND_INFO_LEVELSET,
1556 IMG_BACKGROUND_SETUP,
1557 IMG_BACKGROUND_PLAYING,
1558 IMG_BACKGROUND_DOOR,
1559 IMG_BACKGROUND_TAPE,
1560 IMG_BACKGROUND_PANEL,
1561 IMG_BACKGROUND_PALETTE,
1562 IMG_BACKGROUND_TOOLBOX,
1564 IMG_TITLESCREEN_INITIAL_1,
1565 IMG_TITLESCREEN_INITIAL_2,
1566 IMG_TITLESCREEN_INITIAL_3,
1567 IMG_TITLESCREEN_INITIAL_4,
1568 IMG_TITLESCREEN_INITIAL_5,
1575 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1576 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1577 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1578 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1579 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1580 IMG_BACKGROUND_TITLEMESSAGE_1,
1581 IMG_BACKGROUND_TITLEMESSAGE_2,
1582 IMG_BACKGROUND_TITLEMESSAGE_3,
1583 IMG_BACKGROUND_TITLEMESSAGE_4,
1584 IMG_BACKGROUND_TITLEMESSAGE_5,
1589 checked_free(graphic_info);
1591 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1593 /* initialize "use_image_size" flag with default value */
1594 for (i = 0; i < num_images; i++)
1595 graphic_info[i].use_image_size = FALSE;
1597 /* initialize "use_image_size" flag from static configuration above */
1598 for (i = 0; full_size_graphics[i] != -1; i++)
1599 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1601 /* first set all graphic paramaters ... */
1602 for (i = 0; i < num_images; i++)
1603 set_graphic_parameters(i);
1605 /* ... then copy these parameters for cloned graphics */
1606 for (i = 0; i < num_images; i++)
1607 if (graphic_info[i].clone_from != -1)
1608 set_cloned_graphic_parameters(i);
1610 for (i = 0; i < num_images; i++)
1615 int first_frame, last_frame;
1616 int src_bitmap_width, src_bitmap_height;
1618 /* now check if no animation frames are outside of the loaded image */
1620 if (graphic_info[i].bitmap == NULL)
1621 continue; /* skip check for optional images that are undefined */
1623 /* get image size (this can differ from the standard element tile size!) */
1624 width = graphic_info[i].width;
1625 height = graphic_info[i].height;
1627 /* get final bitmap size (with scaling, but without small images) */
1628 src_bitmap_width = graphic_info[i].src_image_width;
1629 src_bitmap_height = graphic_info[i].src_image_height;
1631 /* check if first animation frame is inside specified bitmap */
1634 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1636 /* this avoids calculating wrong start position for out-of-bounds frame */
1637 src_x = graphic_info[i].src_x;
1638 src_y = graphic_info[i].src_y;
1640 if (src_x < 0 || src_y < 0 ||
1641 src_x + width > src_bitmap_width ||
1642 src_y + height > src_bitmap_height)
1644 Error(ERR_INFO_LINE, "-");
1645 Error(ERR_INFO, "warning: error found in config file:");
1646 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1647 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1648 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1650 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1651 src_x, src_y, src_bitmap_width, src_bitmap_height);
1652 Error(ERR_INFO, "custom graphic rejected for this element/action");
1654 if (i == fallback_graphic)
1655 Error(ERR_EXIT, "no fallback graphic available");
1657 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1658 Error(ERR_INFO_LINE, "-");
1660 graphic_info[i] = graphic_info[fallback_graphic];
1663 /* check if last animation frame is inside specified bitmap */
1665 last_frame = graphic_info[i].anim_frames - 1;
1666 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1668 if (src_x < 0 || src_y < 0 ||
1669 src_x + width > src_bitmap_width ||
1670 src_y + height > src_bitmap_height)
1672 Error(ERR_INFO_LINE, "-");
1673 Error(ERR_INFO, "warning: error found in config file:");
1674 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1675 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1676 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1678 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1679 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1680 Error(ERR_INFO, "::: %d, %d", width, height);
1681 Error(ERR_INFO, "custom graphic rejected for this element/action");
1683 if (i == fallback_graphic)
1684 Error(ERR_EXIT, "no fallback graphic available");
1686 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1687 Error(ERR_INFO_LINE, "-");
1689 graphic_info[i] = graphic_info[fallback_graphic];
1694 static void InitGraphicCompatibilityInfo()
1696 struct FileInfo *fi_global_door =
1697 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1698 int num_images = getImageListSize();
1701 /* the following compatibility handling is needed for the following case:
1702 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1703 graphics mainly used for door and panel graphics, like editor, tape and
1704 in-game buttons with hard-coded bitmap positions and button sizes; as
1705 these graphics now have individual definitions, redefining "global.door"
1706 to change all these graphics at once like before does not work anymore
1707 (because all those individual definitions still have their default values);
1708 to solve this, remap all those individual definitions that are not
1709 redefined to the new bitmap of "global.door" if it was redefined */
1711 /* special compatibility handling if image "global.door" was redefined */
1712 if (fi_global_door->redefined)
1714 for (i = 0; i < num_images; i++)
1716 struct FileInfo *fi = getImageListEntryFromImageID(i);
1718 /* process only those images that still use the default settings */
1721 /* process all images which default to same image as "global.door" */
1722 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1724 // printf("::: special treatment needed for token '%s'\n", fi->token);
1726 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1732 InitGraphicCompatibilityInfo_Doors();
1735 static void InitElementSoundInfo()
1737 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1738 int num_property_mappings = getSoundListPropertyMappingSize();
1741 /* set values to -1 to identify later as "uninitialized" values */
1742 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1743 for (act = 0; act < NUM_ACTIONS; act++)
1744 element_info[i].sound[act] = -1;
1746 /* initialize element/sound mapping from static configuration */
1747 for (i = 0; element_to_sound[i].element > -1; i++)
1749 int element = element_to_sound[i].element;
1750 int action = element_to_sound[i].action;
1751 int sound = element_to_sound[i].sound;
1752 boolean is_class = element_to_sound[i].is_class;
1755 action = ACTION_DEFAULT;
1758 element_info[element].sound[action] = sound;
1760 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1761 if (strEqual(element_info[j].class_name,
1762 element_info[element].class_name))
1763 element_info[j].sound[action] = sound;
1766 /* initialize element class/sound mapping from dynamic configuration */
1767 for (i = 0; i < num_property_mappings; i++)
1769 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1770 int action = property_mapping[i].ext1_index;
1771 int sound = property_mapping[i].artwork_index;
1773 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1777 action = ACTION_DEFAULT;
1779 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1780 if (strEqual(element_info[j].class_name,
1781 element_info[element_class].class_name))
1782 element_info[j].sound[action] = sound;
1785 /* initialize element/sound mapping from dynamic configuration */
1786 for (i = 0; i < num_property_mappings; i++)
1788 int element = property_mapping[i].base_index;
1789 int action = property_mapping[i].ext1_index;
1790 int sound = property_mapping[i].artwork_index;
1792 if (element >= MAX_NUM_ELEMENTS)
1796 action = ACTION_DEFAULT;
1798 element_info[element].sound[action] = sound;
1801 /* now set all '-1' values to element specific default values */
1802 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1804 for (act = 0; act < NUM_ACTIONS; act++)
1806 /* generic default action sound (defined by "[default]" directive) */
1807 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1809 /* look for special default action sound (classic game specific) */
1810 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1811 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1812 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1813 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1814 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1815 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1817 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1818 /* !!! make this better !!! */
1819 if (i == EL_EMPTY_SPACE)
1820 default_action_sound = element_info[EL_DEFAULT].sound[act];
1822 /* no sound for this specific action -- use default action sound */
1823 if (element_info[i].sound[act] == -1)
1824 element_info[i].sound[act] = default_action_sound;
1828 /* copy sound settings to some elements that are only stored in level file
1829 in native R'n'D levels, but are used by game engine in native EM levels */
1830 for (i = 0; copy_properties[i][0] != -1; i++)
1831 for (j = 1; j <= 4; j++)
1832 for (act = 0; act < NUM_ACTIONS; act++)
1833 element_info[copy_properties[i][j]].sound[act] =
1834 element_info[copy_properties[i][0]].sound[act];
1837 static void InitGameModeSoundInfo()
1841 /* set values to -1 to identify later as "uninitialized" values */
1842 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1845 /* initialize gamemode/sound mapping from static configuration */
1846 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1848 int gamemode = gamemode_to_sound[i].gamemode;
1849 int sound = gamemode_to_sound[i].sound;
1852 gamemode = GAME_MODE_DEFAULT;
1854 menu.sound[gamemode] = sound;
1857 /* now set all '-1' values to levelset specific default values */
1858 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1859 if (menu.sound[i] == -1)
1860 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1863 static void set_sound_parameters(int sound, char **parameter_raw)
1865 int parameter[NUM_SND_ARGS];
1868 /* get integer values from string parameters */
1869 for (i = 0; i < NUM_SND_ARGS; i++)
1871 get_parameter_value(parameter_raw[i],
1872 sound_config_suffix[i].token,
1873 sound_config_suffix[i].type);
1875 /* explicit loop mode setting in configuration overrides default value */
1876 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1877 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1879 /* sound volume to change the original volume when loading the sound file */
1880 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1882 /* sound priority to give certain sounds a higher or lower priority */
1883 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1886 static void InitSoundInfo()
1888 int *sound_effect_properties;
1889 int num_sounds = getSoundListSize();
1892 checked_free(sound_info);
1894 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1895 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1897 /* initialize sound effect for all elements to "no sound" */
1898 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1899 for (j = 0; j < NUM_ACTIONS; j++)
1900 element_info[i].sound[j] = SND_UNDEFINED;
1902 for (i = 0; i < num_sounds; i++)
1904 struct FileInfo *sound = getSoundListEntry(i);
1905 int len_effect_text = strlen(sound->token);
1907 sound_effect_properties[i] = ACTION_OTHER;
1908 sound_info[i].loop = FALSE; /* default: play sound only once */
1910 /* determine all loop sounds and identify certain sound classes */
1912 for (j = 0; element_action_info[j].suffix; j++)
1914 int len_action_text = strlen(element_action_info[j].suffix);
1916 if (len_action_text < len_effect_text &&
1917 strEqual(&sound->token[len_effect_text - len_action_text],
1918 element_action_info[j].suffix))
1920 sound_effect_properties[i] = element_action_info[j].value;
1921 sound_info[i].loop = element_action_info[j].is_loop_sound;
1927 /* associate elements and some selected sound actions */
1929 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1931 if (element_info[j].class_name)
1933 int len_class_text = strlen(element_info[j].class_name);
1935 if (len_class_text + 1 < len_effect_text &&
1936 strncmp(sound->token,
1937 element_info[j].class_name, len_class_text) == 0 &&
1938 sound->token[len_class_text] == '.')
1940 int sound_action_value = sound_effect_properties[i];
1942 element_info[j].sound[sound_action_value] = i;
1947 set_sound_parameters(i, sound->parameter);
1950 free(sound_effect_properties);
1953 static void InitGameModeMusicInfo()
1955 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1956 int num_property_mappings = getMusicListPropertyMappingSize();
1957 int default_levelset_music = -1;
1960 /* set values to -1 to identify later as "uninitialized" values */
1961 for (i = 0; i < MAX_LEVELS; i++)
1962 levelset.music[i] = -1;
1963 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1966 /* initialize gamemode/music mapping from static configuration */
1967 for (i = 0; gamemode_to_music[i].music > -1; i++)
1969 int gamemode = gamemode_to_music[i].gamemode;
1970 int music = gamemode_to_music[i].music;
1973 gamemode = GAME_MODE_DEFAULT;
1975 menu.music[gamemode] = music;
1978 /* initialize gamemode/music mapping from dynamic configuration */
1979 for (i = 0; i < num_property_mappings; i++)
1981 int prefix = property_mapping[i].base_index;
1982 int gamemode = property_mapping[i].ext1_index;
1983 int level = property_mapping[i].ext2_index;
1984 int music = property_mapping[i].artwork_index;
1986 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1990 gamemode = GAME_MODE_DEFAULT;
1992 /* level specific music only allowed for in-game music */
1993 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1994 gamemode = GAME_MODE_PLAYING;
1999 default_levelset_music = music;
2002 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2003 levelset.music[level] = music;
2004 if (gamemode != GAME_MODE_PLAYING)
2005 menu.music[gamemode] = music;
2008 /* now set all '-1' values to menu specific default values */
2009 /* (undefined values of "levelset.music[]" might stay at "-1" to
2010 allow dynamic selection of music files from music directory!) */
2011 for (i = 0; i < MAX_LEVELS; i++)
2012 if (levelset.music[i] == -1)
2013 levelset.music[i] = default_levelset_music;
2014 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2015 if (menu.music[i] == -1)
2016 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2019 static void set_music_parameters(int music, char **parameter_raw)
2021 int parameter[NUM_MUS_ARGS];
2024 /* get integer values from string parameters */
2025 for (i = 0; i < NUM_MUS_ARGS; i++)
2027 get_parameter_value(parameter_raw[i],
2028 music_config_suffix[i].token,
2029 music_config_suffix[i].type);
2031 /* explicit loop mode setting in configuration overrides default value */
2032 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2033 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2036 static void InitMusicInfo()
2038 int num_music = getMusicListSize();
2041 checked_free(music_info);
2043 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2045 for (i = 0; i < num_music; i++)
2047 struct FileInfo *music = getMusicListEntry(i);
2048 int len_music_text = strlen(music->token);
2050 music_info[i].loop = TRUE; /* default: play music in loop mode */
2052 /* determine all loop music */
2054 for (j = 0; music_prefix_info[j].prefix; j++)
2056 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2058 if (len_prefix_text < len_music_text &&
2059 strncmp(music->token,
2060 music_prefix_info[j].prefix, len_prefix_text) == 0)
2062 music_info[i].loop = music_prefix_info[j].is_loop_music;
2068 set_music_parameters(i, music->parameter);
2072 static void ReinitializeGraphics()
2074 print_timestamp_init("ReinitializeGraphics");
2076 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2078 InitGraphicInfo(); /* graphic properties mapping */
2079 print_timestamp_time("InitGraphicInfo");
2080 InitElementGraphicInfo(); /* element game graphic mapping */
2081 print_timestamp_time("InitElementGraphicInfo");
2082 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2083 print_timestamp_time("InitElementSpecialGraphicInfo");
2085 InitElementSmallImages(); /* scale elements to all needed sizes */
2086 print_timestamp_time("InitElementSmallImages");
2087 InitScaledImages(); /* scale all other images, if needed */
2088 print_timestamp_time("InitScaledImages");
2089 InitBitmapPointers(); /* set standard size bitmap pointers */
2090 print_timestamp_time("InitBitmapPointers");
2091 InitFontGraphicInfo(); /* initialize text drawing functions */
2092 print_timestamp_time("InitFontGraphicInfo");
2093 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2094 print_timestamp_time("InitGlobalAnimGraphicInfo");
2096 InitImageTextures(); /* create textures for certain images */
2097 print_timestamp_time("InitImageTextures");
2099 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2100 print_timestamp_time("InitGraphicInfo_EM");
2102 InitGraphicCompatibilityInfo();
2103 print_timestamp_time("InitGraphicCompatibilityInfo");
2105 SetMainBackgroundImage(IMG_BACKGROUND);
2106 print_timestamp_time("SetMainBackgroundImage");
2107 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2108 print_timestamp_time("SetDoorBackgroundImage");
2111 print_timestamp_time("InitGadgets");
2113 print_timestamp_time("InitToons");
2115 print_timestamp_time("InitDoors");
2117 print_timestamp_done("ReinitializeGraphics");
2120 static void ReinitializeSounds()
2122 InitSoundInfo(); /* sound properties mapping */
2123 InitElementSoundInfo(); /* element game sound mapping */
2124 InitGameModeSoundInfo(); /* game mode sound mapping */
2125 InitGlobalAnimSoundInfo(); /* global animation sound settings */
2127 InitPlayLevelSound(); /* internal game sound settings */
2130 static void ReinitializeMusic()
2132 InitMusicInfo(); /* music properties mapping */
2133 InitGameModeMusicInfo(); /* game mode music mapping */
2136 static int get_special_property_bit(int element, int property_bit_nr)
2138 struct PropertyBitInfo
2144 static struct PropertyBitInfo pb_can_move_into_acid[] =
2146 /* the player may be able fall into acid when gravity is activated */
2151 { EL_SP_MURPHY, 0 },
2152 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2154 /* all elements that can move may be able to also move into acid */
2157 { EL_BUG_RIGHT, 1 },
2160 { EL_SPACESHIP, 2 },
2161 { EL_SPACESHIP_LEFT, 2 },
2162 { EL_SPACESHIP_RIGHT, 2 },
2163 { EL_SPACESHIP_UP, 2 },
2164 { EL_SPACESHIP_DOWN, 2 },
2165 { EL_BD_BUTTERFLY, 3 },
2166 { EL_BD_BUTTERFLY_LEFT, 3 },
2167 { EL_BD_BUTTERFLY_RIGHT, 3 },
2168 { EL_BD_BUTTERFLY_UP, 3 },
2169 { EL_BD_BUTTERFLY_DOWN, 3 },
2170 { EL_BD_FIREFLY, 4 },
2171 { EL_BD_FIREFLY_LEFT, 4 },
2172 { EL_BD_FIREFLY_RIGHT, 4 },
2173 { EL_BD_FIREFLY_UP, 4 },
2174 { EL_BD_FIREFLY_DOWN, 4 },
2176 { EL_YAMYAM_LEFT, 5 },
2177 { EL_YAMYAM_RIGHT, 5 },
2178 { EL_YAMYAM_UP, 5 },
2179 { EL_YAMYAM_DOWN, 5 },
2180 { EL_DARK_YAMYAM, 6 },
2183 { EL_PACMAN_LEFT, 8 },
2184 { EL_PACMAN_RIGHT, 8 },
2185 { EL_PACMAN_UP, 8 },
2186 { EL_PACMAN_DOWN, 8 },
2188 { EL_MOLE_LEFT, 9 },
2189 { EL_MOLE_RIGHT, 9 },
2191 { EL_MOLE_DOWN, 9 },
2195 { EL_SATELLITE, 13 },
2196 { EL_SP_SNIKSNAK, 14 },
2197 { EL_SP_ELECTRON, 15 },
2200 { EL_EMC_ANDROID, 18 },
2205 static struct PropertyBitInfo pb_dont_collide_with[] =
2207 { EL_SP_SNIKSNAK, 0 },
2208 { EL_SP_ELECTRON, 1 },
2216 struct PropertyBitInfo *pb_info;
2219 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2220 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2225 struct PropertyBitInfo *pb_info = NULL;
2228 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2229 if (pb_definition[i].bit_nr == property_bit_nr)
2230 pb_info = pb_definition[i].pb_info;
2232 if (pb_info == NULL)
2235 for (i = 0; pb_info[i].element != -1; i++)
2236 if (pb_info[i].element == element)
2237 return pb_info[i].bit_nr;
2242 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2243 boolean property_value)
2245 int bit_nr = get_special_property_bit(element, property_bit_nr);
2250 *bitfield |= (1 << bit_nr);
2252 *bitfield &= ~(1 << bit_nr);
2256 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2258 int bit_nr = get_special_property_bit(element, property_bit_nr);
2261 return ((*bitfield & (1 << bit_nr)) != 0);
2266 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2268 static int group_nr;
2269 static struct ElementGroupInfo *group;
2270 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2273 if (actual_group == NULL) /* not yet initialized */
2276 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2278 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2279 group_element - EL_GROUP_START + 1);
2281 /* replace element which caused too deep recursion by question mark */
2282 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2287 if (recursion_depth == 0) /* initialization */
2289 group = actual_group;
2290 group_nr = GROUP_NR(group_element);
2292 group->num_elements_resolved = 0;
2293 group->choice_pos = 0;
2295 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2296 element_info[i].in_group[group_nr] = FALSE;
2299 for (i = 0; i < actual_group->num_elements; i++)
2301 int element = actual_group->element[i];
2303 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2306 if (IS_GROUP_ELEMENT(element))
2307 ResolveGroupElementExt(element, recursion_depth + 1);
2310 group->element_resolved[group->num_elements_resolved++] = element;
2311 element_info[element].in_group[group_nr] = TRUE;
2316 void ResolveGroupElement(int group_element)
2318 ResolveGroupElementExt(group_element, 0);
2321 void InitElementPropertiesStatic()
2323 static boolean clipboard_elements_initialized = FALSE;
2325 static int ep_diggable[] =
2330 EL_SP_BUGGY_BASE_ACTIVATING,
2333 EL_INVISIBLE_SAND_ACTIVE,
2336 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2337 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2342 EL_SP_BUGGY_BASE_ACTIVE,
2349 static int ep_collectible_only[] =
2371 EL_DYNABOMB_INCREASE_NUMBER,
2372 EL_DYNABOMB_INCREASE_SIZE,
2373 EL_DYNABOMB_INCREASE_POWER,
2391 /* !!! handle separately !!! */
2392 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2398 static int ep_dont_run_into[] =
2400 /* same elements as in 'ep_dont_touch' */
2406 /* same elements as in 'ep_dont_collide_with' */
2418 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2423 EL_SP_BUGGY_BASE_ACTIVE,
2430 static int ep_dont_collide_with[] =
2432 /* same elements as in 'ep_dont_touch' */
2449 static int ep_dont_touch[] =
2459 static int ep_indestructible[] =
2463 EL_ACID_POOL_TOPLEFT,
2464 EL_ACID_POOL_TOPRIGHT,
2465 EL_ACID_POOL_BOTTOMLEFT,
2466 EL_ACID_POOL_BOTTOM,
2467 EL_ACID_POOL_BOTTOMRIGHT,
2468 EL_SP_HARDWARE_GRAY,
2469 EL_SP_HARDWARE_GREEN,
2470 EL_SP_HARDWARE_BLUE,
2472 EL_SP_HARDWARE_YELLOW,
2473 EL_SP_HARDWARE_BASE_1,
2474 EL_SP_HARDWARE_BASE_2,
2475 EL_SP_HARDWARE_BASE_3,
2476 EL_SP_HARDWARE_BASE_4,
2477 EL_SP_HARDWARE_BASE_5,
2478 EL_SP_HARDWARE_BASE_6,
2479 EL_INVISIBLE_STEELWALL,
2480 EL_INVISIBLE_STEELWALL_ACTIVE,
2481 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2482 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2483 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2484 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2485 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2486 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2487 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2488 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2489 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2490 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2491 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2492 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2494 EL_LIGHT_SWITCH_ACTIVE,
2495 EL_SIGN_EXCLAMATION,
2496 EL_SIGN_RADIOACTIVITY,
2503 EL_SIGN_ENTRY_FORBIDDEN,
2504 EL_SIGN_EMERGENCY_EXIT,
2512 EL_STEEL_EXIT_CLOSED,
2514 EL_STEEL_EXIT_OPENING,
2515 EL_STEEL_EXIT_CLOSING,
2516 EL_EM_STEEL_EXIT_CLOSED,
2517 EL_EM_STEEL_EXIT_OPEN,
2518 EL_EM_STEEL_EXIT_OPENING,
2519 EL_EM_STEEL_EXIT_CLOSING,
2520 EL_DC_STEELWALL_1_LEFT,
2521 EL_DC_STEELWALL_1_RIGHT,
2522 EL_DC_STEELWALL_1_TOP,
2523 EL_DC_STEELWALL_1_BOTTOM,
2524 EL_DC_STEELWALL_1_HORIZONTAL,
2525 EL_DC_STEELWALL_1_VERTICAL,
2526 EL_DC_STEELWALL_1_TOPLEFT,
2527 EL_DC_STEELWALL_1_TOPRIGHT,
2528 EL_DC_STEELWALL_1_BOTTOMLEFT,
2529 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2530 EL_DC_STEELWALL_1_TOPLEFT_2,
2531 EL_DC_STEELWALL_1_TOPRIGHT_2,
2532 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2533 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2534 EL_DC_STEELWALL_2_LEFT,
2535 EL_DC_STEELWALL_2_RIGHT,
2536 EL_DC_STEELWALL_2_TOP,
2537 EL_DC_STEELWALL_2_BOTTOM,
2538 EL_DC_STEELWALL_2_HORIZONTAL,
2539 EL_DC_STEELWALL_2_VERTICAL,
2540 EL_DC_STEELWALL_2_MIDDLE,
2541 EL_DC_STEELWALL_2_SINGLE,
2542 EL_STEELWALL_SLIPPERY,
2556 EL_GATE_1_GRAY_ACTIVE,
2557 EL_GATE_2_GRAY_ACTIVE,
2558 EL_GATE_3_GRAY_ACTIVE,
2559 EL_GATE_4_GRAY_ACTIVE,
2568 EL_EM_GATE_1_GRAY_ACTIVE,
2569 EL_EM_GATE_2_GRAY_ACTIVE,
2570 EL_EM_GATE_3_GRAY_ACTIVE,
2571 EL_EM_GATE_4_GRAY_ACTIVE,
2580 EL_EMC_GATE_5_GRAY_ACTIVE,
2581 EL_EMC_GATE_6_GRAY_ACTIVE,
2582 EL_EMC_GATE_7_GRAY_ACTIVE,
2583 EL_EMC_GATE_8_GRAY_ACTIVE,
2585 EL_DC_GATE_WHITE_GRAY,
2586 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2587 EL_DC_GATE_FAKE_GRAY,
2589 EL_SWITCHGATE_OPENING,
2590 EL_SWITCHGATE_CLOSED,
2591 EL_SWITCHGATE_CLOSING,
2592 EL_DC_SWITCHGATE_SWITCH_UP,
2593 EL_DC_SWITCHGATE_SWITCH_DOWN,
2595 EL_TIMEGATE_OPENING,
2597 EL_TIMEGATE_CLOSING,
2598 EL_DC_TIMEGATE_SWITCH,
2599 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2603 EL_TUBE_VERTICAL_LEFT,
2604 EL_TUBE_VERTICAL_RIGHT,
2605 EL_TUBE_HORIZONTAL_UP,
2606 EL_TUBE_HORIZONTAL_DOWN,
2611 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2612 EL_EXPANDABLE_STEELWALL_VERTICAL,
2613 EL_EXPANDABLE_STEELWALL_ANY,
2618 static int ep_slippery[] =
2632 EL_ROBOT_WHEEL_ACTIVE,
2638 EL_ACID_POOL_TOPLEFT,
2639 EL_ACID_POOL_TOPRIGHT,
2649 EL_STEELWALL_SLIPPERY,
2652 EL_EMC_WALL_SLIPPERY_1,
2653 EL_EMC_WALL_SLIPPERY_2,
2654 EL_EMC_WALL_SLIPPERY_3,
2655 EL_EMC_WALL_SLIPPERY_4,
2657 EL_EMC_MAGIC_BALL_ACTIVE,
2662 static int ep_can_change[] =
2667 static int ep_can_move[] =
2669 /* same elements as in 'pb_can_move_into_acid' */
2692 static int ep_can_fall[] =
2706 EL_QUICKSAND_FAST_FULL,
2708 EL_BD_MAGIC_WALL_FULL,
2709 EL_DC_MAGIC_WALL_FULL,
2723 static int ep_can_smash_player[] =
2749 static int ep_can_smash_enemies[] =
2758 static int ep_can_smash_everything[] =
2767 static int ep_explodes_by_fire[] =
2769 /* same elements as in 'ep_explodes_impact' */
2774 /* same elements as in 'ep_explodes_smashed' */
2784 EL_EM_DYNAMITE_ACTIVE,
2785 EL_DYNABOMB_PLAYER_1_ACTIVE,
2786 EL_DYNABOMB_PLAYER_2_ACTIVE,
2787 EL_DYNABOMB_PLAYER_3_ACTIVE,
2788 EL_DYNABOMB_PLAYER_4_ACTIVE,
2789 EL_DYNABOMB_INCREASE_NUMBER,
2790 EL_DYNABOMB_INCREASE_SIZE,
2791 EL_DYNABOMB_INCREASE_POWER,
2792 EL_SP_DISK_RED_ACTIVE,
2806 static int ep_explodes_smashed[] =
2808 /* same elements as in 'ep_explodes_impact' */
2822 static int ep_explodes_impact[] =
2831 static int ep_walkable_over[] =
2835 EL_SOKOBAN_FIELD_EMPTY,
2842 EL_EM_STEEL_EXIT_OPEN,
2843 EL_EM_STEEL_EXIT_OPENING,
2852 EL_GATE_1_GRAY_ACTIVE,
2853 EL_GATE_2_GRAY_ACTIVE,
2854 EL_GATE_3_GRAY_ACTIVE,
2855 EL_GATE_4_GRAY_ACTIVE,
2863 static int ep_walkable_inside[] =
2868 EL_TUBE_VERTICAL_LEFT,
2869 EL_TUBE_VERTICAL_RIGHT,
2870 EL_TUBE_HORIZONTAL_UP,
2871 EL_TUBE_HORIZONTAL_DOWN,
2880 static int ep_walkable_under[] =
2885 static int ep_passable_over[] =
2895 EL_EM_GATE_1_GRAY_ACTIVE,
2896 EL_EM_GATE_2_GRAY_ACTIVE,
2897 EL_EM_GATE_3_GRAY_ACTIVE,
2898 EL_EM_GATE_4_GRAY_ACTIVE,
2907 EL_EMC_GATE_5_GRAY_ACTIVE,
2908 EL_EMC_GATE_6_GRAY_ACTIVE,
2909 EL_EMC_GATE_7_GRAY_ACTIVE,
2910 EL_EMC_GATE_8_GRAY_ACTIVE,
2912 EL_DC_GATE_WHITE_GRAY,
2913 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2920 static int ep_passable_inside[] =
2926 EL_SP_PORT_HORIZONTAL,
2927 EL_SP_PORT_VERTICAL,
2929 EL_SP_GRAVITY_PORT_LEFT,
2930 EL_SP_GRAVITY_PORT_RIGHT,
2931 EL_SP_GRAVITY_PORT_UP,
2932 EL_SP_GRAVITY_PORT_DOWN,
2933 EL_SP_GRAVITY_ON_PORT_LEFT,
2934 EL_SP_GRAVITY_ON_PORT_RIGHT,
2935 EL_SP_GRAVITY_ON_PORT_UP,
2936 EL_SP_GRAVITY_ON_PORT_DOWN,
2937 EL_SP_GRAVITY_OFF_PORT_LEFT,
2938 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2939 EL_SP_GRAVITY_OFF_PORT_UP,
2940 EL_SP_GRAVITY_OFF_PORT_DOWN,
2945 static int ep_passable_under[] =
2950 static int ep_droppable[] =
2955 static int ep_explodes_1x1_old[] =
2960 static int ep_pushable[] =
2972 EL_SOKOBAN_FIELD_FULL,
2981 static int ep_explodes_cross_old[] =
2986 static int ep_protected[] =
2988 /* same elements as in 'ep_walkable_inside' */
2992 EL_TUBE_VERTICAL_LEFT,
2993 EL_TUBE_VERTICAL_RIGHT,
2994 EL_TUBE_HORIZONTAL_UP,
2995 EL_TUBE_HORIZONTAL_DOWN,
3001 /* same elements as in 'ep_passable_over' */
3010 EL_EM_GATE_1_GRAY_ACTIVE,
3011 EL_EM_GATE_2_GRAY_ACTIVE,
3012 EL_EM_GATE_3_GRAY_ACTIVE,
3013 EL_EM_GATE_4_GRAY_ACTIVE,
3022 EL_EMC_GATE_5_GRAY_ACTIVE,
3023 EL_EMC_GATE_6_GRAY_ACTIVE,
3024 EL_EMC_GATE_7_GRAY_ACTIVE,
3025 EL_EMC_GATE_8_GRAY_ACTIVE,
3027 EL_DC_GATE_WHITE_GRAY,
3028 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3032 /* same elements as in 'ep_passable_inside' */
3037 EL_SP_PORT_HORIZONTAL,
3038 EL_SP_PORT_VERTICAL,
3040 EL_SP_GRAVITY_PORT_LEFT,
3041 EL_SP_GRAVITY_PORT_RIGHT,
3042 EL_SP_GRAVITY_PORT_UP,
3043 EL_SP_GRAVITY_PORT_DOWN,
3044 EL_SP_GRAVITY_ON_PORT_LEFT,
3045 EL_SP_GRAVITY_ON_PORT_RIGHT,
3046 EL_SP_GRAVITY_ON_PORT_UP,
3047 EL_SP_GRAVITY_ON_PORT_DOWN,
3048 EL_SP_GRAVITY_OFF_PORT_LEFT,
3049 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3050 EL_SP_GRAVITY_OFF_PORT_UP,
3051 EL_SP_GRAVITY_OFF_PORT_DOWN,
3056 static int ep_throwable[] =
3061 static int ep_can_explode[] =
3063 /* same elements as in 'ep_explodes_impact' */
3068 /* same elements as in 'ep_explodes_smashed' */
3074 /* elements that can explode by explosion or by dragonfire */
3078 EL_EM_DYNAMITE_ACTIVE,
3079 EL_DYNABOMB_PLAYER_1_ACTIVE,
3080 EL_DYNABOMB_PLAYER_2_ACTIVE,
3081 EL_DYNABOMB_PLAYER_3_ACTIVE,
3082 EL_DYNABOMB_PLAYER_4_ACTIVE,
3083 EL_DYNABOMB_INCREASE_NUMBER,
3084 EL_DYNABOMB_INCREASE_SIZE,
3085 EL_DYNABOMB_INCREASE_POWER,
3086 EL_SP_DISK_RED_ACTIVE,
3094 /* elements that can explode only by explosion */
3100 static int ep_gravity_reachable[] =
3106 EL_INVISIBLE_SAND_ACTIVE,
3111 EL_SP_PORT_HORIZONTAL,
3112 EL_SP_PORT_VERTICAL,
3114 EL_SP_GRAVITY_PORT_LEFT,
3115 EL_SP_GRAVITY_PORT_RIGHT,
3116 EL_SP_GRAVITY_PORT_UP,
3117 EL_SP_GRAVITY_PORT_DOWN,
3118 EL_SP_GRAVITY_ON_PORT_LEFT,
3119 EL_SP_GRAVITY_ON_PORT_RIGHT,
3120 EL_SP_GRAVITY_ON_PORT_UP,
3121 EL_SP_GRAVITY_ON_PORT_DOWN,
3122 EL_SP_GRAVITY_OFF_PORT_LEFT,
3123 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3124 EL_SP_GRAVITY_OFF_PORT_UP,
3125 EL_SP_GRAVITY_OFF_PORT_DOWN,
3131 static int ep_player[] =
3138 EL_SOKOBAN_FIELD_PLAYER,
3144 static int ep_can_pass_magic_wall[] =
3158 static int ep_can_pass_dc_magic_wall[] =
3174 static int ep_switchable[] =
3178 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3179 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3180 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3181 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3182 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3183 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3184 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3185 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3186 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3187 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3188 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3189 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3190 EL_SWITCHGATE_SWITCH_UP,
3191 EL_SWITCHGATE_SWITCH_DOWN,
3192 EL_DC_SWITCHGATE_SWITCH_UP,
3193 EL_DC_SWITCHGATE_SWITCH_DOWN,
3195 EL_LIGHT_SWITCH_ACTIVE,
3197 EL_DC_TIMEGATE_SWITCH,
3198 EL_BALLOON_SWITCH_LEFT,
3199 EL_BALLOON_SWITCH_RIGHT,
3200 EL_BALLOON_SWITCH_UP,
3201 EL_BALLOON_SWITCH_DOWN,
3202 EL_BALLOON_SWITCH_ANY,
3203 EL_BALLOON_SWITCH_NONE,
3206 EL_EMC_MAGIC_BALL_SWITCH,
3207 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3212 static int ep_bd_element[] =
3246 static int ep_sp_element[] =
3248 /* should always be valid */
3251 /* standard classic Supaplex elements */
3258 EL_SP_HARDWARE_GRAY,
3266 EL_SP_GRAVITY_PORT_RIGHT,
3267 EL_SP_GRAVITY_PORT_DOWN,
3268 EL_SP_GRAVITY_PORT_LEFT,
3269 EL_SP_GRAVITY_PORT_UP,
3274 EL_SP_PORT_VERTICAL,
3275 EL_SP_PORT_HORIZONTAL,
3281 EL_SP_HARDWARE_BASE_1,
3282 EL_SP_HARDWARE_GREEN,
3283 EL_SP_HARDWARE_BLUE,
3285 EL_SP_HARDWARE_YELLOW,
3286 EL_SP_HARDWARE_BASE_2,
3287 EL_SP_HARDWARE_BASE_3,
3288 EL_SP_HARDWARE_BASE_4,
3289 EL_SP_HARDWARE_BASE_5,
3290 EL_SP_HARDWARE_BASE_6,
3294 /* additional elements that appeared in newer Supaplex levels */
3297 /* additional gravity port elements (not switching, but setting gravity) */
3298 EL_SP_GRAVITY_ON_PORT_LEFT,
3299 EL_SP_GRAVITY_ON_PORT_RIGHT,
3300 EL_SP_GRAVITY_ON_PORT_UP,
3301 EL_SP_GRAVITY_ON_PORT_DOWN,
3302 EL_SP_GRAVITY_OFF_PORT_LEFT,
3303 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3304 EL_SP_GRAVITY_OFF_PORT_UP,
3305 EL_SP_GRAVITY_OFF_PORT_DOWN,
3307 /* more than one Murphy in a level results in an inactive clone */
3310 /* runtime Supaplex elements */
3311 EL_SP_DISK_RED_ACTIVE,
3312 EL_SP_TERMINAL_ACTIVE,
3313 EL_SP_BUGGY_BASE_ACTIVATING,
3314 EL_SP_BUGGY_BASE_ACTIVE,
3321 static int ep_sb_element[] =
3326 EL_SOKOBAN_FIELD_EMPTY,
3327 EL_SOKOBAN_FIELD_FULL,
3328 EL_SOKOBAN_FIELD_PLAYER,
3333 EL_INVISIBLE_STEELWALL,
3338 static int ep_gem[] =
3350 static int ep_food_dark_yamyam[] =
3378 static int ep_food_penguin[] =
3392 static int ep_food_pig[] =
3404 static int ep_historic_wall[] =
3415 EL_GATE_1_GRAY_ACTIVE,
3416 EL_GATE_2_GRAY_ACTIVE,
3417 EL_GATE_3_GRAY_ACTIVE,
3418 EL_GATE_4_GRAY_ACTIVE,
3427 EL_EM_GATE_1_GRAY_ACTIVE,
3428 EL_EM_GATE_2_GRAY_ACTIVE,
3429 EL_EM_GATE_3_GRAY_ACTIVE,
3430 EL_EM_GATE_4_GRAY_ACTIVE,
3437 EL_EXPANDABLE_WALL_HORIZONTAL,
3438 EL_EXPANDABLE_WALL_VERTICAL,
3439 EL_EXPANDABLE_WALL_ANY,
3440 EL_EXPANDABLE_WALL_GROWING,
3441 EL_BD_EXPANDABLE_WALL,
3448 EL_SP_HARDWARE_GRAY,
3449 EL_SP_HARDWARE_GREEN,
3450 EL_SP_HARDWARE_BLUE,
3452 EL_SP_HARDWARE_YELLOW,
3453 EL_SP_HARDWARE_BASE_1,
3454 EL_SP_HARDWARE_BASE_2,
3455 EL_SP_HARDWARE_BASE_3,
3456 EL_SP_HARDWARE_BASE_4,
3457 EL_SP_HARDWARE_BASE_5,
3458 EL_SP_HARDWARE_BASE_6,
3460 EL_SP_TERMINAL_ACTIVE,
3463 EL_INVISIBLE_STEELWALL,
3464 EL_INVISIBLE_STEELWALL_ACTIVE,
3466 EL_INVISIBLE_WALL_ACTIVE,
3467 EL_STEELWALL_SLIPPERY,
3484 static int ep_historic_solid[] =
3488 EL_EXPANDABLE_WALL_HORIZONTAL,
3489 EL_EXPANDABLE_WALL_VERTICAL,
3490 EL_EXPANDABLE_WALL_ANY,
3491 EL_BD_EXPANDABLE_WALL,
3504 EL_QUICKSAND_FILLING,
3505 EL_QUICKSAND_EMPTYING,
3507 EL_MAGIC_WALL_ACTIVE,
3508 EL_MAGIC_WALL_EMPTYING,
3509 EL_MAGIC_WALL_FILLING,
3513 EL_BD_MAGIC_WALL_ACTIVE,
3514 EL_BD_MAGIC_WALL_EMPTYING,
3515 EL_BD_MAGIC_WALL_FULL,
3516 EL_BD_MAGIC_WALL_FILLING,
3517 EL_BD_MAGIC_WALL_DEAD,
3526 EL_SP_TERMINAL_ACTIVE,
3530 EL_INVISIBLE_WALL_ACTIVE,
3531 EL_SWITCHGATE_SWITCH_UP,
3532 EL_SWITCHGATE_SWITCH_DOWN,
3533 EL_DC_SWITCHGATE_SWITCH_UP,
3534 EL_DC_SWITCHGATE_SWITCH_DOWN,
3536 EL_TIMEGATE_SWITCH_ACTIVE,
3537 EL_DC_TIMEGATE_SWITCH,
3538 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3550 /* the following elements are a direct copy of "indestructible" elements,
3551 except "EL_ACID", which is "indestructible", but not "solid"! */
3556 EL_ACID_POOL_TOPLEFT,
3557 EL_ACID_POOL_TOPRIGHT,
3558 EL_ACID_POOL_BOTTOMLEFT,
3559 EL_ACID_POOL_BOTTOM,
3560 EL_ACID_POOL_BOTTOMRIGHT,
3561 EL_SP_HARDWARE_GRAY,
3562 EL_SP_HARDWARE_GREEN,
3563 EL_SP_HARDWARE_BLUE,
3565 EL_SP_HARDWARE_YELLOW,
3566 EL_SP_HARDWARE_BASE_1,
3567 EL_SP_HARDWARE_BASE_2,
3568 EL_SP_HARDWARE_BASE_3,
3569 EL_SP_HARDWARE_BASE_4,
3570 EL_SP_HARDWARE_BASE_5,
3571 EL_SP_HARDWARE_BASE_6,
3572 EL_INVISIBLE_STEELWALL,
3573 EL_INVISIBLE_STEELWALL_ACTIVE,
3574 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3575 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3576 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3577 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3578 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3579 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3580 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3581 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3582 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3583 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3584 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3585 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3587 EL_LIGHT_SWITCH_ACTIVE,
3588 EL_SIGN_EXCLAMATION,
3589 EL_SIGN_RADIOACTIVITY,
3596 EL_SIGN_ENTRY_FORBIDDEN,
3597 EL_SIGN_EMERGENCY_EXIT,
3605 EL_STEEL_EXIT_CLOSED,
3607 EL_DC_STEELWALL_1_LEFT,
3608 EL_DC_STEELWALL_1_RIGHT,
3609 EL_DC_STEELWALL_1_TOP,
3610 EL_DC_STEELWALL_1_BOTTOM,
3611 EL_DC_STEELWALL_1_HORIZONTAL,
3612 EL_DC_STEELWALL_1_VERTICAL,
3613 EL_DC_STEELWALL_1_TOPLEFT,
3614 EL_DC_STEELWALL_1_TOPRIGHT,
3615 EL_DC_STEELWALL_1_BOTTOMLEFT,
3616 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3617 EL_DC_STEELWALL_1_TOPLEFT_2,
3618 EL_DC_STEELWALL_1_TOPRIGHT_2,
3619 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3620 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3621 EL_DC_STEELWALL_2_LEFT,
3622 EL_DC_STEELWALL_2_RIGHT,
3623 EL_DC_STEELWALL_2_TOP,
3624 EL_DC_STEELWALL_2_BOTTOM,
3625 EL_DC_STEELWALL_2_HORIZONTAL,
3626 EL_DC_STEELWALL_2_VERTICAL,
3627 EL_DC_STEELWALL_2_MIDDLE,
3628 EL_DC_STEELWALL_2_SINGLE,
3629 EL_STEELWALL_SLIPPERY,
3643 EL_GATE_1_GRAY_ACTIVE,
3644 EL_GATE_2_GRAY_ACTIVE,
3645 EL_GATE_3_GRAY_ACTIVE,
3646 EL_GATE_4_GRAY_ACTIVE,
3655 EL_EM_GATE_1_GRAY_ACTIVE,
3656 EL_EM_GATE_2_GRAY_ACTIVE,
3657 EL_EM_GATE_3_GRAY_ACTIVE,
3658 EL_EM_GATE_4_GRAY_ACTIVE,
3660 EL_SWITCHGATE_OPENING,
3661 EL_SWITCHGATE_CLOSED,
3662 EL_SWITCHGATE_CLOSING,
3664 EL_TIMEGATE_OPENING,
3666 EL_TIMEGATE_CLOSING,
3670 EL_TUBE_VERTICAL_LEFT,
3671 EL_TUBE_VERTICAL_RIGHT,
3672 EL_TUBE_HORIZONTAL_UP,
3673 EL_TUBE_HORIZONTAL_DOWN,
3682 static int ep_classic_enemy[] =
3699 static int ep_belt[] =
3701 EL_CONVEYOR_BELT_1_LEFT,
3702 EL_CONVEYOR_BELT_1_MIDDLE,
3703 EL_CONVEYOR_BELT_1_RIGHT,
3704 EL_CONVEYOR_BELT_2_LEFT,
3705 EL_CONVEYOR_BELT_2_MIDDLE,
3706 EL_CONVEYOR_BELT_2_RIGHT,
3707 EL_CONVEYOR_BELT_3_LEFT,
3708 EL_CONVEYOR_BELT_3_MIDDLE,
3709 EL_CONVEYOR_BELT_3_RIGHT,
3710 EL_CONVEYOR_BELT_4_LEFT,
3711 EL_CONVEYOR_BELT_4_MIDDLE,
3712 EL_CONVEYOR_BELT_4_RIGHT,
3717 static int ep_belt_active[] =
3719 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3720 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3721 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3722 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3723 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3724 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3725 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3726 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3727 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3728 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3729 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3730 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3735 static int ep_belt_switch[] =
3737 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3738 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3739 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3740 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3741 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3742 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3743 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3744 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3745 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3746 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3747 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3748 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3753 static int ep_tube[] =
3760 EL_TUBE_HORIZONTAL_UP,
3761 EL_TUBE_HORIZONTAL_DOWN,
3763 EL_TUBE_VERTICAL_LEFT,
3764 EL_TUBE_VERTICAL_RIGHT,
3770 static int ep_acid_pool[] =
3772 EL_ACID_POOL_TOPLEFT,
3773 EL_ACID_POOL_TOPRIGHT,
3774 EL_ACID_POOL_BOTTOMLEFT,
3775 EL_ACID_POOL_BOTTOM,
3776 EL_ACID_POOL_BOTTOMRIGHT,
3781 static int ep_keygate[] =
3791 EL_GATE_1_GRAY_ACTIVE,
3792 EL_GATE_2_GRAY_ACTIVE,
3793 EL_GATE_3_GRAY_ACTIVE,
3794 EL_GATE_4_GRAY_ACTIVE,
3803 EL_EM_GATE_1_GRAY_ACTIVE,
3804 EL_EM_GATE_2_GRAY_ACTIVE,
3805 EL_EM_GATE_3_GRAY_ACTIVE,
3806 EL_EM_GATE_4_GRAY_ACTIVE,
3815 EL_EMC_GATE_5_GRAY_ACTIVE,
3816 EL_EMC_GATE_6_GRAY_ACTIVE,
3817 EL_EMC_GATE_7_GRAY_ACTIVE,
3818 EL_EMC_GATE_8_GRAY_ACTIVE,
3820 EL_DC_GATE_WHITE_GRAY,
3821 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3826 static int ep_amoeboid[] =
3838 static int ep_amoebalive[] =
3849 static int ep_has_editor_content[] =
3855 EL_SOKOBAN_FIELD_PLAYER,
3872 static int ep_can_turn_each_move[] =
3874 /* !!! do something with this one !!! */
3878 static int ep_can_grow[] =
3892 static int ep_active_bomb[] =
3895 EL_EM_DYNAMITE_ACTIVE,
3896 EL_DYNABOMB_PLAYER_1_ACTIVE,
3897 EL_DYNABOMB_PLAYER_2_ACTIVE,
3898 EL_DYNABOMB_PLAYER_3_ACTIVE,
3899 EL_DYNABOMB_PLAYER_4_ACTIVE,
3900 EL_SP_DISK_RED_ACTIVE,
3905 static int ep_inactive[] =
3915 EL_QUICKSAND_FAST_EMPTY,
3938 EL_GATE_1_GRAY_ACTIVE,
3939 EL_GATE_2_GRAY_ACTIVE,
3940 EL_GATE_3_GRAY_ACTIVE,
3941 EL_GATE_4_GRAY_ACTIVE,
3950 EL_EM_GATE_1_GRAY_ACTIVE,
3951 EL_EM_GATE_2_GRAY_ACTIVE,
3952 EL_EM_GATE_3_GRAY_ACTIVE,
3953 EL_EM_GATE_4_GRAY_ACTIVE,
3962 EL_EMC_GATE_5_GRAY_ACTIVE,
3963 EL_EMC_GATE_6_GRAY_ACTIVE,
3964 EL_EMC_GATE_7_GRAY_ACTIVE,
3965 EL_EMC_GATE_8_GRAY_ACTIVE,
3967 EL_DC_GATE_WHITE_GRAY,
3968 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3969 EL_DC_GATE_FAKE_GRAY,
3972 EL_INVISIBLE_STEELWALL,
3980 EL_WALL_EMERALD_YELLOW,
3981 EL_DYNABOMB_INCREASE_NUMBER,
3982 EL_DYNABOMB_INCREASE_SIZE,
3983 EL_DYNABOMB_INCREASE_POWER,
3987 EL_SOKOBAN_FIELD_EMPTY,
3988 EL_SOKOBAN_FIELD_FULL,
3989 EL_WALL_EMERALD_RED,
3990 EL_WALL_EMERALD_PURPLE,
3991 EL_ACID_POOL_TOPLEFT,
3992 EL_ACID_POOL_TOPRIGHT,
3993 EL_ACID_POOL_BOTTOMLEFT,
3994 EL_ACID_POOL_BOTTOM,
3995 EL_ACID_POOL_BOTTOMRIGHT,
3999 EL_BD_MAGIC_WALL_DEAD,
4001 EL_DC_MAGIC_WALL_DEAD,
4002 EL_AMOEBA_TO_DIAMOND,
4010 EL_SP_GRAVITY_PORT_RIGHT,
4011 EL_SP_GRAVITY_PORT_DOWN,
4012 EL_SP_GRAVITY_PORT_LEFT,
4013 EL_SP_GRAVITY_PORT_UP,
4014 EL_SP_PORT_HORIZONTAL,
4015 EL_SP_PORT_VERTICAL,
4026 EL_SP_HARDWARE_GRAY,
4027 EL_SP_HARDWARE_GREEN,
4028 EL_SP_HARDWARE_BLUE,
4030 EL_SP_HARDWARE_YELLOW,
4031 EL_SP_HARDWARE_BASE_1,
4032 EL_SP_HARDWARE_BASE_2,
4033 EL_SP_HARDWARE_BASE_3,
4034 EL_SP_HARDWARE_BASE_4,
4035 EL_SP_HARDWARE_BASE_5,
4036 EL_SP_HARDWARE_BASE_6,
4037 EL_SP_GRAVITY_ON_PORT_LEFT,
4038 EL_SP_GRAVITY_ON_PORT_RIGHT,
4039 EL_SP_GRAVITY_ON_PORT_UP,
4040 EL_SP_GRAVITY_ON_PORT_DOWN,
4041 EL_SP_GRAVITY_OFF_PORT_LEFT,
4042 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4043 EL_SP_GRAVITY_OFF_PORT_UP,
4044 EL_SP_GRAVITY_OFF_PORT_DOWN,
4045 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4046 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4047 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4048 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4049 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4050 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4051 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4052 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4053 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4054 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4055 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4056 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4057 EL_SIGN_EXCLAMATION,
4058 EL_SIGN_RADIOACTIVITY,
4065 EL_SIGN_ENTRY_FORBIDDEN,
4066 EL_SIGN_EMERGENCY_EXIT,
4074 EL_DC_STEELWALL_1_LEFT,
4075 EL_DC_STEELWALL_1_RIGHT,
4076 EL_DC_STEELWALL_1_TOP,
4077 EL_DC_STEELWALL_1_BOTTOM,
4078 EL_DC_STEELWALL_1_HORIZONTAL,
4079 EL_DC_STEELWALL_1_VERTICAL,
4080 EL_DC_STEELWALL_1_TOPLEFT,
4081 EL_DC_STEELWALL_1_TOPRIGHT,
4082 EL_DC_STEELWALL_1_BOTTOMLEFT,
4083 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4084 EL_DC_STEELWALL_1_TOPLEFT_2,
4085 EL_DC_STEELWALL_1_TOPRIGHT_2,
4086 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4087 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4088 EL_DC_STEELWALL_2_LEFT,
4089 EL_DC_STEELWALL_2_RIGHT,
4090 EL_DC_STEELWALL_2_TOP,
4091 EL_DC_STEELWALL_2_BOTTOM,
4092 EL_DC_STEELWALL_2_HORIZONTAL,
4093 EL_DC_STEELWALL_2_VERTICAL,
4094 EL_DC_STEELWALL_2_MIDDLE,
4095 EL_DC_STEELWALL_2_SINGLE,
4096 EL_STEELWALL_SLIPPERY,
4101 EL_EMC_WALL_SLIPPERY_1,
4102 EL_EMC_WALL_SLIPPERY_2,
4103 EL_EMC_WALL_SLIPPERY_3,
4104 EL_EMC_WALL_SLIPPERY_4,
4125 static int ep_em_slippery_wall[] =
4130 static int ep_gfx_crumbled[] =
4141 static int ep_editor_cascade_active[] =
4143 EL_INTERNAL_CASCADE_BD_ACTIVE,
4144 EL_INTERNAL_CASCADE_EM_ACTIVE,
4145 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4146 EL_INTERNAL_CASCADE_RND_ACTIVE,
4147 EL_INTERNAL_CASCADE_SB_ACTIVE,
4148 EL_INTERNAL_CASCADE_SP_ACTIVE,
4149 EL_INTERNAL_CASCADE_DC_ACTIVE,
4150 EL_INTERNAL_CASCADE_DX_ACTIVE,
4151 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4152 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4153 EL_INTERNAL_CASCADE_CE_ACTIVE,
4154 EL_INTERNAL_CASCADE_GE_ACTIVE,
4155 EL_INTERNAL_CASCADE_REF_ACTIVE,
4156 EL_INTERNAL_CASCADE_USER_ACTIVE,
4157 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4162 static int ep_editor_cascade_inactive[] =
4164 EL_INTERNAL_CASCADE_BD,
4165 EL_INTERNAL_CASCADE_EM,
4166 EL_INTERNAL_CASCADE_EMC,
4167 EL_INTERNAL_CASCADE_RND,
4168 EL_INTERNAL_CASCADE_SB,
4169 EL_INTERNAL_CASCADE_SP,
4170 EL_INTERNAL_CASCADE_DC,
4171 EL_INTERNAL_CASCADE_DX,
4172 EL_INTERNAL_CASCADE_CHARS,
4173 EL_INTERNAL_CASCADE_STEEL_CHARS,
4174 EL_INTERNAL_CASCADE_CE,
4175 EL_INTERNAL_CASCADE_GE,
4176 EL_INTERNAL_CASCADE_REF,
4177 EL_INTERNAL_CASCADE_USER,
4178 EL_INTERNAL_CASCADE_DYNAMIC,
4183 static int ep_obsolete[] =
4187 EL_EM_KEY_1_FILE_OBSOLETE,
4188 EL_EM_KEY_2_FILE_OBSOLETE,
4189 EL_EM_KEY_3_FILE_OBSOLETE,
4190 EL_EM_KEY_4_FILE_OBSOLETE,
4191 EL_ENVELOPE_OBSOLETE,
4200 } element_properties[] =
4202 { ep_diggable, EP_DIGGABLE },
4203 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4204 { ep_dont_run_into, EP_DONT_RUN_INTO },
4205 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4206 { ep_dont_touch, EP_DONT_TOUCH },
4207 { ep_indestructible, EP_INDESTRUCTIBLE },
4208 { ep_slippery, EP_SLIPPERY },
4209 { ep_can_change, EP_CAN_CHANGE },
4210 { ep_can_move, EP_CAN_MOVE },
4211 { ep_can_fall, EP_CAN_FALL },
4212 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4213 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4214 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4215 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4216 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4217 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4218 { ep_walkable_over, EP_WALKABLE_OVER },
4219 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4220 { ep_walkable_under, EP_WALKABLE_UNDER },
4221 { ep_passable_over, EP_PASSABLE_OVER },
4222 { ep_passable_inside, EP_PASSABLE_INSIDE },
4223 { ep_passable_under, EP_PASSABLE_UNDER },
4224 { ep_droppable, EP_DROPPABLE },
4225 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4226 { ep_pushable, EP_PUSHABLE },
4227 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4228 { ep_protected, EP_PROTECTED },
4229 { ep_throwable, EP_THROWABLE },
4230 { ep_can_explode, EP_CAN_EXPLODE },
4231 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4233 { ep_player, EP_PLAYER },
4234 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4235 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4236 { ep_switchable, EP_SWITCHABLE },
4237 { ep_bd_element, EP_BD_ELEMENT },
4238 { ep_sp_element, EP_SP_ELEMENT },
4239 { ep_sb_element, EP_SB_ELEMENT },
4241 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4242 { ep_food_penguin, EP_FOOD_PENGUIN },
4243 { ep_food_pig, EP_FOOD_PIG },
4244 { ep_historic_wall, EP_HISTORIC_WALL },
4245 { ep_historic_solid, EP_HISTORIC_SOLID },
4246 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4247 { ep_belt, EP_BELT },
4248 { ep_belt_active, EP_BELT_ACTIVE },
4249 { ep_belt_switch, EP_BELT_SWITCH },
4250 { ep_tube, EP_TUBE },
4251 { ep_acid_pool, EP_ACID_POOL },
4252 { ep_keygate, EP_KEYGATE },
4253 { ep_amoeboid, EP_AMOEBOID },
4254 { ep_amoebalive, EP_AMOEBALIVE },
4255 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4256 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4257 { ep_can_grow, EP_CAN_GROW },
4258 { ep_active_bomb, EP_ACTIVE_BOMB },
4259 { ep_inactive, EP_INACTIVE },
4261 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4263 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4265 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4266 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4268 { ep_obsolete, EP_OBSOLETE },
4275 /* always start with reliable default values (element has no properties) */
4276 /* (but never initialize clipboard elements after the very first time) */
4277 /* (to be able to use clipboard elements between several levels) */
4278 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4279 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4280 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4281 SET_PROPERTY(i, j, FALSE);
4283 /* set all base element properties from above array definitions */
4284 for (i = 0; element_properties[i].elements != NULL; i++)
4285 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4286 SET_PROPERTY((element_properties[i].elements)[j],
4287 element_properties[i].property, TRUE);
4289 /* copy properties to some elements that are only stored in level file */
4290 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4291 for (j = 0; copy_properties[j][0] != -1; j++)
4292 if (HAS_PROPERTY(copy_properties[j][0], i))
4293 for (k = 1; k <= 4; k++)
4294 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4296 /* set static element properties that are not listed in array definitions */
4297 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4298 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4300 clipboard_elements_initialized = TRUE;
4303 void InitElementPropertiesEngine(int engine_version)
4305 static int no_wall_properties[] =
4308 EP_COLLECTIBLE_ONLY,
4310 EP_DONT_COLLIDE_WITH,
4313 EP_CAN_SMASH_PLAYER,
4314 EP_CAN_SMASH_ENEMIES,
4315 EP_CAN_SMASH_EVERYTHING,
4320 EP_FOOD_DARK_YAMYAM,
4336 /* important: after initialization in InitElementPropertiesStatic(), the
4337 elements are not again initialized to a default value; therefore all
4338 changes have to make sure that they leave the element with a defined
4339 property (which means that conditional property changes must be set to
4340 a reliable default value before) */
4342 /* resolve group elements */
4343 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4344 ResolveGroupElement(EL_GROUP_START + i);
4346 /* set all special, combined or engine dependent element properties */
4347 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4349 /* do not change (already initialized) clipboard elements here */
4350 if (IS_CLIPBOARD_ELEMENT(i))
4353 /* ---------- INACTIVE ------------------------------------------------- */
4354 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4355 i <= EL_CHAR_END) ||
4356 (i >= EL_STEEL_CHAR_START &&
4357 i <= EL_STEEL_CHAR_END)));
4359 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4360 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4361 IS_WALKABLE_INSIDE(i) ||
4362 IS_WALKABLE_UNDER(i)));
4364 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4365 IS_PASSABLE_INSIDE(i) ||
4366 IS_PASSABLE_UNDER(i)));
4368 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4369 IS_PASSABLE_OVER(i)));
4371 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4372 IS_PASSABLE_INSIDE(i)));
4374 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4375 IS_PASSABLE_UNDER(i)));
4377 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4380 /* ---------- COLLECTIBLE ---------------------------------------------- */
4381 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4385 /* ---------- SNAPPABLE ------------------------------------------------ */
4386 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4387 IS_COLLECTIBLE(i) ||
4391 /* ---------- WALL ----------------------------------------------------- */
4392 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4394 for (j = 0; no_wall_properties[j] != -1; j++)
4395 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4396 i >= EL_FIRST_RUNTIME_UNREAL)
4397 SET_PROPERTY(i, EP_WALL, FALSE);
4399 if (IS_HISTORIC_WALL(i))
4400 SET_PROPERTY(i, EP_WALL, TRUE);
4402 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4403 if (engine_version < VERSION_IDENT(2,2,0,0))
4404 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4406 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4408 !IS_COLLECTIBLE(i)));
4410 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4411 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4412 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4414 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4415 IS_INDESTRUCTIBLE(i)));
4417 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4419 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4420 else if (engine_version < VERSION_IDENT(2,2,0,0))
4421 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4423 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4427 if (IS_CUSTOM_ELEMENT(i))
4429 /* these are additional properties which are initially false when set */
4431 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4433 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4434 if (DONT_COLLIDE_WITH(i))
4435 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4437 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4438 if (CAN_SMASH_EVERYTHING(i))
4439 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4440 if (CAN_SMASH_ENEMIES(i))
4441 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4444 /* ---------- CAN_SMASH ------------------------------------------------ */
4445 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4446 CAN_SMASH_ENEMIES(i) ||
4447 CAN_SMASH_EVERYTHING(i)));
4449 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4450 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4451 EXPLODES_BY_FIRE(i)));
4453 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4454 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4455 EXPLODES_SMASHED(i)));
4457 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4458 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4459 EXPLODES_IMPACT(i)));
4461 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4462 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4464 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4465 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4466 i == EL_BLACK_ORB));
4468 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4469 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4471 IS_CUSTOM_ELEMENT(i)));
4473 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4474 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4475 i == EL_SP_ELECTRON));
4477 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4478 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4479 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4480 getMoveIntoAcidProperty(&level, i));
4482 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4483 if (MAYBE_DONT_COLLIDE_WITH(i))
4484 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4485 getDontCollideWithProperty(&level, i));
4487 /* ---------- SP_PORT -------------------------------------------------- */
4488 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4489 IS_PASSABLE_INSIDE(i)));
4491 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4492 for (j = 0; j < level.num_android_clone_elements; j++)
4493 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4495 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4497 /* ---------- CAN_CHANGE ----------------------------------------------- */
4498 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4499 for (j = 0; j < element_info[i].num_change_pages; j++)
4500 if (element_info[i].change_page[j].can_change)
4501 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4503 /* ---------- HAS_ACTION ----------------------------------------------- */
4504 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4505 for (j = 0; j < element_info[i].num_change_pages; j++)
4506 if (element_info[i].change_page[j].has_action)
4507 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4509 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4510 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4513 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4514 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4515 element_info[i].crumbled[ACTION_DEFAULT] !=
4516 element_info[i].graphic[ACTION_DEFAULT]);
4518 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4519 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4520 IS_EDITOR_CASCADE_INACTIVE(i)));
4523 /* dynamically adjust element properties according to game engine version */
4525 static int ep_em_slippery_wall[] =
4530 EL_EXPANDABLE_WALL_HORIZONTAL,
4531 EL_EXPANDABLE_WALL_VERTICAL,
4532 EL_EXPANDABLE_WALL_ANY,
4533 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4534 EL_EXPANDABLE_STEELWALL_VERTICAL,
4535 EL_EXPANDABLE_STEELWALL_ANY,
4536 EL_EXPANDABLE_STEELWALL_GROWING,
4540 static int ep_em_explodes_by_fire[] =
4543 EL_EM_DYNAMITE_ACTIVE,
4548 /* special EM style gems behaviour */
4549 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4550 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4551 level.em_slippery_gems);
4553 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4554 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4555 (level.em_slippery_gems &&
4556 engine_version > VERSION_IDENT(2,0,1,0)));
4558 /* special EM style explosion behaviour regarding chain reactions */
4559 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4560 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4561 level.em_explodes_by_fire);
4564 /* this is needed because some graphics depend on element properties */
4565 if (game_status == GAME_MODE_PLAYING)
4566 InitElementGraphicInfo();
4569 void InitElementPropertiesAfterLoading(int engine_version)
4573 /* set some other uninitialized values of custom elements in older levels */
4574 if (engine_version < VERSION_IDENT(3,1,0,0))
4576 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4578 int element = EL_CUSTOM_START + i;
4580 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4582 element_info[element].explosion_delay = 17;
4583 element_info[element].ignition_delay = 8;
4588 void InitElementPropertiesGfxElement()
4592 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4594 struct ElementInfo *ei = &element_info[i];
4596 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4600 static void InitGlobal()
4605 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4607 /* check if element_name_info entry defined for each element in "main.h" */
4608 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4609 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4611 element_info[i].token_name = element_name_info[i].token_name;
4612 element_info[i].class_name = element_name_info[i].class_name;
4613 element_info[i].editor_description= element_name_info[i].editor_description;
4616 /* create hash from image config list */
4617 image_config_hash = newSetupFileHash();
4618 for (i = 0; image_config[i].token != NULL; i++)
4619 setHashEntry(image_config_hash,
4620 image_config[i].token,
4621 image_config[i].value);
4623 /* create hash from element token list */
4624 element_token_hash = newSetupFileHash();
4625 for (i = 0; element_name_info[i].token_name != NULL; i++)
4626 setHashEntry(element_token_hash,
4627 element_name_info[i].token_name,
4630 /* create hash from graphic token list */
4631 graphic_token_hash = newSetupFileHash();
4632 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4633 if (strSuffix(image_config[i].value, ".png") ||
4634 strSuffix(image_config[i].value, ".pcx") ||
4635 strSuffix(image_config[i].value, ".wav") ||
4636 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4637 setHashEntry(graphic_token_hash,
4638 image_config[i].token,
4639 int2str(graphic++, 0));
4641 /* create hash from font token list */
4642 font_token_hash = newSetupFileHash();
4643 for (i = 0; font_info[i].token_name != NULL; i++)
4644 setHashEntry(font_token_hash,
4645 font_info[i].token_name,
4648 /* set default filenames for all cloned graphics in static configuration */
4649 for (i = 0; image_config[i].token != NULL; i++)
4651 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4653 char *token = image_config[i].token;
4654 char *token_clone_from = getStringCat2(token, ".clone_from");
4655 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4657 if (token_cloned != NULL)
4659 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4661 if (value_cloned != NULL)
4663 /* set default filename in static configuration */
4664 image_config[i].value = value_cloned;
4666 /* set default filename in image config hash */
4667 setHashEntry(image_config_hash, token, value_cloned);
4671 free(token_clone_from);
4675 /* always start with reliable default values (all elements) */
4676 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4677 ActiveElement[i] = i;
4679 /* now add all entries that have an active state (active elements) */
4680 for (i = 0; element_with_active_state[i].element != -1; i++)
4682 int element = element_with_active_state[i].element;
4683 int element_active = element_with_active_state[i].element_active;
4685 ActiveElement[element] = element_active;
4688 /* always start with reliable default values (all buttons) */
4689 for (i = 0; i < NUM_IMAGE_FILES; i++)
4690 ActiveButton[i] = i;
4692 /* now add all entries that have an active state (active buttons) */
4693 for (i = 0; button_with_active_state[i].button != -1; i++)
4695 int button = button_with_active_state[i].button;
4696 int button_active = button_with_active_state[i].button_active;
4698 ActiveButton[button] = button_active;
4701 /* always start with reliable default values (all fonts) */
4702 for (i = 0; i < NUM_FONTS; i++)
4705 /* now add all entries that have an active state (active fonts) */
4706 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4708 int font = font_with_active_state[i].font_nr;
4709 int font_active = font_with_active_state[i].font_nr_active;
4711 ActiveFont[font] = font_active;
4714 global.autoplay_leveldir = NULL;
4715 global.convert_leveldir = NULL;
4716 global.create_images_dir = NULL;
4718 global.frames_per_second = 0;
4720 global.border_status = GAME_MODE_LOADING;
4721 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4723 global.use_envelope_request = FALSE;
4726 void Execute_Command(char *command)
4730 if (strEqual(command, "print graphicsinfo.conf"))
4732 Print("# You can configure additional/alternative image files here.\n");
4733 Print("# (The entries below are default and therefore commented out.)\n");
4735 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4737 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4740 for (i = 0; image_config[i].token != NULL; i++)
4741 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4742 image_config[i].value));
4746 else if (strEqual(command, "print soundsinfo.conf"))
4748 Print("# You can configure additional/alternative sound files here.\n");
4749 Print("# (The entries below are default and therefore commented out.)\n");
4751 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4753 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4756 for (i = 0; sound_config[i].token != NULL; i++)
4757 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4758 sound_config[i].value));
4762 else if (strEqual(command, "print musicinfo.conf"))
4764 Print("# You can configure additional/alternative music files here.\n");
4765 Print("# (The entries below are default and therefore commented out.)\n");
4767 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4769 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4772 for (i = 0; music_config[i].token != NULL; i++)
4773 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4774 music_config[i].value));
4778 else if (strEqual(command, "print editorsetup.conf"))
4780 Print("# You can configure your personal editor element list here.\n");
4781 Print("# (The entries below are default and therefore commented out.)\n");
4784 /* this is needed to be able to check element list for cascade elements */
4785 InitElementPropertiesStatic();
4786 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4788 PrintEditorElementList();
4792 else if (strEqual(command, "print helpanim.conf"))
4794 Print("# You can configure different element help animations here.\n");
4795 Print("# (The entries below are default and therefore commented out.)\n");
4798 for (i = 0; helpanim_config[i].token != NULL; i++)
4800 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4801 helpanim_config[i].value));
4803 if (strEqual(helpanim_config[i].token, "end"))
4809 else if (strEqual(command, "print helptext.conf"))
4811 Print("# You can configure different element help text here.\n");
4812 Print("# (The entries below are default and therefore commented out.)\n");
4815 for (i = 0; helptext_config[i].token != NULL; i++)
4816 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4817 helptext_config[i].value));
4821 else if (strPrefix(command, "dump level "))
4823 char *filename = &command[11];
4825 if (!fileExists(filename))
4826 Error(ERR_EXIT, "cannot open file '%s'", filename);
4828 LoadLevelFromFilename(&level, filename);
4833 else if (strPrefix(command, "dump tape "))
4835 char *filename = &command[10];
4837 if (!fileExists(filename))
4838 Error(ERR_EXIT, "cannot open file '%s'", filename);
4840 LoadTapeFromFilename(filename);
4845 else if (strPrefix(command, "autotest ") ||
4846 strPrefix(command, "autoplay ") ||
4847 strPrefix(command, "autoffwd "))
4849 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4851 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4852 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4853 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4855 while (*str_ptr != '\0') /* continue parsing string */
4857 /* cut leading whitespace from string, replace it by string terminator */
4858 while (*str_ptr == ' ' || *str_ptr == '\t')
4861 if (*str_ptr == '\0') /* end of string reached */
4864 if (global.autoplay_leveldir == NULL) /* read level set string */
4866 global.autoplay_leveldir = str_ptr;
4867 global.autoplay_all = TRUE; /* default: play all tapes */
4869 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4870 global.autoplay_level[i] = FALSE;
4872 else /* read level number string */
4874 int level_nr = atoi(str_ptr); /* get level_nr value */
4876 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4877 global.autoplay_level[level_nr] = TRUE;
4879 global.autoplay_all = FALSE;
4882 /* advance string pointer to the next whitespace (or end of string) */
4883 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4887 else if (strPrefix(command, "convert "))
4889 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4890 char *str_ptr = strchr(str_copy, ' ');
4892 global.convert_leveldir = str_copy;
4893 global.convert_level_nr = -1;
4895 if (str_ptr != NULL) /* level number follows */
4897 *str_ptr++ = '\0'; /* terminate leveldir string */
4898 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4901 else if (strPrefix(command, "create images "))
4903 global.create_images_dir = getStringCopy(&command[14]);
4905 if (access(global.create_images_dir, W_OK) != 0)
4906 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4907 global.create_images_dir);
4909 else if (strPrefix(command, "create CE image "))
4911 CreateCustomElementImages(&command[16]);
4917 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4921 static void InitSetup()
4923 LoadSetup(); /* global setup info */
4925 /* set some options from setup file */
4927 if (setup.options.verbose)
4928 options.verbose = TRUE;
4931 static void InitGameInfo()
4933 game.restart_level = FALSE;
4936 static void InitPlayerInfo()
4940 /* choose default local player */
4941 local_player = &stored_player[0];
4943 for (i = 0; i < MAX_PLAYERS; i++)
4944 stored_player[i].connected = FALSE;
4946 local_player->connected = TRUE;
4949 static void InitArtworkInfo()
4954 static char *get_string_in_brackets(char *string)
4956 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4958 sprintf(string_in_brackets, "[%s]", string);
4960 return string_in_brackets;
4963 static char *get_level_id_suffix(int id_nr)
4965 char *id_suffix = checked_malloc(1 + 3 + 1);
4967 if (id_nr < 0 || id_nr > 999)
4970 sprintf(id_suffix, ".%03d", id_nr);
4975 static void InitArtworkConfig()
4977 static char *image_id_prefix[MAX_NUM_ELEMENTS +
4979 NUM_GLOBAL_ANIM_TOKENS + 1];
4980 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
4981 NUM_GLOBAL_ANIM_TOKENS + 1];
4982 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4983 static char *action_id_suffix[NUM_ACTIONS + 1];
4984 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4985 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4986 static char *level_id_suffix[MAX_LEVELS + 1];
4987 static char *dummy[1] = { NULL };
4988 static char *ignore_generic_tokens[] =
4994 static char **ignore_image_tokens;
4995 static char **ignore_sound_tokens;
4996 static char **ignore_music_tokens;
4997 int num_ignore_generic_tokens;
4998 int num_ignore_image_tokens;
4999 int num_ignore_sound_tokens;
5000 int num_ignore_music_tokens;
5003 /* dynamically determine list of generic tokens to be ignored */
5004 num_ignore_generic_tokens = 0;
5005 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5006 num_ignore_generic_tokens++;
5008 /* dynamically determine list of image tokens to be ignored */
5009 num_ignore_image_tokens = num_ignore_generic_tokens;
5010 for (i = 0; image_config_vars[i].token != NULL; i++)
5011 num_ignore_image_tokens++;
5012 ignore_image_tokens =
5013 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5014 for (i = 0; i < num_ignore_generic_tokens; i++)
5015 ignore_image_tokens[i] = ignore_generic_tokens[i];
5016 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5017 ignore_image_tokens[num_ignore_generic_tokens + i] =
5018 image_config_vars[i].token;
5019 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5021 /* dynamically determine list of sound tokens to be ignored */
5022 num_ignore_sound_tokens = num_ignore_generic_tokens;
5023 ignore_sound_tokens =
5024 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5025 for (i = 0; i < num_ignore_generic_tokens; i++)
5026 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5027 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5029 /* dynamically determine list of music tokens to be ignored */
5030 num_ignore_music_tokens = num_ignore_generic_tokens;
5031 ignore_music_tokens =
5032 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5033 for (i = 0; i < num_ignore_generic_tokens; i++)
5034 ignore_music_tokens[i] = ignore_generic_tokens[i];
5035 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5037 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5038 image_id_prefix[i] = element_info[i].token_name;
5039 for (i = 0; i < NUM_FONTS; i++)
5040 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5041 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5042 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5043 global_anim_info[i].token_name;
5044 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5046 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5047 sound_id_prefix[i] = element_info[i].token_name;
5048 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5049 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5050 get_string_in_brackets(element_info[i].class_name);
5051 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5052 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5053 global_anim_info[i].token_name;
5054 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5056 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5057 music_id_prefix[i] = music_prefix_info[i].prefix;
5058 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5060 for (i = 0; i < NUM_ACTIONS; i++)
5061 action_id_suffix[i] = element_action_info[i].suffix;
5062 action_id_suffix[NUM_ACTIONS] = NULL;
5064 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5065 direction_id_suffix[i] = element_direction_info[i].suffix;
5066 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5068 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5069 special_id_suffix[i] = special_suffix_info[i].suffix;
5070 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5072 for (i = 0; i < MAX_LEVELS; i++)
5073 level_id_suffix[i] = get_level_id_suffix(i);
5074 level_id_suffix[MAX_LEVELS] = NULL;
5076 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5077 image_id_prefix, action_id_suffix, direction_id_suffix,
5078 special_id_suffix, ignore_image_tokens);
5079 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5080 sound_id_prefix, action_id_suffix, dummy,
5081 special_id_suffix, ignore_sound_tokens);
5082 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5083 music_id_prefix, special_id_suffix, level_id_suffix,
5084 dummy, ignore_music_tokens);
5087 static void InitMixer()
5094 void InitGfxBuffers()
5096 static int win_xsize_last = -1;
5097 static int win_ysize_last = -1;
5099 /* create additional image buffers for double-buffering and cross-fading */
5101 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5103 /* may contain content for cross-fading -- only re-create if changed */
5104 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5105 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5107 win_xsize_last = WIN_XSIZE;
5108 win_ysize_last = WIN_YSIZE;
5111 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5112 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5113 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5114 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5115 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5117 /* initialize screen properties */
5118 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5119 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5121 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5122 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5123 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5124 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5125 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5126 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5128 /* required if door size definitions have changed */
5129 InitGraphicCompatibilityInfo_Doors();
5131 InitGfxBuffers_EM();
5132 InitGfxBuffers_SP();
5137 struct GraphicInfo *graphic_info_last = graphic_info;
5138 char *filename_font_initial = NULL;
5139 char *filename_anim_initial = NULL;
5140 Bitmap *bitmap_font_initial = NULL;
5144 /* determine settings for initial font (for displaying startup messages) */
5145 for (i = 0; image_config[i].token != NULL; i++)
5147 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5149 char font_token[128];
5152 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5153 len_font_token = strlen(font_token);
5155 if (strEqual(image_config[i].token, font_token))
5156 filename_font_initial = image_config[i].value;
5157 else if (strlen(image_config[i].token) > len_font_token &&
5158 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5160 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5161 font_initial[j].src_x = atoi(image_config[i].value);
5162 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5163 font_initial[j].src_y = atoi(image_config[i].value);
5164 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5165 font_initial[j].width = atoi(image_config[i].value);
5166 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5167 font_initial[j].height = atoi(image_config[i].value);
5172 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5174 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5175 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5178 if (filename_font_initial == NULL) /* should not happen */
5179 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5182 InitGfxCustomArtworkInfo();
5183 InitGfxOtherSettings();
5185 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5187 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5188 font_initial[j].bitmap = bitmap_font_initial;
5190 InitFontGraphicInfo();
5192 font_height = getFontHeight(FC_RED);
5194 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5195 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5196 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5199 DrawInitText("Loading graphics", 120, FC_GREEN);
5201 /* initialize settings for busy animation with default values */
5202 int parameter[NUM_GFX_ARGS];
5203 for (i = 0; i < NUM_GFX_ARGS; i++)
5204 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5205 image_config_suffix[i].token,
5206 image_config_suffix[i].type);
5208 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5209 int len_anim_token = strlen(anim_token);
5211 /* read settings for busy animation from default custom artwork config */
5212 char *gfx_config_filename = getPath3(options.graphics_directory,
5214 GRAPHICSINFO_FILENAME);
5216 if (fileExists(gfx_config_filename))
5218 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5220 if (setup_file_hash)
5222 char *filename = getHashEntry(setup_file_hash, anim_token);
5226 filename_anim_initial = getStringCopy(filename);
5228 for (j = 0; image_config_suffix[j].token != NULL; j++)
5230 int type = image_config_suffix[j].type;
5231 char *suffix = image_config_suffix[j].token;
5232 char *token = getStringCat2(anim_token, suffix);
5233 char *value = getHashEntry(setup_file_hash, token);
5235 checked_free(token);
5238 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5242 freeSetupFileHash(setup_file_hash);
5246 if (filename_anim_initial == NULL)
5248 /* read settings for busy animation from static default artwork config */
5249 for (i = 0; image_config[i].token != NULL; i++)
5251 if (strEqual(image_config[i].token, anim_token))
5252 filename_anim_initial = getStringCopy(image_config[i].value);
5253 else if (strlen(image_config[i].token) > len_anim_token &&
5254 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5256 for (j = 0; image_config_suffix[j].token != NULL; j++)
5258 if (strEqual(&image_config[i].token[len_anim_token],
5259 image_config_suffix[j].token))
5261 get_graphic_parameter_value(image_config[i].value,
5262 image_config_suffix[j].token,
5263 image_config_suffix[j].type);
5269 if (filename_anim_initial == NULL) /* should not happen */
5270 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5272 anim_initial.bitmaps =
5273 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5275 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5276 LoadCustomImage(filename_anim_initial);
5278 checked_free(filename_anim_initial);
5280 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5282 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5284 graphic_info = graphic_info_last;
5286 init.busy.width = anim_initial.width;
5287 init.busy.height = anim_initial.height;
5289 InitMenuDesignSettings_Static();
5291 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5292 InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5293 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5295 gfx.fade_border_source_status = global.border_status;
5296 gfx.fade_border_target_status = global.border_status;
5297 gfx.masked_border_bitmap_ptr = backbuffer;
5299 /* use copy of busy animation to prevent change while reloading artwork */
5303 void InitGfxBackground()
5305 fieldbuffer = bitmap_db_field;
5306 SetDrawtoField(DRAW_BACKBUFFER);
5308 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5310 redraw_mask = REDRAW_ALL;
5313 static void InitLevelInfo()
5315 LoadLevelInfo(); /* global level info */
5316 LoadLevelSetup_LastSeries(); /* last played series info */
5317 LoadLevelSetup_SeriesInfo(); /* last played level info */
5319 if (global.autoplay_leveldir &&
5320 global.autoplay_mode != AUTOPLAY_TEST)
5322 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5323 global.autoplay_leveldir);
5324 if (leveldir_current == NULL)
5325 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5329 static void InitLevelArtworkInfo()
5331 LoadLevelArtworkInfo();
5334 static void InitImages()
5336 print_timestamp_init("InitImages");
5339 printf("::: leveldir_current->identifier == '%s'\n",
5340 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5341 printf("::: leveldir_current->graphics_path == '%s'\n",
5342 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5343 printf("::: leveldir_current->graphics_set == '%s'\n",
5344 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5345 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5346 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5349 setLevelArtworkDir(artwork.gfx_first);
5352 printf("::: leveldir_current->identifier == '%s'\n",
5353 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5354 printf("::: leveldir_current->graphics_path == '%s'\n",
5355 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5356 printf("::: leveldir_current->graphics_set == '%s'\n",
5357 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5358 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5359 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5363 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5364 leveldir_current->identifier,
5365 artwork.gfx_current_identifier,
5366 artwork.gfx_current->identifier,
5367 leveldir_current->graphics_set,
5368 leveldir_current->graphics_path);
5371 UPDATE_BUSY_STATE();
5373 ReloadCustomImages();
5374 print_timestamp_time("ReloadCustomImages");
5376 UPDATE_BUSY_STATE();
5378 LoadCustomElementDescriptions();
5379 print_timestamp_time("LoadCustomElementDescriptions");
5381 UPDATE_BUSY_STATE();
5383 LoadMenuDesignSettings();
5384 print_timestamp_time("LoadMenuDesignSettings");
5386 UPDATE_BUSY_STATE();
5388 ReinitializeGraphics();
5389 print_timestamp_time("ReinitializeGraphics");
5391 UPDATE_BUSY_STATE();
5393 print_timestamp_done("InitImages");
5396 static void InitSound(char *identifier)
5398 print_timestamp_init("InitSound");
5400 if (identifier == NULL)
5401 identifier = artwork.snd_current->identifier;
5403 /* set artwork path to send it to the sound server process */
5404 setLevelArtworkDir(artwork.snd_first);
5406 InitReloadCustomSounds(identifier);
5407 print_timestamp_time("InitReloadCustomSounds");
5409 ReinitializeSounds();
5410 print_timestamp_time("ReinitializeSounds");
5412 print_timestamp_done("InitSound");
5415 static void InitMusic(char *identifier)
5417 print_timestamp_init("InitMusic");
5419 if (identifier == NULL)
5420 identifier = artwork.mus_current->identifier;
5422 /* set artwork path to send it to the sound server process */
5423 setLevelArtworkDir(artwork.mus_first);
5425 InitReloadCustomMusic(identifier);
5426 print_timestamp_time("InitReloadCustomMusic");
5428 ReinitializeMusic();
5429 print_timestamp_time("ReinitializeMusic");
5431 print_timestamp_done("InitMusic");
5434 static void InitArtworkDone()
5436 InitGlobalAnimations();
5439 void InitNetworkServer()
5441 #if defined(NETWORK_AVALIABLE)
5445 if (!options.network)
5448 #if defined(NETWORK_AVALIABLE)
5449 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5451 if (!ConnectToServer(options.server_host, options.server_port))
5452 Error(ERR_EXIT, "cannot connect to network game server");
5454 SendToServer_PlayerName(setup.player_name);
5455 SendToServer_ProtocolVersion();
5458 SendToServer_NrWanted(nr_wanted);
5462 static boolean CheckArtworkConfigForCustomElements(char *filename)
5464 SetupFileHash *setup_file_hash;
5465 boolean redefined_ce_found = FALSE;
5467 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5469 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5471 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5473 char *token = HASH_ITERATION_TOKEN(itr);
5475 if (strPrefix(token, "custom_"))
5477 redefined_ce_found = TRUE;
5482 END_HASH_ITERATION(setup_file_hash, itr)
5484 freeSetupFileHash(setup_file_hash);
5487 return redefined_ce_found;
5490 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5492 char *filename_base, *filename_local;
5493 boolean redefined_ce_found = FALSE;
5495 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5498 printf("::: leveldir_current->identifier == '%s'\n",
5499 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5500 printf("::: leveldir_current->graphics_path == '%s'\n",
5501 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5502 printf("::: leveldir_current->graphics_set == '%s'\n",
5503 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5504 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5505 leveldir_current == NULL ? "[NULL]" :
5506 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5509 /* first look for special artwork configured in level series config */
5510 filename_base = getCustomArtworkLevelConfigFilename(type);
5513 printf("::: filename_base == '%s'\n", filename_base);
5516 if (fileExists(filename_base))
5517 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5519 filename_local = getCustomArtworkConfigFilename(type);
5522 printf("::: filename_local == '%s'\n", filename_local);
5525 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5526 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5529 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5532 return redefined_ce_found;
5535 static void InitOverrideArtwork()
5537 boolean redefined_ce_found = FALSE;
5539 /* to check if this level set redefines any CEs, do not use overriding */
5540 gfx.override_level_graphics = FALSE;
5541 gfx.override_level_sounds = FALSE;
5542 gfx.override_level_music = FALSE;
5544 /* now check if this level set has definitions for custom elements */
5545 if (setup.override_level_graphics == AUTO ||
5546 setup.override_level_sounds == AUTO ||
5547 setup.override_level_music == AUTO)
5548 redefined_ce_found =
5549 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5550 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5551 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5554 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5557 if (redefined_ce_found)
5559 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5560 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5561 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5562 gfx.override_level_music = (setup.override_level_music == TRUE);
5566 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5567 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5568 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5569 gfx.override_level_music = (setup.override_level_music != FALSE);
5573 printf("::: => %d, %d, %d\n",
5574 gfx.override_level_graphics,
5575 gfx.override_level_sounds,
5576 gfx.override_level_music);
5580 static char *getNewArtworkIdentifier(int type)
5582 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5583 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5584 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5585 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5586 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5587 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5588 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5589 char *leveldir_identifier = leveldir_current->identifier;
5590 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5591 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5592 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5593 char *artwork_current_identifier;
5594 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5596 /* leveldir_current may be invalid (level group, parent link) */
5597 if (!validLevelSeries(leveldir_current))
5600 /* 1st step: determine artwork set to be activated in descending order:
5601 --------------------------------------------------------------------
5602 1. setup artwork (when configured to override everything else)
5603 2. artwork set configured in "levelinfo.conf" of current level set
5604 (artwork in level directory will have priority when loading later)
5605 3. artwork in level directory (stored in artwork sub-directory)
5606 4. setup artwork (currently configured in setup menu) */
5608 if (setup_override_artwork)
5609 artwork_current_identifier = setup_artwork_set;
5610 else if (leveldir_artwork_set != NULL)
5611 artwork_current_identifier = leveldir_artwork_set;
5612 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5613 artwork_current_identifier = leveldir_identifier;
5615 artwork_current_identifier = setup_artwork_set;
5618 /* 2nd step: check if it is really needed to reload artwork set
5619 ------------------------------------------------------------ */
5621 /* ---------- reload if level set and also artwork set has changed ------- */
5622 if (leveldir_current_identifier[type] != leveldir_identifier &&
5623 (last_has_level_artwork_set[type] || has_level_artwork_set))
5624 artwork_new_identifier = artwork_current_identifier;
5626 leveldir_current_identifier[type] = leveldir_identifier;
5627 last_has_level_artwork_set[type] = has_level_artwork_set;
5629 /* ---------- reload if "override artwork" setting has changed ----------- */
5630 if (last_override_level_artwork[type] != setup_override_artwork)
5631 artwork_new_identifier = artwork_current_identifier;
5633 last_override_level_artwork[type] = setup_override_artwork;
5635 /* ---------- reload if current artwork identifier has changed ----------- */
5636 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5637 artwork_current_identifier))
5638 artwork_new_identifier = artwork_current_identifier;
5640 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5642 /* ---------- do not reload directly after starting ---------------------- */
5643 if (!initialized[type])
5644 artwork_new_identifier = NULL;
5646 initialized[type] = TRUE;
5648 return artwork_new_identifier;
5651 void ReloadCustomArtwork(int force_reload)
5653 int last_game_status = game_status; /* save current game status */
5654 char *gfx_new_identifier;
5655 char *snd_new_identifier;
5656 char *mus_new_identifier;
5657 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5658 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5659 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5660 boolean reload_needed;
5662 InitOverrideArtwork();
5664 force_reload_gfx |= AdjustGraphicsForEMC();
5666 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5667 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5668 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5670 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5671 snd_new_identifier != NULL || force_reload_snd ||
5672 mus_new_identifier != NULL || force_reload_mus);
5677 print_timestamp_init("ReloadCustomArtwork");
5679 SetGameStatus(GAME_MODE_LOADING);
5681 FadeOut(REDRAW_ALL);
5683 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5684 print_timestamp_time("ClearRectangle");
5688 if (gfx_new_identifier != NULL || force_reload_gfx)
5691 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5692 artwork.gfx_current_identifier,
5694 artwork.gfx_current->identifier,
5695 leveldir_current->graphics_set);
5699 print_timestamp_time("InitImages");
5702 if (snd_new_identifier != NULL || force_reload_snd)
5704 InitSound(snd_new_identifier);
5705 print_timestamp_time("InitSound");
5708 if (mus_new_identifier != NULL || force_reload_mus)
5710 InitMusic(mus_new_identifier);
5711 print_timestamp_time("InitMusic");
5716 SetGameStatus(last_game_status); /* restore current game status */
5718 init_last = init; /* switch to new busy animation */
5720 FadeOut(REDRAW_ALL);
5722 RedrawGlobalBorder();
5724 /* force redraw of (open or closed) door graphics */
5725 SetDoorState(DOOR_OPEN_ALL);
5726 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5728 FadeSetEnterScreen();
5729 FadeSkipNextFadeOut();
5731 print_timestamp_done("ReloadCustomArtwork");
5733 LimitScreenUpdates(FALSE);
5736 void KeyboardAutoRepeatOffUnlessAutoplay()
5738 if (global.autoplay_leveldir == NULL)
5739 KeyboardAutoRepeatOff();
5742 void DisplayExitMessage(char *format, va_list ap)
5744 // check if draw buffer and fonts for exit message are already available
5745 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5748 int font_1 = FC_RED;
5749 int font_2 = FC_YELLOW;
5750 int font_3 = FC_BLUE;
5751 int font_width = getFontWidth(font_2);
5752 int font_height = getFontHeight(font_2);
5755 int sxsize = WIN_XSIZE - 2 * sx;
5756 int sysize = WIN_YSIZE - 2 * sy;
5757 int line_length = sxsize / font_width;
5758 int max_lines = sysize / font_height;
5759 int num_lines_printed;
5763 gfx.sxsize = sxsize;
5764 gfx.sysize = sysize;
5768 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5770 DrawTextSCentered(sy, font_1, "Fatal error:");
5771 sy += 3 * font_height;;
5774 DrawTextBufferVA(sx, sy, format, ap, font_2,
5775 line_length, line_length, max_lines,
5776 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5777 sy += (num_lines_printed + 3) * font_height;
5779 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5780 sy += 3 * font_height;
5783 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5784 line_length, line_length, max_lines,
5785 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5787 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5789 redraw_mask = REDRAW_ALL;
5791 /* force drawing exit message even if screen updates are currently limited */
5792 LimitScreenUpdates(FALSE);
5796 /* deactivate toons on error message screen */
5797 setup.toons = FALSE;
5799 WaitForEventToContinue();
5803 /* ========================================================================= */
5805 /* ========================================================================= */
5809 print_timestamp_init("OpenAll");
5811 SetGameStatus(GAME_MODE_LOADING);
5815 InitGlobal(); /* initialize some global variables */
5817 print_timestamp_time("[init global stuff]");
5821 print_timestamp_time("[init setup/config stuff (1)]");
5823 if (options.execute_command)
5824 Execute_Command(options.execute_command);
5826 if (options.serveronly)
5828 #if defined(PLATFORM_UNIX)
5829 NetworkServer(options.server_port, options.serveronly);
5831 Error(ERR_WARN, "networking only supported in Unix version");
5834 exit(0); /* never reached, server loops forever */
5838 print_timestamp_time("[init setup/config stuff (2)]");
5840 print_timestamp_time("[init setup/config stuff (3)]");
5841 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5842 print_timestamp_time("[init setup/config stuff (4)]");
5843 InitArtworkConfig(); /* needed before forking sound child process */
5844 print_timestamp_time("[init setup/config stuff (5)]");
5846 print_timestamp_time("[init setup/config stuff (6)]");
5848 InitRND(NEW_RANDOMIZE);
5849 InitSimpleRandom(NEW_RANDOMIZE);
5853 print_timestamp_time("[init setup/config stuff]");
5856 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5858 InitEventFilter(FilterEvents);
5860 print_timestamp_time("[init video stuff]");
5862 InitElementPropertiesStatic();
5863 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5864 InitElementPropertiesGfxElement();
5866 print_timestamp_time("[init element properties stuff]");
5870 print_timestamp_time("InitGfx");
5873 print_timestamp_time("InitLevelInfo");
5875 InitLevelArtworkInfo();
5876 print_timestamp_time("InitLevelArtworkInfo");
5878 InitOverrideArtwork(); /* needs to know current level directory */
5879 print_timestamp_time("InitOverrideArtwork");
5881 InitImages(); /* needs to know current level directory */
5882 print_timestamp_time("InitImages");
5884 InitSound(NULL); /* needs to know current level directory */
5885 print_timestamp_time("InitSound");
5887 InitMusic(NULL); /* needs to know current level directory */
5888 print_timestamp_time("InitMusic");
5892 InitGfxBackground();
5897 if (global.autoplay_leveldir)
5902 else if (global.convert_leveldir)
5907 else if (global.create_images_dir)
5909 CreateLevelSketchImages();
5913 SetGameStatus(GAME_MODE_MAIN);
5915 FadeSetEnterScreen();
5916 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5917 FadeSkipNextFadeOut();
5919 print_timestamp_time("[post-artwork]");
5921 print_timestamp_done("OpenAll");
5925 InitNetworkServer();
5928 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5930 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5931 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5932 #if defined(PLATFORM_ANDROID)
5933 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5934 SDL_AndroidGetInternalStoragePath());
5935 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5936 SDL_AndroidGetExternalStoragePath());
5937 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5938 (SDL_AndroidGetExternalStorageState() ==
5939 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5940 SDL_AndroidGetExternalStorageState() ==
5941 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5946 void CloseAllAndExit(int exit_value)
5951 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5958 #if defined(TARGET_SDL)
5959 #if defined(TARGET_SDL2)
5961 // set a flag to tell the network server thread to quit and wait for it
5962 // using SDL_WaitThread()
5964 if (network_server) /* terminate network server */
5965 SDL_KillThread(server_thread);
5969 CloseVideoDisplay();
5970 ClosePlatformDependentStuff();
5972 if (exit_value != 0)
5974 /* fall back to default level set (current set may have caused an error) */
5975 SaveLevelSetup_LastSeries_Deactivate();
5977 /* tell user where to find error log file which may contain more details */
5978 // (error notification now directly displayed on screen inside R'n'D
5979 // NotifyUserAboutErrorFile(); /* currently only works for Windows */