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[] =
185 IMG_EDITOR_ELEMENT_BORDER,
186 IMG_EDITOR_ELEMENT_BORDER_INPUT,
187 IMG_EDITOR_CASCADE_LIST,
188 IMG_EDITOR_CASCADE_LIST_ACTIVE,
191 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
192 int num_property_mappings = getImageListPropertyMappingSize();
195 print_timestamp_time("getImageListPropertyMapping/Size");
197 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
198 /* initialize normal images from static configuration */
199 for (i = 0; element_to_graphic[i].element > -1; i++)
200 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
201 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
203 /* initialize special images from static configuration */
204 for (i = 0; element_to_special_graphic[i].element > -1; i++)
205 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
206 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
208 /* initialize images from dynamic configuration (may be elements or other) */
209 for (i = 0; i < num_property_mappings; i++)
210 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
211 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
213 /* initialize special images from above list (non-element images) */
214 for (i = 0; special_graphics[i] > -1; i++)
215 InitElementSmallImagesScaledUp(special_graphics[i]);
216 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
218 print_timestamp_done("InitElementSmallImages");
221 void InitScaledImages()
225 /* scale normal images from static configuration, if not already scaled */
226 for (i = 0; i < NUM_IMAGE_FILES; i++)
227 ScaleImage(i, graphic_info[i].scale_up_factor);
230 void InitBitmapPointers()
232 int num_images = getImageListSize();
235 // standard size bitmap may have changed -- update default bitmap pointer
236 for (i = 0; i < num_images; i++)
237 if (graphic_info[i].bitmaps)
238 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
241 void InitImageTextures()
245 FreeAllImageTextures();
247 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
248 CreateImageTextures(i);
250 for (i = 0; i < MAX_NUM_TOONS; i++)
251 CreateImageTextures(IMG_TOON_1 + i);
253 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
255 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
257 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
259 int graphic = global_anim_info[i].graphic[j][k];
261 if (graphic == IMG_UNDEFINED)
264 CreateImageTextures(graphic);
271 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
272 void SetBitmaps_EM(Bitmap **em_bitmap)
274 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
275 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
280 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
281 void SetBitmaps_SP(Bitmap **sp_bitmap)
283 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
287 static int getFontBitmapID(int font_nr)
291 /* (special case: do not use special font for GAME_MODE_LOADING) */
292 if (game_status >= GAME_MODE_TITLE_INITIAL &&
293 game_status <= GAME_MODE_PSEUDO_PREVIEW)
294 special = game_status;
295 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
296 special = GFX_SPECIAL_ARG_MAIN;
299 return font_info[font_nr].special_bitmap_id[special];
304 static int getFontFromToken(char *token)
306 char *value = getHashEntry(font_token_hash, token);
311 /* if font not found, use reliable default value */
312 return FONT_INITIAL_1;
315 void InitFontGraphicInfo()
317 static struct FontBitmapInfo *font_bitmap_info = NULL;
318 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
319 int num_property_mappings = getImageListPropertyMappingSize();
320 int num_font_bitmaps = NUM_FONTS;
323 if (graphic_info == NULL) /* still at startup phase */
325 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
326 getFontBitmapID, getFontFromToken);
331 /* ---------- initialize font graphic definitions ---------- */
333 /* always start with reliable default values (normal font graphics) */
334 for (i = 0; i < NUM_FONTS; i++)
335 font_info[i].graphic = IMG_FONT_INITIAL_1;
337 /* initialize normal font/graphic mapping from static configuration */
338 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
340 int font_nr = font_to_graphic[i].font_nr;
341 int special = font_to_graphic[i].special;
342 int graphic = font_to_graphic[i].graphic;
347 font_info[font_nr].graphic = graphic;
350 /* always start with reliable default values (special font graphics) */
351 for (i = 0; i < NUM_FONTS; i++)
353 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
355 font_info[i].special_graphic[j] = font_info[i].graphic;
356 font_info[i].special_bitmap_id[j] = i;
360 /* initialize special font/graphic mapping from static configuration */
361 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
363 int font_nr = font_to_graphic[i].font_nr;
364 int special = font_to_graphic[i].special;
365 int graphic = font_to_graphic[i].graphic;
366 int base_graphic = font2baseimg(font_nr);
368 if (IS_SPECIAL_GFX_ARG(special))
370 boolean base_redefined =
371 getImageListEntryFromImageID(base_graphic)->redefined;
372 boolean special_redefined =
373 getImageListEntryFromImageID(graphic)->redefined;
374 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
376 /* if the base font ("font.title_1", for example) has been redefined,
377 but not the special font ("font.title_1.LEVELS", for example), do not
378 use an existing (in this case considered obsolete) special font
379 anymore, but use the automatically determined default font */
380 /* special case: cloned special fonts must be explicitly redefined,
381 but are not automatically redefined by redefining base font */
382 if (base_redefined && !special_redefined && !special_cloned)
385 font_info[font_nr].special_graphic[special] = graphic;
386 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
391 /* initialize special font/graphic mapping from dynamic configuration */
392 for (i = 0; i < num_property_mappings; i++)
394 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
395 int special = property_mapping[i].ext3_index;
396 int graphic = property_mapping[i].artwork_index;
401 if (IS_SPECIAL_GFX_ARG(special))
403 font_info[font_nr].special_graphic[special] = graphic;
404 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
409 /* correct special font/graphic mapping for cloned fonts for downwards
410 compatibility of PREVIEW fonts -- this is only needed for implicit
411 redefinition of special font by redefined base font, and only if other
412 fonts are cloned from this special font (like in the "Zelda" level set) */
413 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
415 int font_nr = font_to_graphic[i].font_nr;
416 int special = font_to_graphic[i].special;
417 int graphic = font_to_graphic[i].graphic;
419 if (IS_SPECIAL_GFX_ARG(special))
421 boolean special_redefined =
422 getImageListEntryFromImageID(graphic)->redefined;
423 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
425 if (special_cloned && !special_redefined)
429 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
431 int font_nr2 = font_to_graphic[j].font_nr;
432 int special2 = font_to_graphic[j].special;
433 int graphic2 = font_to_graphic[j].graphic;
435 if (IS_SPECIAL_GFX_ARG(special2) &&
436 graphic2 == graphic_info[graphic].clone_from)
438 font_info[font_nr].special_graphic[special] =
439 font_info[font_nr2].special_graphic[special2];
440 font_info[font_nr].special_bitmap_id[special] =
441 font_info[font_nr2].special_bitmap_id[special2];
448 /* reset non-redefined ".active" font graphics if normal font is redefined */
449 /* (this different treatment is needed because normal and active fonts are
450 independently defined ("active" is not a property of font definitions!) */
451 for (i = 0; i < NUM_FONTS; i++)
453 int font_nr_base = i;
454 int font_nr_active = FONT_ACTIVE(font_nr_base);
456 /* check only those fonts with exist as normal and ".active" variant */
457 if (font_nr_base != font_nr_active)
459 int base_graphic = font_info[font_nr_base].graphic;
460 int active_graphic = font_info[font_nr_active].graphic;
461 boolean base_redefined =
462 getImageListEntryFromImageID(base_graphic)->redefined;
463 boolean active_redefined =
464 getImageListEntryFromImageID(active_graphic)->redefined;
466 /* if the base font ("font.menu_1", for example) has been redefined,
467 but not the active font ("font.menu_1.active", for example), do not
468 use an existing (in this case considered obsolete) active font
469 anymore, but use the automatically determined default font */
470 if (base_redefined && !active_redefined)
471 font_info[font_nr_active].graphic = base_graphic;
473 /* now also check each "special" font (which may be the same as above) */
474 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
476 int base_graphic = font_info[font_nr_base].special_graphic[j];
477 int active_graphic = font_info[font_nr_active].special_graphic[j];
478 boolean base_redefined =
479 getImageListEntryFromImageID(base_graphic)->redefined;
480 boolean active_redefined =
481 getImageListEntryFromImageID(active_graphic)->redefined;
483 /* same as above, but check special graphic definitions, for example:
484 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
485 if (base_redefined && !active_redefined)
487 font_info[font_nr_active].special_graphic[j] =
488 font_info[font_nr_base].special_graphic[j];
489 font_info[font_nr_active].special_bitmap_id[j] =
490 font_info[font_nr_base].special_bitmap_id[j];
496 /* ---------- initialize font bitmap array ---------- */
498 if (font_bitmap_info != NULL)
499 FreeFontInfo(font_bitmap_info);
502 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
504 /* ---------- initialize font bitmap definitions ---------- */
506 for (i = 0; i < NUM_FONTS; i++)
508 if (i < NUM_INITIAL_FONTS)
510 font_bitmap_info[i] = font_initial[i];
514 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
516 int font_bitmap_id = font_info[i].special_bitmap_id[j];
517 int graphic = font_info[i].special_graphic[j];
519 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
520 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
522 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
523 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
526 /* copy font relevant information from graphics information */
527 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
528 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
529 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
530 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
531 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
533 font_bitmap_info[font_bitmap_id].draw_xoffset =
534 graphic_info[graphic].draw_xoffset;
535 font_bitmap_info[font_bitmap_id].draw_yoffset =
536 graphic_info[graphic].draw_yoffset;
538 font_bitmap_info[font_bitmap_id].num_chars =
539 graphic_info[graphic].anim_frames;
540 font_bitmap_info[font_bitmap_id].num_chars_per_line =
541 graphic_info[graphic].anim_frames_per_line;
545 InitFontInfo(font_bitmap_info, num_font_bitmaps,
546 getFontBitmapID, getFontFromToken);
549 void InitGlobalAnimGraphicInfo()
551 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
552 int num_property_mappings = getImageListPropertyMappingSize();
555 if (graphic_info == NULL) /* still at startup phase */
558 /* always start with reliable default values (no global animations) */
559 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
560 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
561 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
562 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
564 /* initialize global animation definitions from static configuration */
565 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
567 int j = GLOBAL_ANIM_ID_PART_BASE;
568 int k = GFX_SPECIAL_ARG_DEFAULT;
570 global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
573 /* initialize global animation definitions from dynamic configuration */
574 for (i = 0; i < num_property_mappings; i++)
576 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
577 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
578 int special = property_mapping[i].ext3_index;
579 int graphic = property_mapping[i].artwork_index;
581 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
584 /* set animation part to base part, if not specified */
585 if (!IS_GLOBAL_ANIM_PART(part_nr))
586 part_nr = GLOBAL_ANIM_ID_PART_BASE;
588 /* set animation screen to default, if not specified */
589 if (!IS_SPECIAL_GFX_ARG(special))
590 special = GFX_SPECIAL_ARG_DEFAULT;
592 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
596 printf("::: InitGlobalAnimGraphicInfo\n");
598 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
599 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
600 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
601 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
602 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
603 printf("::: - anim %d, part %d, mode %d => %d\n",
604 i, j, k, global_anim_info[i].graphic[j][k]);
608 void InitGlobalAnimSoundInfo()
610 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
611 int num_property_mappings = getSoundListPropertyMappingSize();
614 /* always start with reliable default values (no global animation sounds) */
615 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
616 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
617 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
618 global_anim_info[i].sound[j][k] = SND_UNDEFINED;
620 /* initialize global animation sound definitions from dynamic configuration */
621 for (i = 0; i < num_property_mappings; i++)
623 int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
624 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
625 int special = property_mapping[i].ext3_index;
626 int sound = property_mapping[i].artwork_index;
628 // sound uses control definition; map it to position of graphic (artwork)
629 anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
631 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
634 /* set animation part to base part, if not specified */
635 if (!IS_GLOBAL_ANIM_PART(part_nr))
636 part_nr = GLOBAL_ANIM_ID_PART_BASE;
638 /* set animation screen to default, if not specified */
639 if (!IS_SPECIAL_GFX_ARG(special))
640 special = GFX_SPECIAL_ARG_DEFAULT;
642 global_anim_info[anim_nr].sound[part_nr][special] = sound;
646 printf("::: InitGlobalAnimSoundInfo\n");
648 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
649 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
650 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
651 if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
652 printf("::: - anim %d, part %d, mode %d => %d\n",
653 i, j, k, global_anim_info[i].sound[j][k]);
657 void InitElementGraphicInfo()
659 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
660 int num_property_mappings = getImageListPropertyMappingSize();
663 if (graphic_info == NULL) /* still at startup phase */
666 /* set values to -1 to identify later as "uninitialized" values */
667 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
669 for (act = 0; act < NUM_ACTIONS; act++)
671 element_info[i].graphic[act] = -1;
672 element_info[i].crumbled[act] = -1;
674 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
676 element_info[i].direction_graphic[act][dir] = -1;
677 element_info[i].direction_crumbled[act][dir] = -1;
684 /* initialize normal element/graphic mapping from static configuration */
685 for (i = 0; element_to_graphic[i].element > -1; i++)
687 int element = element_to_graphic[i].element;
688 int action = element_to_graphic[i].action;
689 int direction = element_to_graphic[i].direction;
690 boolean crumbled = element_to_graphic[i].crumbled;
691 int graphic = element_to_graphic[i].graphic;
692 int base_graphic = el2baseimg(element);
694 if (graphic_info[graphic].bitmap == NULL)
697 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
700 boolean base_redefined =
701 getImageListEntryFromImageID(base_graphic)->redefined;
702 boolean act_dir_redefined =
703 getImageListEntryFromImageID(graphic)->redefined;
705 /* if the base graphic ("emerald", for example) has been redefined,
706 but not the action graphic ("emerald.falling", for example), do not
707 use an existing (in this case considered obsolete) action graphic
708 anymore, but use the automatically determined default graphic */
709 if (base_redefined && !act_dir_redefined)
714 action = ACTION_DEFAULT;
719 element_info[element].direction_crumbled[action][direction] = graphic;
721 element_info[element].crumbled[action] = graphic;
726 element_info[element].direction_graphic[action][direction] = graphic;
728 element_info[element].graphic[action] = graphic;
732 /* initialize normal element/graphic mapping from dynamic configuration */
733 for (i = 0; i < num_property_mappings; i++)
735 int element = property_mapping[i].base_index;
736 int action = property_mapping[i].ext1_index;
737 int direction = property_mapping[i].ext2_index;
738 int special = property_mapping[i].ext3_index;
739 int graphic = property_mapping[i].artwork_index;
740 boolean crumbled = FALSE;
742 if (special == GFX_SPECIAL_ARG_CRUMBLED)
748 if (graphic_info[graphic].bitmap == NULL)
751 if (element >= MAX_NUM_ELEMENTS || special != -1)
755 action = ACTION_DEFAULT;
760 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
761 element_info[element].direction_crumbled[action][dir] = -1;
764 element_info[element].direction_crumbled[action][direction] = graphic;
766 element_info[element].crumbled[action] = graphic;
771 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
772 element_info[element].direction_graphic[action][dir] = -1;
775 element_info[element].direction_graphic[action][direction] = graphic;
777 element_info[element].graphic[action] = graphic;
781 /* now copy all graphics that are defined to be cloned from other graphics */
782 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
784 int graphic = element_info[i].graphic[ACTION_DEFAULT];
785 int crumbled_like, diggable_like;
790 crumbled_like = graphic_info[graphic].crumbled_like;
791 diggable_like = graphic_info[graphic].diggable_like;
793 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
795 for (act = 0; act < NUM_ACTIONS; act++)
796 element_info[i].crumbled[act] =
797 element_info[crumbled_like].crumbled[act];
798 for (act = 0; act < NUM_ACTIONS; act++)
799 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
800 element_info[i].direction_crumbled[act][dir] =
801 element_info[crumbled_like].direction_crumbled[act][dir];
804 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
806 element_info[i].graphic[ACTION_DIGGING] =
807 element_info[diggable_like].graphic[ACTION_DIGGING];
808 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
809 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
810 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
814 /* set hardcoded definitions for some runtime elements without graphic */
815 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
817 /* set hardcoded definitions for some internal elements without graphic */
818 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
820 if (IS_EDITOR_CASCADE_INACTIVE(i))
821 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
822 else if (IS_EDITOR_CASCADE_ACTIVE(i))
823 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
826 /* now set all undefined/invalid graphics to -1 to set to default after it */
827 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
829 for (act = 0; act < NUM_ACTIONS; act++)
833 graphic = element_info[i].graphic[act];
834 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
835 element_info[i].graphic[act] = -1;
837 graphic = element_info[i].crumbled[act];
838 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
839 element_info[i].crumbled[act] = -1;
841 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
843 graphic = element_info[i].direction_graphic[act][dir];
844 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
845 element_info[i].direction_graphic[act][dir] = -1;
847 graphic = element_info[i].direction_crumbled[act][dir];
848 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
849 element_info[i].direction_crumbled[act][dir] = -1;
856 /* adjust graphics with 2nd tile for movement according to direction
857 (do this before correcting '-1' values to minimize calculations) */
858 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
860 for (act = 0; act < NUM_ACTIONS; act++)
862 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
864 int graphic = element_info[i].direction_graphic[act][dir];
865 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
867 if (act == ACTION_FALLING) /* special case */
868 graphic = element_info[i].graphic[act];
871 graphic_info[graphic].double_movement &&
872 graphic_info[graphic].swap_double_tiles != 0)
874 struct GraphicInfo *g = &graphic_info[graphic];
875 int src_x_front = g->src_x;
876 int src_y_front = g->src_y;
877 int src_x_back = g->src_x + g->offset2_x;
878 int src_y_back = g->src_y + g->offset2_y;
879 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
881 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
882 src_y_front < src_y_back);
883 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
884 boolean swap_movement_tiles_autodetected =
885 (!frames_are_ordered_diagonally &&
886 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
887 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
888 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
889 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
892 /* swap frontside and backside graphic tile coordinates, if needed */
893 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
895 /* get current (wrong) backside tile coordinates */
896 getFixedGraphicSourceExt(graphic, 0, &dummy,
897 &src_x_back, &src_y_back, TRUE);
899 /* set frontside tile coordinates to backside tile coordinates */
900 g->src_x = src_x_back;
901 g->src_y = src_y_back;
903 /* invert tile offset to point to new backside tile coordinates */
907 /* do not swap front and backside tiles again after correction */
908 g->swap_double_tiles = 0;
917 /* now set all '-1' values to element specific default values */
918 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
920 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
921 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
922 int default_direction_graphic[NUM_DIRECTIONS_FULL];
923 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
925 if (default_graphic == -1)
926 default_graphic = IMG_UNKNOWN;
928 if (default_crumbled == -1)
929 default_crumbled = default_graphic;
931 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
933 default_direction_graphic[dir] =
934 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
935 default_direction_crumbled[dir] =
936 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
938 if (default_direction_graphic[dir] == -1)
939 default_direction_graphic[dir] = default_graphic;
941 if (default_direction_crumbled[dir] == -1)
942 default_direction_crumbled[dir] = default_direction_graphic[dir];
945 for (act = 0; act < NUM_ACTIONS; act++)
947 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
948 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
949 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
950 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
951 act == ACTION_TURNING_FROM_RIGHT ||
952 act == ACTION_TURNING_FROM_UP ||
953 act == ACTION_TURNING_FROM_DOWN);
955 /* generic default action graphic (defined by "[default]" directive) */
956 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
957 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
958 int default_remove_graphic = IMG_EMPTY;
960 if (act_remove && default_action_graphic != -1)
961 default_remove_graphic = default_action_graphic;
963 /* look for special default action graphic (classic game specific) */
964 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
965 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
966 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
967 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
968 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
969 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
971 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
972 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
973 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
974 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
975 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
976 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
978 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
979 /* !!! make this better !!! */
980 if (i == EL_EMPTY_SPACE)
982 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
983 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
986 if (default_action_graphic == -1)
987 default_action_graphic = default_graphic;
989 if (default_action_crumbled == -1)
990 default_action_crumbled = default_action_graphic;
992 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
994 /* use action graphic as the default direction graphic, if undefined */
995 int default_action_direction_graphic = element_info[i].graphic[act];
996 int default_action_direction_crumbled = element_info[i].crumbled[act];
998 /* no graphic for current action -- use default direction graphic */
999 if (default_action_direction_graphic == -1)
1000 default_action_direction_graphic =
1001 (act_remove ? default_remove_graphic :
1003 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1004 default_action_graphic != default_graphic ?
1005 default_action_graphic :
1006 default_direction_graphic[dir]);
1008 if (element_info[i].direction_graphic[act][dir] == -1)
1009 element_info[i].direction_graphic[act][dir] =
1010 default_action_direction_graphic;
1012 if (default_action_direction_crumbled == -1)
1013 default_action_direction_crumbled =
1014 element_info[i].direction_graphic[act][dir];
1016 if (element_info[i].direction_crumbled[act][dir] == -1)
1017 element_info[i].direction_crumbled[act][dir] =
1018 default_action_direction_crumbled;
1021 /* no graphic for this specific action -- use default action graphic */
1022 if (element_info[i].graphic[act] == -1)
1023 element_info[i].graphic[act] =
1024 (act_remove ? default_remove_graphic :
1025 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1026 default_action_graphic);
1028 if (element_info[i].crumbled[act] == -1)
1029 element_info[i].crumbled[act] = element_info[i].graphic[act];
1033 UPDATE_BUSY_STATE();
1036 void InitElementSpecialGraphicInfo()
1038 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1039 int num_property_mappings = getImageListPropertyMappingSize();
1042 /* always start with reliable default values */
1043 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1044 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1045 element_info[i].special_graphic[j] =
1046 element_info[i].graphic[ACTION_DEFAULT];
1048 /* initialize special element/graphic mapping from static configuration */
1049 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1051 int element = element_to_special_graphic[i].element;
1052 int special = element_to_special_graphic[i].special;
1053 int graphic = element_to_special_graphic[i].graphic;
1054 int base_graphic = el2baseimg(element);
1055 boolean base_redefined =
1056 getImageListEntryFromImageID(base_graphic)->redefined;
1057 boolean special_redefined =
1058 getImageListEntryFromImageID(graphic)->redefined;
1060 /* if the base graphic ("emerald", for example) has been redefined,
1061 but not the special graphic ("emerald.EDITOR", for example), do not
1062 use an existing (in this case considered obsolete) special graphic
1063 anymore, but use the automatically created (down-scaled) graphic */
1064 if (base_redefined && !special_redefined)
1067 element_info[element].special_graphic[special] = graphic;
1070 /* initialize special element/graphic mapping from dynamic configuration */
1071 for (i = 0; i < num_property_mappings; i++)
1073 int element = property_mapping[i].base_index;
1074 int action = property_mapping[i].ext1_index;
1075 int direction = property_mapping[i].ext2_index;
1076 int special = property_mapping[i].ext3_index;
1077 int graphic = property_mapping[i].artwork_index;
1079 /* for action ".active", replace element with active element, if exists */
1080 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1082 element = ELEMENT_ACTIVE(element);
1086 if (element >= MAX_NUM_ELEMENTS)
1089 /* do not change special graphic if action or direction was specified */
1090 if (action != -1 || direction != -1)
1093 if (IS_SPECIAL_GFX_ARG(special))
1094 element_info[element].special_graphic[special] = graphic;
1097 /* now set all undefined/invalid graphics to default */
1098 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1099 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1100 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1101 element_info[i].special_graphic[j] =
1102 element_info[i].graphic[ACTION_DEFAULT];
1105 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1107 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1108 return get_parameter_value(value_raw, suffix, type);
1110 if (strEqual(value_raw, ARG_UNDEFINED))
1111 return ARG_UNDEFINED_VALUE;
1113 if (type == TYPE_ELEMENT)
1115 char *value = getHashEntry(element_token_hash, value_raw);
1119 Error(ERR_INFO_LINE, "-");
1120 Error(ERR_INFO, "warning: error found in config file:");
1121 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1122 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1123 Error(ERR_INFO, "custom graphic rejected for this element/action");
1124 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1125 Error(ERR_INFO_LINE, "-");
1128 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1130 else if (type == TYPE_GRAPHIC)
1132 char *value = getHashEntry(graphic_token_hash, value_raw);
1133 int fallback_graphic = IMG_CHAR_EXCLAM;
1137 Error(ERR_INFO_LINE, "-");
1138 Error(ERR_INFO, "warning: error found in config file:");
1139 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1140 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1141 Error(ERR_INFO, "custom graphic rejected for this element/action");
1142 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1143 Error(ERR_INFO_LINE, "-");
1146 return (value != NULL ? atoi(value) : fallback_graphic);
1152 static int get_scaled_graphic_width(int graphic)
1154 int original_width = getOriginalImageWidthFromImageID(graphic);
1155 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1157 return original_width * scale_up_factor;
1160 static int get_scaled_graphic_height(int graphic)
1162 int original_height = getOriginalImageHeightFromImageID(graphic);
1163 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1165 return original_height * scale_up_factor;
1168 static void set_graphic_parameters_ext(int graphic, int *parameter,
1169 Bitmap **src_bitmaps)
1171 struct GraphicInfo *g = &graphic_info[graphic];
1172 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1173 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1174 int anim_frames_per_line = 1;
1176 /* always start with reliable default values */
1177 g->src_image_width = 0;
1178 g->src_image_height = 0;
1181 g->width = TILEX; /* default for element graphics */
1182 g->height = TILEY; /* default for element graphics */
1183 g->offset_x = 0; /* one or both of these values ... */
1184 g->offset_y = 0; /* ... will be corrected later */
1185 g->offset2_x = 0; /* one or both of these values ... */
1186 g->offset2_y = 0; /* ... will be corrected later */
1187 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1188 g->crumbled_like = -1; /* do not use clone element */
1189 g->diggable_like = -1; /* do not use clone element */
1190 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1191 g->scale_up_factor = 1; /* default: no scaling up */
1192 g->tile_size = TILESIZE; /* default: standard tile size */
1193 g->clone_from = -1; /* do not use clone graphic */
1194 g->init_delay_fixed = 0;
1195 g->init_delay_random = 0;
1196 g->anim_delay_fixed = 0;
1197 g->anim_delay_random = 0;
1198 g->post_delay_fixed = 0;
1199 g->post_delay_random = 0;
1201 g->fade_mode = FADE_MODE_DEFAULT;
1205 g->align = ALIGN_CENTER; /* default for title screens */
1206 g->valign = VALIGN_MIDDLE; /* default for title screens */
1207 g->sort_priority = 0; /* default for title screens */
1209 g->style = STYLE_DEFAULT;
1211 g->bitmaps = src_bitmaps;
1212 g->bitmap = src_bitmap;
1214 /* optional zoom factor for scaling up the image to a larger size */
1215 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1216 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1217 if (g->scale_up_factor < 1)
1218 g->scale_up_factor = 1; /* no scaling */
1220 /* optional tile size for using non-standard image size */
1221 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1223 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1226 // CHECK: should tile sizes less than standard tile size be allowed?
1227 if (g->tile_size < TILESIZE)
1228 g->tile_size = TILESIZE; /* standard tile size */
1231 // when setting tile size, also set width and height accordingly
1232 g->width = g->tile_size;
1233 g->height = g->tile_size;
1236 if (g->use_image_size)
1238 /* set new default bitmap size (with scaling, but without small images) */
1239 g->width = get_scaled_graphic_width(graphic);
1240 g->height = get_scaled_graphic_height(graphic);
1243 /* optional width and height of each animation frame */
1244 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1245 g->width = parameter[GFX_ARG_WIDTH];
1246 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1247 g->height = parameter[GFX_ARG_HEIGHT];
1249 /* optional x and y tile position of animation frame sequence */
1250 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1251 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1252 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1253 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1255 /* optional x and y pixel position of animation frame sequence */
1256 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1257 g->src_x = parameter[GFX_ARG_X];
1258 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1259 g->src_y = parameter[GFX_ARG_Y];
1265 Error(ERR_INFO_LINE, "-");
1266 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1267 g->width, getTokenFromImageID(graphic), TILEX);
1268 Error(ERR_INFO_LINE, "-");
1270 g->width = TILEX; /* will be checked to be inside bitmap later */
1275 Error(ERR_INFO_LINE, "-");
1276 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1277 g->height, getTokenFromImageID(graphic), TILEY);
1278 Error(ERR_INFO_LINE, "-");
1280 g->height = TILEY; /* will be checked to be inside bitmap later */
1286 /* get final bitmap size (with scaling, but without small images) */
1287 int src_image_width = get_scaled_graphic_width(graphic);
1288 int src_image_height = get_scaled_graphic_height(graphic);
1290 if (src_image_width == 0 || src_image_height == 0)
1292 /* only happens when loaded outside artwork system (like "global.busy") */
1293 src_image_width = src_bitmap->width;
1294 src_image_height = src_bitmap->height;
1297 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1299 anim_frames_per_row = src_image_width / g->tile_size;
1300 anim_frames_per_col = src_image_height / g->tile_size;
1304 anim_frames_per_row = src_image_width / g->width;
1305 anim_frames_per_col = src_image_height / g->height;
1308 g->src_image_width = src_image_width;
1309 g->src_image_height = src_image_height;
1312 /* correct x or y offset dependent of vertical or horizontal frame order */
1313 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1315 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1316 parameter[GFX_ARG_OFFSET] : g->height);
1317 anim_frames_per_line = anim_frames_per_col;
1319 else /* frames are ordered horizontally */
1321 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1322 parameter[GFX_ARG_OFFSET] : g->width);
1323 anim_frames_per_line = anim_frames_per_row;
1326 /* optionally, the x and y offset of frames can be specified directly */
1327 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1328 g->offset_x = parameter[GFX_ARG_XOFFSET];
1329 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1330 g->offset_y = parameter[GFX_ARG_YOFFSET];
1332 /* optionally, moving animations may have separate start and end graphics */
1333 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1335 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1336 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1338 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1339 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1340 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1341 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1342 else /* frames are ordered horizontally */
1343 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1344 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1346 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1347 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1348 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1349 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1350 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1352 /* optionally, the second movement tile can be specified as start tile */
1353 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1354 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1356 /* automatically determine correct number of frames, if not defined */
1357 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1358 g->anim_frames = parameter[GFX_ARG_FRAMES];
1359 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1360 g->anim_frames = anim_frames_per_row;
1361 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1362 g->anim_frames = anim_frames_per_col;
1366 if (g->anim_frames == 0) /* frames must be at least 1 */
1369 g->anim_frames_per_line =
1370 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1371 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1373 g->anim_delay = parameter[GFX_ARG_DELAY];
1374 if (g->anim_delay == 0) /* delay must be at least 1 */
1377 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1379 /* automatically determine correct start frame, if not defined */
1380 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1381 g->anim_start_frame = 0;
1382 else if (g->anim_mode & ANIM_REVERSE)
1383 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1385 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1387 /* animation synchronized with global frame counter, not move position */
1388 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1390 /* optional element for cloning crumble graphics */
1391 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1392 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1394 /* optional element for cloning digging graphics */
1395 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1396 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1398 /* optional border size for "crumbling" diggable graphics */
1399 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1400 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1402 /* used for global animations and player "boring" and "sleeping" actions */
1403 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1404 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1405 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1406 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1407 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1408 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1409 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1410 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1411 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1412 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1413 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1414 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1416 /* used for toon animations and global animations */
1417 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1418 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1419 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1420 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1421 g->direction = parameter[GFX_ARG_DIRECTION];
1422 g->position = parameter[GFX_ARG_POSITION];
1423 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1424 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1426 /* this is only used for drawing font characters */
1427 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1428 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1430 /* this is only used for drawing envelope graphics */
1431 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1433 /* used for toon animations and global animations */
1434 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1435 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1437 /* optional graphic for cloning all graphics settings */
1438 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1439 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1441 /* optional settings for drawing title screens and title messages */
1442 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1443 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1444 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1445 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1446 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1447 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1448 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1449 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1450 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1451 g->align = parameter[GFX_ARG_ALIGN];
1452 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1453 g->valign = parameter[GFX_ARG_VALIGN];
1454 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1455 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1457 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1458 g->class = parameter[GFX_ARG_CLASS];
1459 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1460 g->style = parameter[GFX_ARG_STYLE];
1462 /* this is only used for drawing menu buttons and text */
1463 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1464 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1465 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1466 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1469 static void set_graphic_parameters(int graphic)
1471 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1472 char **parameter_raw = image->parameter;
1473 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1474 int parameter[NUM_GFX_ARGS];
1477 /* if fallback to default artwork is done, also use the default parameters */
1478 if (image->fallback_to_default)
1479 parameter_raw = image->default_parameter;
1481 /* get integer values from string parameters */
1482 for (i = 0; i < NUM_GFX_ARGS; i++)
1483 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1484 image_config_suffix[i].token,
1485 image_config_suffix[i].type);
1487 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1489 UPDATE_BUSY_STATE();
1492 static void set_cloned_graphic_parameters(int graphic)
1494 int fallback_graphic = IMG_CHAR_EXCLAM;
1495 int max_num_images = getImageListSize();
1496 int clone_graphic = graphic_info[graphic].clone_from;
1497 int num_references_followed = 1;
1499 while (graphic_info[clone_graphic].clone_from != -1 &&
1500 num_references_followed < max_num_images)
1502 clone_graphic = graphic_info[clone_graphic].clone_from;
1504 num_references_followed++;
1507 if (num_references_followed >= max_num_images)
1509 Error(ERR_INFO_LINE, "-");
1510 Error(ERR_INFO, "warning: error found in config file:");
1511 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1512 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1513 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1514 Error(ERR_INFO, "custom graphic rejected for this element/action");
1516 if (graphic == fallback_graphic)
1517 Error(ERR_EXIT, "no fallback graphic available");
1519 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1520 Error(ERR_INFO_LINE, "-");
1522 graphic_info[graphic] = graphic_info[fallback_graphic];
1526 graphic_info[graphic] = graphic_info[clone_graphic];
1527 graphic_info[graphic].clone_from = clone_graphic;
1531 static void InitGraphicInfo()
1533 int fallback_graphic = IMG_CHAR_EXCLAM;
1534 int num_images = getImageListSize();
1537 /* use image size as default values for width and height for these images */
1538 static int full_size_graphics[] =
1541 IMG_GLOBAL_BORDER_MAIN,
1542 IMG_GLOBAL_BORDER_SCORES,
1543 IMG_GLOBAL_BORDER_EDITOR,
1544 IMG_GLOBAL_BORDER_PLAYING,
1547 IMG_BACKGROUND_ENVELOPE_1,
1548 IMG_BACKGROUND_ENVELOPE_2,
1549 IMG_BACKGROUND_ENVELOPE_3,
1550 IMG_BACKGROUND_ENVELOPE_4,
1551 IMG_BACKGROUND_REQUEST,
1554 IMG_BACKGROUND_TITLE_INITIAL,
1555 IMG_BACKGROUND_TITLE,
1556 IMG_BACKGROUND_MAIN,
1557 IMG_BACKGROUND_LEVELS,
1558 IMG_BACKGROUND_LEVELNR,
1559 IMG_BACKGROUND_SCORES,
1560 IMG_BACKGROUND_EDITOR,
1561 IMG_BACKGROUND_INFO,
1562 IMG_BACKGROUND_INFO_ELEMENTS,
1563 IMG_BACKGROUND_INFO_MUSIC,
1564 IMG_BACKGROUND_INFO_CREDITS,
1565 IMG_BACKGROUND_INFO_PROGRAM,
1566 IMG_BACKGROUND_INFO_VERSION,
1567 IMG_BACKGROUND_INFO_LEVELSET,
1568 IMG_BACKGROUND_SETUP,
1569 IMG_BACKGROUND_PLAYING,
1570 IMG_BACKGROUND_DOOR,
1571 IMG_BACKGROUND_TAPE,
1572 IMG_BACKGROUND_PANEL,
1573 IMG_BACKGROUND_PALETTE,
1574 IMG_BACKGROUND_TOOLBOX,
1576 IMG_TITLESCREEN_INITIAL_1,
1577 IMG_TITLESCREEN_INITIAL_2,
1578 IMG_TITLESCREEN_INITIAL_3,
1579 IMG_TITLESCREEN_INITIAL_4,
1580 IMG_TITLESCREEN_INITIAL_5,
1587 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1588 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1589 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1590 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1591 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1592 IMG_BACKGROUND_TITLEMESSAGE_1,
1593 IMG_BACKGROUND_TITLEMESSAGE_2,
1594 IMG_BACKGROUND_TITLEMESSAGE_3,
1595 IMG_BACKGROUND_TITLEMESSAGE_4,
1596 IMG_BACKGROUND_TITLEMESSAGE_5,
1601 checked_free(graphic_info);
1603 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1605 /* initialize "use_image_size" flag with default value */
1606 for (i = 0; i < num_images; i++)
1607 graphic_info[i].use_image_size = FALSE;
1609 /* initialize "use_image_size" flag from static configuration above */
1610 for (i = 0; full_size_graphics[i] != -1; i++)
1611 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1613 /* first set all graphic paramaters ... */
1614 for (i = 0; i < num_images; i++)
1615 set_graphic_parameters(i);
1617 /* ... then copy these parameters for cloned graphics */
1618 for (i = 0; i < num_images; i++)
1619 if (graphic_info[i].clone_from != -1)
1620 set_cloned_graphic_parameters(i);
1622 for (i = 0; i < num_images; i++)
1627 int first_frame, last_frame;
1628 int src_bitmap_width, src_bitmap_height;
1630 /* now check if no animation frames are outside of the loaded image */
1632 if (graphic_info[i].bitmap == NULL)
1633 continue; /* skip check for optional images that are undefined */
1635 /* get image size (this can differ from the standard element tile size!) */
1636 width = graphic_info[i].width;
1637 height = graphic_info[i].height;
1639 /* get final bitmap size (with scaling, but without small images) */
1640 src_bitmap_width = graphic_info[i].src_image_width;
1641 src_bitmap_height = graphic_info[i].src_image_height;
1643 /* check if first animation frame is inside specified bitmap */
1646 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1648 /* this avoids calculating wrong start position for out-of-bounds frame */
1649 src_x = graphic_info[i].src_x;
1650 src_y = graphic_info[i].src_y;
1652 if (src_x < 0 || src_y < 0 ||
1653 src_x + width > src_bitmap_width ||
1654 src_y + height > src_bitmap_height)
1656 Error(ERR_INFO_LINE, "-");
1657 Error(ERR_INFO, "warning: error found in config file:");
1658 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1659 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1660 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1662 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1663 src_x, src_y, src_bitmap_width, src_bitmap_height);
1664 Error(ERR_INFO, "custom graphic rejected for this element/action");
1666 if (i == fallback_graphic)
1667 Error(ERR_EXIT, "no fallback graphic available");
1669 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1670 Error(ERR_INFO_LINE, "-");
1672 graphic_info[i] = graphic_info[fallback_graphic];
1675 /* check if last animation frame is inside specified bitmap */
1677 last_frame = graphic_info[i].anim_frames - 1;
1678 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1680 if (src_x < 0 || src_y < 0 ||
1681 src_x + width > src_bitmap_width ||
1682 src_y + height > src_bitmap_height)
1684 Error(ERR_INFO_LINE, "-");
1685 Error(ERR_INFO, "warning: error found in config file:");
1686 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1687 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1688 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1690 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1691 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1692 Error(ERR_INFO, "::: %d, %d", width, height);
1693 Error(ERR_INFO, "custom graphic rejected for this element/action");
1695 if (i == fallback_graphic)
1696 Error(ERR_EXIT, "no fallback graphic available");
1698 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1699 Error(ERR_INFO_LINE, "-");
1701 graphic_info[i] = graphic_info[fallback_graphic];
1706 static void InitGraphicCompatibilityInfo()
1708 struct FileInfo *fi_global_door =
1709 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1710 int num_images = getImageListSize();
1713 /* the following compatibility handling is needed for the following case:
1714 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1715 graphics mainly used for door and panel graphics, like editor, tape and
1716 in-game buttons with hard-coded bitmap positions and button sizes; as
1717 these graphics now have individual definitions, redefining "global.door"
1718 to change all these graphics at once like before does not work anymore
1719 (because all those individual definitions still have their default values);
1720 to solve this, remap all those individual definitions that are not
1721 redefined to the new bitmap of "global.door" if it was redefined */
1723 /* special compatibility handling if image "global.door" was redefined */
1724 if (fi_global_door->redefined)
1726 for (i = 0; i < num_images; i++)
1728 struct FileInfo *fi = getImageListEntryFromImageID(i);
1730 /* process only those images that still use the default settings */
1733 /* process all images which default to same image as "global.door" */
1734 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1736 // printf("::: special treatment needed for token '%s'\n", fi->token);
1738 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1744 InitGraphicCompatibilityInfo_Doors();
1747 static void InitElementSoundInfo()
1749 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1750 int num_property_mappings = getSoundListPropertyMappingSize();
1753 /* set values to -1 to identify later as "uninitialized" values */
1754 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1755 for (act = 0; act < NUM_ACTIONS; act++)
1756 element_info[i].sound[act] = -1;
1758 /* initialize element/sound mapping from static configuration */
1759 for (i = 0; element_to_sound[i].element > -1; i++)
1761 int element = element_to_sound[i].element;
1762 int action = element_to_sound[i].action;
1763 int sound = element_to_sound[i].sound;
1764 boolean is_class = element_to_sound[i].is_class;
1767 action = ACTION_DEFAULT;
1770 element_info[element].sound[action] = sound;
1772 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1773 if (strEqual(element_info[j].class_name,
1774 element_info[element].class_name))
1775 element_info[j].sound[action] = sound;
1778 /* initialize element class/sound mapping from dynamic configuration */
1779 for (i = 0; i < num_property_mappings; i++)
1781 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1782 int action = property_mapping[i].ext1_index;
1783 int sound = property_mapping[i].artwork_index;
1785 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1789 action = ACTION_DEFAULT;
1791 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1792 if (strEqual(element_info[j].class_name,
1793 element_info[element_class].class_name))
1794 element_info[j].sound[action] = sound;
1797 /* initialize element/sound mapping from dynamic configuration */
1798 for (i = 0; i < num_property_mappings; i++)
1800 int element = property_mapping[i].base_index;
1801 int action = property_mapping[i].ext1_index;
1802 int sound = property_mapping[i].artwork_index;
1804 if (element >= MAX_NUM_ELEMENTS)
1808 action = ACTION_DEFAULT;
1810 element_info[element].sound[action] = sound;
1813 /* now set all '-1' values to element specific default values */
1814 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1816 for (act = 0; act < NUM_ACTIONS; act++)
1818 /* generic default action sound (defined by "[default]" directive) */
1819 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1821 /* look for special default action sound (classic game specific) */
1822 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1823 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1824 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1825 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1826 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1827 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1829 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1830 /* !!! make this better !!! */
1831 if (i == EL_EMPTY_SPACE)
1832 default_action_sound = element_info[EL_DEFAULT].sound[act];
1834 /* no sound for this specific action -- use default action sound */
1835 if (element_info[i].sound[act] == -1)
1836 element_info[i].sound[act] = default_action_sound;
1840 /* copy sound settings to some elements that are only stored in level file
1841 in native R'n'D levels, but are used by game engine in native EM levels */
1842 for (i = 0; copy_properties[i][0] != -1; i++)
1843 for (j = 1; j <= 4; j++)
1844 for (act = 0; act < NUM_ACTIONS; act++)
1845 element_info[copy_properties[i][j]].sound[act] =
1846 element_info[copy_properties[i][0]].sound[act];
1849 static void InitGameModeSoundInfo()
1853 /* set values to -1 to identify later as "uninitialized" values */
1854 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1857 /* initialize gamemode/sound mapping from static configuration */
1858 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1860 int gamemode = gamemode_to_sound[i].gamemode;
1861 int sound = gamemode_to_sound[i].sound;
1864 gamemode = GAME_MODE_DEFAULT;
1866 menu.sound[gamemode] = sound;
1869 /* now set all '-1' values to levelset specific default values */
1870 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1871 if (menu.sound[i] == -1)
1872 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1875 static void set_sound_parameters(int sound, char **parameter_raw)
1877 int parameter[NUM_SND_ARGS];
1880 /* get integer values from string parameters */
1881 for (i = 0; i < NUM_SND_ARGS; i++)
1883 get_parameter_value(parameter_raw[i],
1884 sound_config_suffix[i].token,
1885 sound_config_suffix[i].type);
1887 /* explicit loop mode setting in configuration overrides default value */
1888 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1889 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1891 /* sound volume to change the original volume when loading the sound file */
1892 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1894 /* sound priority to give certain sounds a higher or lower priority */
1895 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1898 static void InitSoundInfo()
1900 int *sound_effect_properties;
1901 int num_sounds = getSoundListSize();
1904 checked_free(sound_info);
1906 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1907 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1909 /* initialize sound effect for all elements to "no sound" */
1910 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1911 for (j = 0; j < NUM_ACTIONS; j++)
1912 element_info[i].sound[j] = SND_UNDEFINED;
1914 for (i = 0; i < num_sounds; i++)
1916 struct FileInfo *sound = getSoundListEntry(i);
1917 int len_effect_text = strlen(sound->token);
1919 sound_effect_properties[i] = ACTION_OTHER;
1920 sound_info[i].loop = FALSE; /* default: play sound only once */
1922 /* determine all loop sounds and identify certain sound classes */
1924 for (j = 0; element_action_info[j].suffix; j++)
1926 int len_action_text = strlen(element_action_info[j].suffix);
1928 if (len_action_text < len_effect_text &&
1929 strEqual(&sound->token[len_effect_text - len_action_text],
1930 element_action_info[j].suffix))
1932 sound_effect_properties[i] = element_action_info[j].value;
1933 sound_info[i].loop = element_action_info[j].is_loop_sound;
1939 /* associate elements and some selected sound actions */
1941 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1943 if (element_info[j].class_name)
1945 int len_class_text = strlen(element_info[j].class_name);
1947 if (len_class_text + 1 < len_effect_text &&
1948 strncmp(sound->token,
1949 element_info[j].class_name, len_class_text) == 0 &&
1950 sound->token[len_class_text] == '.')
1952 int sound_action_value = sound_effect_properties[i];
1954 element_info[j].sound[sound_action_value] = i;
1959 set_sound_parameters(i, sound->parameter);
1962 free(sound_effect_properties);
1965 static void InitGameModeMusicInfo()
1967 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1968 int num_property_mappings = getMusicListPropertyMappingSize();
1969 int default_levelset_music = -1;
1972 /* set values to -1 to identify later as "uninitialized" values */
1973 for (i = 0; i < MAX_LEVELS; i++)
1974 levelset.music[i] = -1;
1975 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1978 /* initialize gamemode/music mapping from static configuration */
1979 for (i = 0; gamemode_to_music[i].music > -1; i++)
1981 int gamemode = gamemode_to_music[i].gamemode;
1982 int music = gamemode_to_music[i].music;
1985 gamemode = GAME_MODE_DEFAULT;
1987 menu.music[gamemode] = music;
1990 /* initialize gamemode/music mapping from dynamic configuration */
1991 for (i = 0; i < num_property_mappings; i++)
1993 int prefix = property_mapping[i].base_index;
1994 int gamemode = property_mapping[i].ext1_index;
1995 int level = property_mapping[i].ext2_index;
1996 int music = property_mapping[i].artwork_index;
1998 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2002 gamemode = GAME_MODE_DEFAULT;
2004 /* level specific music only allowed for in-game music */
2005 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2006 gamemode = GAME_MODE_PLAYING;
2011 default_levelset_music = music;
2014 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2015 levelset.music[level] = music;
2016 if (gamemode != GAME_MODE_PLAYING)
2017 menu.music[gamemode] = music;
2020 /* now set all '-1' values to menu specific default values */
2021 /* (undefined values of "levelset.music[]" might stay at "-1" to
2022 allow dynamic selection of music files from music directory!) */
2023 for (i = 0; i < MAX_LEVELS; i++)
2024 if (levelset.music[i] == -1)
2025 levelset.music[i] = default_levelset_music;
2026 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2027 if (menu.music[i] == -1)
2028 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2031 static void set_music_parameters(int music, char **parameter_raw)
2033 int parameter[NUM_MUS_ARGS];
2036 /* get integer values from string parameters */
2037 for (i = 0; i < NUM_MUS_ARGS; i++)
2039 get_parameter_value(parameter_raw[i],
2040 music_config_suffix[i].token,
2041 music_config_suffix[i].type);
2043 /* explicit loop mode setting in configuration overrides default value */
2044 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2045 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2048 static void InitMusicInfo()
2050 int num_music = getMusicListSize();
2053 checked_free(music_info);
2055 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2057 for (i = 0; i < num_music; i++)
2059 struct FileInfo *music = getMusicListEntry(i);
2060 int len_music_text = strlen(music->token);
2062 music_info[i].loop = TRUE; /* default: play music in loop mode */
2064 /* determine all loop music */
2066 for (j = 0; music_prefix_info[j].prefix; j++)
2068 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2070 if (len_prefix_text < len_music_text &&
2071 strncmp(music->token,
2072 music_prefix_info[j].prefix, len_prefix_text) == 0)
2074 music_info[i].loop = music_prefix_info[j].is_loop_music;
2080 set_music_parameters(i, music->parameter);
2084 static void ReinitializeGraphics()
2086 print_timestamp_init("ReinitializeGraphics");
2088 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2090 InitGraphicInfo(); /* graphic properties mapping */
2091 print_timestamp_time("InitGraphicInfo");
2092 InitElementGraphicInfo(); /* element game graphic mapping */
2093 print_timestamp_time("InitElementGraphicInfo");
2094 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2095 print_timestamp_time("InitElementSpecialGraphicInfo");
2097 InitElementSmallImages(); /* scale elements to all needed sizes */
2098 print_timestamp_time("InitElementSmallImages");
2099 InitScaledImages(); /* scale all other images, if needed */
2100 print_timestamp_time("InitScaledImages");
2101 InitBitmapPointers(); /* set standard size bitmap pointers */
2102 print_timestamp_time("InitBitmapPointers");
2103 InitFontGraphicInfo(); /* initialize text drawing functions */
2104 print_timestamp_time("InitFontGraphicInfo");
2105 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2106 print_timestamp_time("InitGlobalAnimGraphicInfo");
2108 InitImageTextures(); /* create textures for certain images */
2109 print_timestamp_time("InitImageTextures");
2111 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2112 print_timestamp_time("InitGraphicInfo_EM");
2114 InitGraphicCompatibilityInfo();
2115 print_timestamp_time("InitGraphicCompatibilityInfo");
2117 SetMainBackgroundImage(IMG_BACKGROUND);
2118 print_timestamp_time("SetMainBackgroundImage");
2119 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2120 print_timestamp_time("SetDoorBackgroundImage");
2123 print_timestamp_time("InitGadgets");
2125 print_timestamp_time("InitDoors");
2127 print_timestamp_done("ReinitializeGraphics");
2130 static void ReinitializeSounds()
2132 InitSoundInfo(); /* sound properties mapping */
2133 InitElementSoundInfo(); /* element game sound mapping */
2134 InitGameModeSoundInfo(); /* game mode sound mapping */
2135 InitGlobalAnimSoundInfo(); /* global animation sound settings */
2137 InitPlayLevelSound(); /* internal game sound settings */
2140 static void ReinitializeMusic()
2142 InitMusicInfo(); /* music properties mapping */
2143 InitGameModeMusicInfo(); /* game mode music mapping */
2146 static int get_special_property_bit(int element, int property_bit_nr)
2148 struct PropertyBitInfo
2154 static struct PropertyBitInfo pb_can_move_into_acid[] =
2156 /* the player may be able fall into acid when gravity is activated */
2161 { EL_SP_MURPHY, 0 },
2162 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2164 /* all elements that can move may be able to also move into acid */
2167 { EL_BUG_RIGHT, 1 },
2170 { EL_SPACESHIP, 2 },
2171 { EL_SPACESHIP_LEFT, 2 },
2172 { EL_SPACESHIP_RIGHT, 2 },
2173 { EL_SPACESHIP_UP, 2 },
2174 { EL_SPACESHIP_DOWN, 2 },
2175 { EL_BD_BUTTERFLY, 3 },
2176 { EL_BD_BUTTERFLY_LEFT, 3 },
2177 { EL_BD_BUTTERFLY_RIGHT, 3 },
2178 { EL_BD_BUTTERFLY_UP, 3 },
2179 { EL_BD_BUTTERFLY_DOWN, 3 },
2180 { EL_BD_FIREFLY, 4 },
2181 { EL_BD_FIREFLY_LEFT, 4 },
2182 { EL_BD_FIREFLY_RIGHT, 4 },
2183 { EL_BD_FIREFLY_UP, 4 },
2184 { EL_BD_FIREFLY_DOWN, 4 },
2186 { EL_YAMYAM_LEFT, 5 },
2187 { EL_YAMYAM_RIGHT, 5 },
2188 { EL_YAMYAM_UP, 5 },
2189 { EL_YAMYAM_DOWN, 5 },
2190 { EL_DARK_YAMYAM, 6 },
2193 { EL_PACMAN_LEFT, 8 },
2194 { EL_PACMAN_RIGHT, 8 },
2195 { EL_PACMAN_UP, 8 },
2196 { EL_PACMAN_DOWN, 8 },
2198 { EL_MOLE_LEFT, 9 },
2199 { EL_MOLE_RIGHT, 9 },
2201 { EL_MOLE_DOWN, 9 },
2205 { EL_SATELLITE, 13 },
2206 { EL_SP_SNIKSNAK, 14 },
2207 { EL_SP_ELECTRON, 15 },
2210 { EL_EMC_ANDROID, 18 },
2215 static struct PropertyBitInfo pb_dont_collide_with[] =
2217 { EL_SP_SNIKSNAK, 0 },
2218 { EL_SP_ELECTRON, 1 },
2226 struct PropertyBitInfo *pb_info;
2229 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2230 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2235 struct PropertyBitInfo *pb_info = NULL;
2238 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2239 if (pb_definition[i].bit_nr == property_bit_nr)
2240 pb_info = pb_definition[i].pb_info;
2242 if (pb_info == NULL)
2245 for (i = 0; pb_info[i].element != -1; i++)
2246 if (pb_info[i].element == element)
2247 return pb_info[i].bit_nr;
2252 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2253 boolean property_value)
2255 int bit_nr = get_special_property_bit(element, property_bit_nr);
2260 *bitfield |= (1 << bit_nr);
2262 *bitfield &= ~(1 << bit_nr);
2266 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2268 int bit_nr = get_special_property_bit(element, property_bit_nr);
2271 return ((*bitfield & (1 << bit_nr)) != 0);
2276 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2278 static int group_nr;
2279 static struct ElementGroupInfo *group;
2280 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2283 if (actual_group == NULL) /* not yet initialized */
2286 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2288 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2289 group_element - EL_GROUP_START + 1);
2291 /* replace element which caused too deep recursion by question mark */
2292 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2297 if (recursion_depth == 0) /* initialization */
2299 group = actual_group;
2300 group_nr = GROUP_NR(group_element);
2302 group->num_elements_resolved = 0;
2303 group->choice_pos = 0;
2305 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2306 element_info[i].in_group[group_nr] = FALSE;
2309 for (i = 0; i < actual_group->num_elements; i++)
2311 int element = actual_group->element[i];
2313 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2316 if (IS_GROUP_ELEMENT(element))
2317 ResolveGroupElementExt(element, recursion_depth + 1);
2320 group->element_resolved[group->num_elements_resolved++] = element;
2321 element_info[element].in_group[group_nr] = TRUE;
2326 void ResolveGroupElement(int group_element)
2328 ResolveGroupElementExt(group_element, 0);
2331 void InitElementPropertiesStatic()
2333 static boolean clipboard_elements_initialized = FALSE;
2335 static int ep_diggable[] =
2340 EL_SP_BUGGY_BASE_ACTIVATING,
2343 EL_INVISIBLE_SAND_ACTIVE,
2346 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2347 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2352 EL_SP_BUGGY_BASE_ACTIVE,
2359 static int ep_collectible_only[] =
2381 EL_DYNABOMB_INCREASE_NUMBER,
2382 EL_DYNABOMB_INCREASE_SIZE,
2383 EL_DYNABOMB_INCREASE_POWER,
2401 /* !!! handle separately !!! */
2402 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2408 static int ep_dont_run_into[] =
2410 /* same elements as in 'ep_dont_touch' */
2416 /* same elements as in 'ep_dont_collide_with' */
2428 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2433 EL_SP_BUGGY_BASE_ACTIVE,
2440 static int ep_dont_collide_with[] =
2442 /* same elements as in 'ep_dont_touch' */
2459 static int ep_dont_touch[] =
2469 static int ep_indestructible[] =
2473 EL_ACID_POOL_TOPLEFT,
2474 EL_ACID_POOL_TOPRIGHT,
2475 EL_ACID_POOL_BOTTOMLEFT,
2476 EL_ACID_POOL_BOTTOM,
2477 EL_ACID_POOL_BOTTOMRIGHT,
2478 EL_SP_HARDWARE_GRAY,
2479 EL_SP_HARDWARE_GREEN,
2480 EL_SP_HARDWARE_BLUE,
2482 EL_SP_HARDWARE_YELLOW,
2483 EL_SP_HARDWARE_BASE_1,
2484 EL_SP_HARDWARE_BASE_2,
2485 EL_SP_HARDWARE_BASE_3,
2486 EL_SP_HARDWARE_BASE_4,
2487 EL_SP_HARDWARE_BASE_5,
2488 EL_SP_HARDWARE_BASE_6,
2489 EL_INVISIBLE_STEELWALL,
2490 EL_INVISIBLE_STEELWALL_ACTIVE,
2491 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2492 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2493 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2494 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2495 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2496 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2497 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2498 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2499 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2500 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2501 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2502 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2504 EL_LIGHT_SWITCH_ACTIVE,
2505 EL_SIGN_EXCLAMATION,
2506 EL_SIGN_RADIOACTIVITY,
2513 EL_SIGN_ENTRY_FORBIDDEN,
2514 EL_SIGN_EMERGENCY_EXIT,
2522 EL_STEEL_EXIT_CLOSED,
2524 EL_STEEL_EXIT_OPENING,
2525 EL_STEEL_EXIT_CLOSING,
2526 EL_EM_STEEL_EXIT_CLOSED,
2527 EL_EM_STEEL_EXIT_OPEN,
2528 EL_EM_STEEL_EXIT_OPENING,
2529 EL_EM_STEEL_EXIT_CLOSING,
2530 EL_DC_STEELWALL_1_LEFT,
2531 EL_DC_STEELWALL_1_RIGHT,
2532 EL_DC_STEELWALL_1_TOP,
2533 EL_DC_STEELWALL_1_BOTTOM,
2534 EL_DC_STEELWALL_1_HORIZONTAL,
2535 EL_DC_STEELWALL_1_VERTICAL,
2536 EL_DC_STEELWALL_1_TOPLEFT,
2537 EL_DC_STEELWALL_1_TOPRIGHT,
2538 EL_DC_STEELWALL_1_BOTTOMLEFT,
2539 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2540 EL_DC_STEELWALL_1_TOPLEFT_2,
2541 EL_DC_STEELWALL_1_TOPRIGHT_2,
2542 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2543 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2544 EL_DC_STEELWALL_2_LEFT,
2545 EL_DC_STEELWALL_2_RIGHT,
2546 EL_DC_STEELWALL_2_TOP,
2547 EL_DC_STEELWALL_2_BOTTOM,
2548 EL_DC_STEELWALL_2_HORIZONTAL,
2549 EL_DC_STEELWALL_2_VERTICAL,
2550 EL_DC_STEELWALL_2_MIDDLE,
2551 EL_DC_STEELWALL_2_SINGLE,
2552 EL_STEELWALL_SLIPPERY,
2566 EL_GATE_1_GRAY_ACTIVE,
2567 EL_GATE_2_GRAY_ACTIVE,
2568 EL_GATE_3_GRAY_ACTIVE,
2569 EL_GATE_4_GRAY_ACTIVE,
2578 EL_EM_GATE_1_GRAY_ACTIVE,
2579 EL_EM_GATE_2_GRAY_ACTIVE,
2580 EL_EM_GATE_3_GRAY_ACTIVE,
2581 EL_EM_GATE_4_GRAY_ACTIVE,
2590 EL_EMC_GATE_5_GRAY_ACTIVE,
2591 EL_EMC_GATE_6_GRAY_ACTIVE,
2592 EL_EMC_GATE_7_GRAY_ACTIVE,
2593 EL_EMC_GATE_8_GRAY_ACTIVE,
2595 EL_DC_GATE_WHITE_GRAY,
2596 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2597 EL_DC_GATE_FAKE_GRAY,
2599 EL_SWITCHGATE_OPENING,
2600 EL_SWITCHGATE_CLOSED,
2601 EL_SWITCHGATE_CLOSING,
2602 EL_DC_SWITCHGATE_SWITCH_UP,
2603 EL_DC_SWITCHGATE_SWITCH_DOWN,
2605 EL_TIMEGATE_OPENING,
2607 EL_TIMEGATE_CLOSING,
2608 EL_DC_TIMEGATE_SWITCH,
2609 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2613 EL_TUBE_VERTICAL_LEFT,
2614 EL_TUBE_VERTICAL_RIGHT,
2615 EL_TUBE_HORIZONTAL_UP,
2616 EL_TUBE_HORIZONTAL_DOWN,
2621 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2622 EL_EXPANDABLE_STEELWALL_VERTICAL,
2623 EL_EXPANDABLE_STEELWALL_ANY,
2628 static int ep_slippery[] =
2642 EL_ROBOT_WHEEL_ACTIVE,
2648 EL_ACID_POOL_TOPLEFT,
2649 EL_ACID_POOL_TOPRIGHT,
2659 EL_STEELWALL_SLIPPERY,
2662 EL_EMC_WALL_SLIPPERY_1,
2663 EL_EMC_WALL_SLIPPERY_2,
2664 EL_EMC_WALL_SLIPPERY_3,
2665 EL_EMC_WALL_SLIPPERY_4,
2667 EL_EMC_MAGIC_BALL_ACTIVE,
2672 static int ep_can_change[] =
2677 static int ep_can_move[] =
2679 /* same elements as in 'pb_can_move_into_acid' */
2702 static int ep_can_fall[] =
2716 EL_QUICKSAND_FAST_FULL,
2718 EL_BD_MAGIC_WALL_FULL,
2719 EL_DC_MAGIC_WALL_FULL,
2733 static int ep_can_smash_player[] =
2759 static int ep_can_smash_enemies[] =
2768 static int ep_can_smash_everything[] =
2777 static int ep_explodes_by_fire[] =
2779 /* same elements as in 'ep_explodes_impact' */
2784 /* same elements as in 'ep_explodes_smashed' */
2794 EL_EM_DYNAMITE_ACTIVE,
2795 EL_DYNABOMB_PLAYER_1_ACTIVE,
2796 EL_DYNABOMB_PLAYER_2_ACTIVE,
2797 EL_DYNABOMB_PLAYER_3_ACTIVE,
2798 EL_DYNABOMB_PLAYER_4_ACTIVE,
2799 EL_DYNABOMB_INCREASE_NUMBER,
2800 EL_DYNABOMB_INCREASE_SIZE,
2801 EL_DYNABOMB_INCREASE_POWER,
2802 EL_SP_DISK_RED_ACTIVE,
2816 static int ep_explodes_smashed[] =
2818 /* same elements as in 'ep_explodes_impact' */
2832 static int ep_explodes_impact[] =
2841 static int ep_walkable_over[] =
2845 EL_SOKOBAN_FIELD_EMPTY,
2852 EL_EM_STEEL_EXIT_OPEN,
2853 EL_EM_STEEL_EXIT_OPENING,
2862 EL_GATE_1_GRAY_ACTIVE,
2863 EL_GATE_2_GRAY_ACTIVE,
2864 EL_GATE_3_GRAY_ACTIVE,
2865 EL_GATE_4_GRAY_ACTIVE,
2873 static int ep_walkable_inside[] =
2878 EL_TUBE_VERTICAL_LEFT,
2879 EL_TUBE_VERTICAL_RIGHT,
2880 EL_TUBE_HORIZONTAL_UP,
2881 EL_TUBE_HORIZONTAL_DOWN,
2890 static int ep_walkable_under[] =
2895 static int ep_passable_over[] =
2905 EL_EM_GATE_1_GRAY_ACTIVE,
2906 EL_EM_GATE_2_GRAY_ACTIVE,
2907 EL_EM_GATE_3_GRAY_ACTIVE,
2908 EL_EM_GATE_4_GRAY_ACTIVE,
2917 EL_EMC_GATE_5_GRAY_ACTIVE,
2918 EL_EMC_GATE_6_GRAY_ACTIVE,
2919 EL_EMC_GATE_7_GRAY_ACTIVE,
2920 EL_EMC_GATE_8_GRAY_ACTIVE,
2922 EL_DC_GATE_WHITE_GRAY,
2923 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2930 static int ep_passable_inside[] =
2936 EL_SP_PORT_HORIZONTAL,
2937 EL_SP_PORT_VERTICAL,
2939 EL_SP_GRAVITY_PORT_LEFT,
2940 EL_SP_GRAVITY_PORT_RIGHT,
2941 EL_SP_GRAVITY_PORT_UP,
2942 EL_SP_GRAVITY_PORT_DOWN,
2943 EL_SP_GRAVITY_ON_PORT_LEFT,
2944 EL_SP_GRAVITY_ON_PORT_RIGHT,
2945 EL_SP_GRAVITY_ON_PORT_UP,
2946 EL_SP_GRAVITY_ON_PORT_DOWN,
2947 EL_SP_GRAVITY_OFF_PORT_LEFT,
2948 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2949 EL_SP_GRAVITY_OFF_PORT_UP,
2950 EL_SP_GRAVITY_OFF_PORT_DOWN,
2955 static int ep_passable_under[] =
2960 static int ep_droppable[] =
2965 static int ep_explodes_1x1_old[] =
2970 static int ep_pushable[] =
2982 EL_SOKOBAN_FIELD_FULL,
2991 static int ep_explodes_cross_old[] =
2996 static int ep_protected[] =
2998 /* same elements as in 'ep_walkable_inside' */
3002 EL_TUBE_VERTICAL_LEFT,
3003 EL_TUBE_VERTICAL_RIGHT,
3004 EL_TUBE_HORIZONTAL_UP,
3005 EL_TUBE_HORIZONTAL_DOWN,
3011 /* same elements as in 'ep_passable_over' */
3020 EL_EM_GATE_1_GRAY_ACTIVE,
3021 EL_EM_GATE_2_GRAY_ACTIVE,
3022 EL_EM_GATE_3_GRAY_ACTIVE,
3023 EL_EM_GATE_4_GRAY_ACTIVE,
3032 EL_EMC_GATE_5_GRAY_ACTIVE,
3033 EL_EMC_GATE_6_GRAY_ACTIVE,
3034 EL_EMC_GATE_7_GRAY_ACTIVE,
3035 EL_EMC_GATE_8_GRAY_ACTIVE,
3037 EL_DC_GATE_WHITE_GRAY,
3038 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3042 /* same elements as in 'ep_passable_inside' */
3047 EL_SP_PORT_HORIZONTAL,
3048 EL_SP_PORT_VERTICAL,
3050 EL_SP_GRAVITY_PORT_LEFT,
3051 EL_SP_GRAVITY_PORT_RIGHT,
3052 EL_SP_GRAVITY_PORT_UP,
3053 EL_SP_GRAVITY_PORT_DOWN,
3054 EL_SP_GRAVITY_ON_PORT_LEFT,
3055 EL_SP_GRAVITY_ON_PORT_RIGHT,
3056 EL_SP_GRAVITY_ON_PORT_UP,
3057 EL_SP_GRAVITY_ON_PORT_DOWN,
3058 EL_SP_GRAVITY_OFF_PORT_LEFT,
3059 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3060 EL_SP_GRAVITY_OFF_PORT_UP,
3061 EL_SP_GRAVITY_OFF_PORT_DOWN,
3066 static int ep_throwable[] =
3071 static int ep_can_explode[] =
3073 /* same elements as in 'ep_explodes_impact' */
3078 /* same elements as in 'ep_explodes_smashed' */
3084 /* elements that can explode by explosion or by dragonfire */
3088 EL_EM_DYNAMITE_ACTIVE,
3089 EL_DYNABOMB_PLAYER_1_ACTIVE,
3090 EL_DYNABOMB_PLAYER_2_ACTIVE,
3091 EL_DYNABOMB_PLAYER_3_ACTIVE,
3092 EL_DYNABOMB_PLAYER_4_ACTIVE,
3093 EL_DYNABOMB_INCREASE_NUMBER,
3094 EL_DYNABOMB_INCREASE_SIZE,
3095 EL_DYNABOMB_INCREASE_POWER,
3096 EL_SP_DISK_RED_ACTIVE,
3104 /* elements that can explode only by explosion */
3110 static int ep_gravity_reachable[] =
3116 EL_INVISIBLE_SAND_ACTIVE,
3121 EL_SP_PORT_HORIZONTAL,
3122 EL_SP_PORT_VERTICAL,
3124 EL_SP_GRAVITY_PORT_LEFT,
3125 EL_SP_GRAVITY_PORT_RIGHT,
3126 EL_SP_GRAVITY_PORT_UP,
3127 EL_SP_GRAVITY_PORT_DOWN,
3128 EL_SP_GRAVITY_ON_PORT_LEFT,
3129 EL_SP_GRAVITY_ON_PORT_RIGHT,
3130 EL_SP_GRAVITY_ON_PORT_UP,
3131 EL_SP_GRAVITY_ON_PORT_DOWN,
3132 EL_SP_GRAVITY_OFF_PORT_LEFT,
3133 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3134 EL_SP_GRAVITY_OFF_PORT_UP,
3135 EL_SP_GRAVITY_OFF_PORT_DOWN,
3141 static int ep_player[] =
3148 EL_SOKOBAN_FIELD_PLAYER,
3154 static int ep_can_pass_magic_wall[] =
3168 static int ep_can_pass_dc_magic_wall[] =
3184 static int ep_switchable[] =
3188 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3189 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3190 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3191 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3192 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3193 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3194 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3195 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3196 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3197 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3198 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3199 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3200 EL_SWITCHGATE_SWITCH_UP,
3201 EL_SWITCHGATE_SWITCH_DOWN,
3202 EL_DC_SWITCHGATE_SWITCH_UP,
3203 EL_DC_SWITCHGATE_SWITCH_DOWN,
3205 EL_LIGHT_SWITCH_ACTIVE,
3207 EL_DC_TIMEGATE_SWITCH,
3208 EL_BALLOON_SWITCH_LEFT,
3209 EL_BALLOON_SWITCH_RIGHT,
3210 EL_BALLOON_SWITCH_UP,
3211 EL_BALLOON_SWITCH_DOWN,
3212 EL_BALLOON_SWITCH_ANY,
3213 EL_BALLOON_SWITCH_NONE,
3216 EL_EMC_MAGIC_BALL_SWITCH,
3217 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3222 static int ep_bd_element[] =
3256 static int ep_sp_element[] =
3258 /* should always be valid */
3261 /* standard classic Supaplex elements */
3268 EL_SP_HARDWARE_GRAY,
3276 EL_SP_GRAVITY_PORT_RIGHT,
3277 EL_SP_GRAVITY_PORT_DOWN,
3278 EL_SP_GRAVITY_PORT_LEFT,
3279 EL_SP_GRAVITY_PORT_UP,
3284 EL_SP_PORT_VERTICAL,
3285 EL_SP_PORT_HORIZONTAL,
3291 EL_SP_HARDWARE_BASE_1,
3292 EL_SP_HARDWARE_GREEN,
3293 EL_SP_HARDWARE_BLUE,
3295 EL_SP_HARDWARE_YELLOW,
3296 EL_SP_HARDWARE_BASE_2,
3297 EL_SP_HARDWARE_BASE_3,
3298 EL_SP_HARDWARE_BASE_4,
3299 EL_SP_HARDWARE_BASE_5,
3300 EL_SP_HARDWARE_BASE_6,
3304 /* additional elements that appeared in newer Supaplex levels */
3307 /* additional gravity port elements (not switching, but setting gravity) */
3308 EL_SP_GRAVITY_ON_PORT_LEFT,
3309 EL_SP_GRAVITY_ON_PORT_RIGHT,
3310 EL_SP_GRAVITY_ON_PORT_UP,
3311 EL_SP_GRAVITY_ON_PORT_DOWN,
3312 EL_SP_GRAVITY_OFF_PORT_LEFT,
3313 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3314 EL_SP_GRAVITY_OFF_PORT_UP,
3315 EL_SP_GRAVITY_OFF_PORT_DOWN,
3317 /* more than one Murphy in a level results in an inactive clone */
3320 /* runtime Supaplex elements */
3321 EL_SP_DISK_RED_ACTIVE,
3322 EL_SP_TERMINAL_ACTIVE,
3323 EL_SP_BUGGY_BASE_ACTIVATING,
3324 EL_SP_BUGGY_BASE_ACTIVE,
3331 static int ep_sb_element[] =
3336 EL_SOKOBAN_FIELD_EMPTY,
3337 EL_SOKOBAN_FIELD_FULL,
3338 EL_SOKOBAN_FIELD_PLAYER,
3343 EL_INVISIBLE_STEELWALL,
3348 static int ep_gem[] =
3360 static int ep_food_dark_yamyam[] =
3388 static int ep_food_penguin[] =
3402 static int ep_food_pig[] =
3414 static int ep_historic_wall[] =
3425 EL_GATE_1_GRAY_ACTIVE,
3426 EL_GATE_2_GRAY_ACTIVE,
3427 EL_GATE_3_GRAY_ACTIVE,
3428 EL_GATE_4_GRAY_ACTIVE,
3437 EL_EM_GATE_1_GRAY_ACTIVE,
3438 EL_EM_GATE_2_GRAY_ACTIVE,
3439 EL_EM_GATE_3_GRAY_ACTIVE,
3440 EL_EM_GATE_4_GRAY_ACTIVE,
3447 EL_EXPANDABLE_WALL_HORIZONTAL,
3448 EL_EXPANDABLE_WALL_VERTICAL,
3449 EL_EXPANDABLE_WALL_ANY,
3450 EL_EXPANDABLE_WALL_GROWING,
3451 EL_BD_EXPANDABLE_WALL,
3458 EL_SP_HARDWARE_GRAY,
3459 EL_SP_HARDWARE_GREEN,
3460 EL_SP_HARDWARE_BLUE,
3462 EL_SP_HARDWARE_YELLOW,
3463 EL_SP_HARDWARE_BASE_1,
3464 EL_SP_HARDWARE_BASE_2,
3465 EL_SP_HARDWARE_BASE_3,
3466 EL_SP_HARDWARE_BASE_4,
3467 EL_SP_HARDWARE_BASE_5,
3468 EL_SP_HARDWARE_BASE_6,
3470 EL_SP_TERMINAL_ACTIVE,
3473 EL_INVISIBLE_STEELWALL,
3474 EL_INVISIBLE_STEELWALL_ACTIVE,
3476 EL_INVISIBLE_WALL_ACTIVE,
3477 EL_STEELWALL_SLIPPERY,
3494 static int ep_historic_solid[] =
3498 EL_EXPANDABLE_WALL_HORIZONTAL,
3499 EL_EXPANDABLE_WALL_VERTICAL,
3500 EL_EXPANDABLE_WALL_ANY,
3501 EL_BD_EXPANDABLE_WALL,
3514 EL_QUICKSAND_FILLING,
3515 EL_QUICKSAND_EMPTYING,
3517 EL_MAGIC_WALL_ACTIVE,
3518 EL_MAGIC_WALL_EMPTYING,
3519 EL_MAGIC_WALL_FILLING,
3523 EL_BD_MAGIC_WALL_ACTIVE,
3524 EL_BD_MAGIC_WALL_EMPTYING,
3525 EL_BD_MAGIC_WALL_FULL,
3526 EL_BD_MAGIC_WALL_FILLING,
3527 EL_BD_MAGIC_WALL_DEAD,
3536 EL_SP_TERMINAL_ACTIVE,
3540 EL_INVISIBLE_WALL_ACTIVE,
3541 EL_SWITCHGATE_SWITCH_UP,
3542 EL_SWITCHGATE_SWITCH_DOWN,
3543 EL_DC_SWITCHGATE_SWITCH_UP,
3544 EL_DC_SWITCHGATE_SWITCH_DOWN,
3546 EL_TIMEGATE_SWITCH_ACTIVE,
3547 EL_DC_TIMEGATE_SWITCH,
3548 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3560 /* the following elements are a direct copy of "indestructible" elements,
3561 except "EL_ACID", which is "indestructible", but not "solid"! */
3566 EL_ACID_POOL_TOPLEFT,
3567 EL_ACID_POOL_TOPRIGHT,
3568 EL_ACID_POOL_BOTTOMLEFT,
3569 EL_ACID_POOL_BOTTOM,
3570 EL_ACID_POOL_BOTTOMRIGHT,
3571 EL_SP_HARDWARE_GRAY,
3572 EL_SP_HARDWARE_GREEN,
3573 EL_SP_HARDWARE_BLUE,
3575 EL_SP_HARDWARE_YELLOW,
3576 EL_SP_HARDWARE_BASE_1,
3577 EL_SP_HARDWARE_BASE_2,
3578 EL_SP_HARDWARE_BASE_3,
3579 EL_SP_HARDWARE_BASE_4,
3580 EL_SP_HARDWARE_BASE_5,
3581 EL_SP_HARDWARE_BASE_6,
3582 EL_INVISIBLE_STEELWALL,
3583 EL_INVISIBLE_STEELWALL_ACTIVE,
3584 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3585 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3586 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3587 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3588 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3589 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3590 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3591 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3592 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3593 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3594 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3595 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3597 EL_LIGHT_SWITCH_ACTIVE,
3598 EL_SIGN_EXCLAMATION,
3599 EL_SIGN_RADIOACTIVITY,
3606 EL_SIGN_ENTRY_FORBIDDEN,
3607 EL_SIGN_EMERGENCY_EXIT,
3615 EL_STEEL_EXIT_CLOSED,
3617 EL_DC_STEELWALL_1_LEFT,
3618 EL_DC_STEELWALL_1_RIGHT,
3619 EL_DC_STEELWALL_1_TOP,
3620 EL_DC_STEELWALL_1_BOTTOM,
3621 EL_DC_STEELWALL_1_HORIZONTAL,
3622 EL_DC_STEELWALL_1_VERTICAL,
3623 EL_DC_STEELWALL_1_TOPLEFT,
3624 EL_DC_STEELWALL_1_TOPRIGHT,
3625 EL_DC_STEELWALL_1_BOTTOMLEFT,
3626 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3627 EL_DC_STEELWALL_1_TOPLEFT_2,
3628 EL_DC_STEELWALL_1_TOPRIGHT_2,
3629 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3630 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3631 EL_DC_STEELWALL_2_LEFT,
3632 EL_DC_STEELWALL_2_RIGHT,
3633 EL_DC_STEELWALL_2_TOP,
3634 EL_DC_STEELWALL_2_BOTTOM,
3635 EL_DC_STEELWALL_2_HORIZONTAL,
3636 EL_DC_STEELWALL_2_VERTICAL,
3637 EL_DC_STEELWALL_2_MIDDLE,
3638 EL_DC_STEELWALL_2_SINGLE,
3639 EL_STEELWALL_SLIPPERY,
3653 EL_GATE_1_GRAY_ACTIVE,
3654 EL_GATE_2_GRAY_ACTIVE,
3655 EL_GATE_3_GRAY_ACTIVE,
3656 EL_GATE_4_GRAY_ACTIVE,
3665 EL_EM_GATE_1_GRAY_ACTIVE,
3666 EL_EM_GATE_2_GRAY_ACTIVE,
3667 EL_EM_GATE_3_GRAY_ACTIVE,
3668 EL_EM_GATE_4_GRAY_ACTIVE,
3670 EL_SWITCHGATE_OPENING,
3671 EL_SWITCHGATE_CLOSED,
3672 EL_SWITCHGATE_CLOSING,
3674 EL_TIMEGATE_OPENING,
3676 EL_TIMEGATE_CLOSING,
3680 EL_TUBE_VERTICAL_LEFT,
3681 EL_TUBE_VERTICAL_RIGHT,
3682 EL_TUBE_HORIZONTAL_UP,
3683 EL_TUBE_HORIZONTAL_DOWN,
3692 static int ep_classic_enemy[] =
3709 static int ep_belt[] =
3711 EL_CONVEYOR_BELT_1_LEFT,
3712 EL_CONVEYOR_BELT_1_MIDDLE,
3713 EL_CONVEYOR_BELT_1_RIGHT,
3714 EL_CONVEYOR_BELT_2_LEFT,
3715 EL_CONVEYOR_BELT_2_MIDDLE,
3716 EL_CONVEYOR_BELT_2_RIGHT,
3717 EL_CONVEYOR_BELT_3_LEFT,
3718 EL_CONVEYOR_BELT_3_MIDDLE,
3719 EL_CONVEYOR_BELT_3_RIGHT,
3720 EL_CONVEYOR_BELT_4_LEFT,
3721 EL_CONVEYOR_BELT_4_MIDDLE,
3722 EL_CONVEYOR_BELT_4_RIGHT,
3727 static int ep_belt_active[] =
3729 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3730 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3731 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3732 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3733 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3734 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3735 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3736 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3737 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3738 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3739 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3740 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3745 static int ep_belt_switch[] =
3747 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3748 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3749 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3750 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3751 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3752 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3753 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3754 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3755 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3756 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3757 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3758 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3763 static int ep_tube[] =
3770 EL_TUBE_HORIZONTAL_UP,
3771 EL_TUBE_HORIZONTAL_DOWN,
3773 EL_TUBE_VERTICAL_LEFT,
3774 EL_TUBE_VERTICAL_RIGHT,
3780 static int ep_acid_pool[] =
3782 EL_ACID_POOL_TOPLEFT,
3783 EL_ACID_POOL_TOPRIGHT,
3784 EL_ACID_POOL_BOTTOMLEFT,
3785 EL_ACID_POOL_BOTTOM,
3786 EL_ACID_POOL_BOTTOMRIGHT,
3791 static int ep_keygate[] =
3801 EL_GATE_1_GRAY_ACTIVE,
3802 EL_GATE_2_GRAY_ACTIVE,
3803 EL_GATE_3_GRAY_ACTIVE,
3804 EL_GATE_4_GRAY_ACTIVE,
3813 EL_EM_GATE_1_GRAY_ACTIVE,
3814 EL_EM_GATE_2_GRAY_ACTIVE,
3815 EL_EM_GATE_3_GRAY_ACTIVE,
3816 EL_EM_GATE_4_GRAY_ACTIVE,
3825 EL_EMC_GATE_5_GRAY_ACTIVE,
3826 EL_EMC_GATE_6_GRAY_ACTIVE,
3827 EL_EMC_GATE_7_GRAY_ACTIVE,
3828 EL_EMC_GATE_8_GRAY_ACTIVE,
3830 EL_DC_GATE_WHITE_GRAY,
3831 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3836 static int ep_amoeboid[] =
3848 static int ep_amoebalive[] =
3859 static int ep_has_editor_content[] =
3865 EL_SOKOBAN_FIELD_PLAYER,
3882 static int ep_can_turn_each_move[] =
3884 /* !!! do something with this one !!! */
3888 static int ep_can_grow[] =
3902 static int ep_active_bomb[] =
3905 EL_EM_DYNAMITE_ACTIVE,
3906 EL_DYNABOMB_PLAYER_1_ACTIVE,
3907 EL_DYNABOMB_PLAYER_2_ACTIVE,
3908 EL_DYNABOMB_PLAYER_3_ACTIVE,
3909 EL_DYNABOMB_PLAYER_4_ACTIVE,
3910 EL_SP_DISK_RED_ACTIVE,
3915 static int ep_inactive[] =
3925 EL_QUICKSAND_FAST_EMPTY,
3948 EL_GATE_1_GRAY_ACTIVE,
3949 EL_GATE_2_GRAY_ACTIVE,
3950 EL_GATE_3_GRAY_ACTIVE,
3951 EL_GATE_4_GRAY_ACTIVE,
3960 EL_EM_GATE_1_GRAY_ACTIVE,
3961 EL_EM_GATE_2_GRAY_ACTIVE,
3962 EL_EM_GATE_3_GRAY_ACTIVE,
3963 EL_EM_GATE_4_GRAY_ACTIVE,
3972 EL_EMC_GATE_5_GRAY_ACTIVE,
3973 EL_EMC_GATE_6_GRAY_ACTIVE,
3974 EL_EMC_GATE_7_GRAY_ACTIVE,
3975 EL_EMC_GATE_8_GRAY_ACTIVE,
3977 EL_DC_GATE_WHITE_GRAY,
3978 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3979 EL_DC_GATE_FAKE_GRAY,
3982 EL_INVISIBLE_STEELWALL,
3990 EL_WALL_EMERALD_YELLOW,
3991 EL_DYNABOMB_INCREASE_NUMBER,
3992 EL_DYNABOMB_INCREASE_SIZE,
3993 EL_DYNABOMB_INCREASE_POWER,
3997 EL_SOKOBAN_FIELD_EMPTY,
3998 EL_SOKOBAN_FIELD_FULL,
3999 EL_WALL_EMERALD_RED,
4000 EL_WALL_EMERALD_PURPLE,
4001 EL_ACID_POOL_TOPLEFT,
4002 EL_ACID_POOL_TOPRIGHT,
4003 EL_ACID_POOL_BOTTOMLEFT,
4004 EL_ACID_POOL_BOTTOM,
4005 EL_ACID_POOL_BOTTOMRIGHT,
4009 EL_BD_MAGIC_WALL_DEAD,
4011 EL_DC_MAGIC_WALL_DEAD,
4012 EL_AMOEBA_TO_DIAMOND,
4020 EL_SP_GRAVITY_PORT_RIGHT,
4021 EL_SP_GRAVITY_PORT_DOWN,
4022 EL_SP_GRAVITY_PORT_LEFT,
4023 EL_SP_GRAVITY_PORT_UP,
4024 EL_SP_PORT_HORIZONTAL,
4025 EL_SP_PORT_VERTICAL,
4036 EL_SP_HARDWARE_GRAY,
4037 EL_SP_HARDWARE_GREEN,
4038 EL_SP_HARDWARE_BLUE,
4040 EL_SP_HARDWARE_YELLOW,
4041 EL_SP_HARDWARE_BASE_1,
4042 EL_SP_HARDWARE_BASE_2,
4043 EL_SP_HARDWARE_BASE_3,
4044 EL_SP_HARDWARE_BASE_4,
4045 EL_SP_HARDWARE_BASE_5,
4046 EL_SP_HARDWARE_BASE_6,
4047 EL_SP_GRAVITY_ON_PORT_LEFT,
4048 EL_SP_GRAVITY_ON_PORT_RIGHT,
4049 EL_SP_GRAVITY_ON_PORT_UP,
4050 EL_SP_GRAVITY_ON_PORT_DOWN,
4051 EL_SP_GRAVITY_OFF_PORT_LEFT,
4052 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4053 EL_SP_GRAVITY_OFF_PORT_UP,
4054 EL_SP_GRAVITY_OFF_PORT_DOWN,
4055 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4056 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4057 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4058 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4059 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4060 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4061 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4062 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4063 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4064 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4065 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4066 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4067 EL_SIGN_EXCLAMATION,
4068 EL_SIGN_RADIOACTIVITY,
4075 EL_SIGN_ENTRY_FORBIDDEN,
4076 EL_SIGN_EMERGENCY_EXIT,
4084 EL_DC_STEELWALL_1_LEFT,
4085 EL_DC_STEELWALL_1_RIGHT,
4086 EL_DC_STEELWALL_1_TOP,
4087 EL_DC_STEELWALL_1_BOTTOM,
4088 EL_DC_STEELWALL_1_HORIZONTAL,
4089 EL_DC_STEELWALL_1_VERTICAL,
4090 EL_DC_STEELWALL_1_TOPLEFT,
4091 EL_DC_STEELWALL_1_TOPRIGHT,
4092 EL_DC_STEELWALL_1_BOTTOMLEFT,
4093 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4094 EL_DC_STEELWALL_1_TOPLEFT_2,
4095 EL_DC_STEELWALL_1_TOPRIGHT_2,
4096 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4097 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4098 EL_DC_STEELWALL_2_LEFT,
4099 EL_DC_STEELWALL_2_RIGHT,
4100 EL_DC_STEELWALL_2_TOP,
4101 EL_DC_STEELWALL_2_BOTTOM,
4102 EL_DC_STEELWALL_2_HORIZONTAL,
4103 EL_DC_STEELWALL_2_VERTICAL,
4104 EL_DC_STEELWALL_2_MIDDLE,
4105 EL_DC_STEELWALL_2_SINGLE,
4106 EL_STEELWALL_SLIPPERY,
4111 EL_EMC_WALL_SLIPPERY_1,
4112 EL_EMC_WALL_SLIPPERY_2,
4113 EL_EMC_WALL_SLIPPERY_3,
4114 EL_EMC_WALL_SLIPPERY_4,
4135 static int ep_em_slippery_wall[] =
4140 static int ep_gfx_crumbled[] =
4151 static int ep_editor_cascade_active[] =
4153 EL_INTERNAL_CASCADE_BD_ACTIVE,
4154 EL_INTERNAL_CASCADE_EM_ACTIVE,
4155 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4156 EL_INTERNAL_CASCADE_RND_ACTIVE,
4157 EL_INTERNAL_CASCADE_SB_ACTIVE,
4158 EL_INTERNAL_CASCADE_SP_ACTIVE,
4159 EL_INTERNAL_CASCADE_DC_ACTIVE,
4160 EL_INTERNAL_CASCADE_DX_ACTIVE,
4161 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4162 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4163 EL_INTERNAL_CASCADE_CE_ACTIVE,
4164 EL_INTERNAL_CASCADE_GE_ACTIVE,
4165 EL_INTERNAL_CASCADE_REF_ACTIVE,
4166 EL_INTERNAL_CASCADE_USER_ACTIVE,
4167 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4172 static int ep_editor_cascade_inactive[] =
4174 EL_INTERNAL_CASCADE_BD,
4175 EL_INTERNAL_CASCADE_EM,
4176 EL_INTERNAL_CASCADE_EMC,
4177 EL_INTERNAL_CASCADE_RND,
4178 EL_INTERNAL_CASCADE_SB,
4179 EL_INTERNAL_CASCADE_SP,
4180 EL_INTERNAL_CASCADE_DC,
4181 EL_INTERNAL_CASCADE_DX,
4182 EL_INTERNAL_CASCADE_CHARS,
4183 EL_INTERNAL_CASCADE_STEEL_CHARS,
4184 EL_INTERNAL_CASCADE_CE,
4185 EL_INTERNAL_CASCADE_GE,
4186 EL_INTERNAL_CASCADE_REF,
4187 EL_INTERNAL_CASCADE_USER,
4188 EL_INTERNAL_CASCADE_DYNAMIC,
4193 static int ep_obsolete[] =
4197 EL_EM_KEY_1_FILE_OBSOLETE,
4198 EL_EM_KEY_2_FILE_OBSOLETE,
4199 EL_EM_KEY_3_FILE_OBSOLETE,
4200 EL_EM_KEY_4_FILE_OBSOLETE,
4201 EL_ENVELOPE_OBSOLETE,
4210 } element_properties[] =
4212 { ep_diggable, EP_DIGGABLE },
4213 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4214 { ep_dont_run_into, EP_DONT_RUN_INTO },
4215 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4216 { ep_dont_touch, EP_DONT_TOUCH },
4217 { ep_indestructible, EP_INDESTRUCTIBLE },
4218 { ep_slippery, EP_SLIPPERY },
4219 { ep_can_change, EP_CAN_CHANGE },
4220 { ep_can_move, EP_CAN_MOVE },
4221 { ep_can_fall, EP_CAN_FALL },
4222 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4223 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4224 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4225 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4226 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4227 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4228 { ep_walkable_over, EP_WALKABLE_OVER },
4229 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4230 { ep_walkable_under, EP_WALKABLE_UNDER },
4231 { ep_passable_over, EP_PASSABLE_OVER },
4232 { ep_passable_inside, EP_PASSABLE_INSIDE },
4233 { ep_passable_under, EP_PASSABLE_UNDER },
4234 { ep_droppable, EP_DROPPABLE },
4235 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4236 { ep_pushable, EP_PUSHABLE },
4237 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4238 { ep_protected, EP_PROTECTED },
4239 { ep_throwable, EP_THROWABLE },
4240 { ep_can_explode, EP_CAN_EXPLODE },
4241 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4243 { ep_player, EP_PLAYER },
4244 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4245 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4246 { ep_switchable, EP_SWITCHABLE },
4247 { ep_bd_element, EP_BD_ELEMENT },
4248 { ep_sp_element, EP_SP_ELEMENT },
4249 { ep_sb_element, EP_SB_ELEMENT },
4251 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4252 { ep_food_penguin, EP_FOOD_PENGUIN },
4253 { ep_food_pig, EP_FOOD_PIG },
4254 { ep_historic_wall, EP_HISTORIC_WALL },
4255 { ep_historic_solid, EP_HISTORIC_SOLID },
4256 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4257 { ep_belt, EP_BELT },
4258 { ep_belt_active, EP_BELT_ACTIVE },
4259 { ep_belt_switch, EP_BELT_SWITCH },
4260 { ep_tube, EP_TUBE },
4261 { ep_acid_pool, EP_ACID_POOL },
4262 { ep_keygate, EP_KEYGATE },
4263 { ep_amoeboid, EP_AMOEBOID },
4264 { ep_amoebalive, EP_AMOEBALIVE },
4265 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4266 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4267 { ep_can_grow, EP_CAN_GROW },
4268 { ep_active_bomb, EP_ACTIVE_BOMB },
4269 { ep_inactive, EP_INACTIVE },
4271 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4273 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4275 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4276 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4278 { ep_obsolete, EP_OBSOLETE },
4285 /* always start with reliable default values (element has no properties) */
4286 /* (but never initialize clipboard elements after the very first time) */
4287 /* (to be able to use clipboard elements between several levels) */
4288 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4289 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4290 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4291 SET_PROPERTY(i, j, FALSE);
4293 /* set all base element properties from above array definitions */
4294 for (i = 0; element_properties[i].elements != NULL; i++)
4295 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4296 SET_PROPERTY((element_properties[i].elements)[j],
4297 element_properties[i].property, TRUE);
4299 /* copy properties to some elements that are only stored in level file */
4300 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4301 for (j = 0; copy_properties[j][0] != -1; j++)
4302 if (HAS_PROPERTY(copy_properties[j][0], i))
4303 for (k = 1; k <= 4; k++)
4304 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4306 /* set static element properties that are not listed in array definitions */
4307 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4308 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4310 clipboard_elements_initialized = TRUE;
4313 void InitElementPropertiesEngine(int engine_version)
4315 static int no_wall_properties[] =
4318 EP_COLLECTIBLE_ONLY,
4320 EP_DONT_COLLIDE_WITH,
4323 EP_CAN_SMASH_PLAYER,
4324 EP_CAN_SMASH_ENEMIES,
4325 EP_CAN_SMASH_EVERYTHING,
4330 EP_FOOD_DARK_YAMYAM,
4346 /* important: after initialization in InitElementPropertiesStatic(), the
4347 elements are not again initialized to a default value; therefore all
4348 changes have to make sure that they leave the element with a defined
4349 property (which means that conditional property changes must be set to
4350 a reliable default value before) */
4352 /* resolve group elements */
4353 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4354 ResolveGroupElement(EL_GROUP_START + i);
4356 /* set all special, combined or engine dependent element properties */
4357 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4359 /* do not change (already initialized) clipboard elements here */
4360 if (IS_CLIPBOARD_ELEMENT(i))
4363 /* ---------- INACTIVE ------------------------------------------------- */
4364 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4365 i <= EL_CHAR_END) ||
4366 (i >= EL_STEEL_CHAR_START &&
4367 i <= EL_STEEL_CHAR_END)));
4369 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4370 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4371 IS_WALKABLE_INSIDE(i) ||
4372 IS_WALKABLE_UNDER(i)));
4374 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4375 IS_PASSABLE_INSIDE(i) ||
4376 IS_PASSABLE_UNDER(i)));
4378 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4379 IS_PASSABLE_OVER(i)));
4381 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4382 IS_PASSABLE_INSIDE(i)));
4384 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4385 IS_PASSABLE_UNDER(i)));
4387 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4390 /* ---------- COLLECTIBLE ---------------------------------------------- */
4391 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4395 /* ---------- SNAPPABLE ------------------------------------------------ */
4396 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4397 IS_COLLECTIBLE(i) ||
4401 /* ---------- WALL ----------------------------------------------------- */
4402 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4404 for (j = 0; no_wall_properties[j] != -1; j++)
4405 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4406 i >= EL_FIRST_RUNTIME_UNREAL)
4407 SET_PROPERTY(i, EP_WALL, FALSE);
4409 if (IS_HISTORIC_WALL(i))
4410 SET_PROPERTY(i, EP_WALL, TRUE);
4412 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4413 if (engine_version < VERSION_IDENT(2,2,0,0))
4414 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4416 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4418 !IS_COLLECTIBLE(i)));
4420 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4421 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4422 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4424 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4425 IS_INDESTRUCTIBLE(i)));
4427 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4429 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4430 else if (engine_version < VERSION_IDENT(2,2,0,0))
4431 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4433 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4437 if (IS_CUSTOM_ELEMENT(i))
4439 /* these are additional properties which are initially false when set */
4441 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4443 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4444 if (DONT_COLLIDE_WITH(i))
4445 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4447 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4448 if (CAN_SMASH_EVERYTHING(i))
4449 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4450 if (CAN_SMASH_ENEMIES(i))
4451 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4454 /* ---------- CAN_SMASH ------------------------------------------------ */
4455 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4456 CAN_SMASH_ENEMIES(i) ||
4457 CAN_SMASH_EVERYTHING(i)));
4459 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4460 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4461 EXPLODES_BY_FIRE(i)));
4463 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4464 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4465 EXPLODES_SMASHED(i)));
4467 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4468 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4469 EXPLODES_IMPACT(i)));
4471 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4472 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4474 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4475 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4476 i == EL_BLACK_ORB));
4478 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4479 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4481 IS_CUSTOM_ELEMENT(i)));
4483 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4484 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4485 i == EL_SP_ELECTRON));
4487 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4488 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4489 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4490 getMoveIntoAcidProperty(&level, i));
4492 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4493 if (MAYBE_DONT_COLLIDE_WITH(i))
4494 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4495 getDontCollideWithProperty(&level, i));
4497 /* ---------- SP_PORT -------------------------------------------------- */
4498 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4499 IS_PASSABLE_INSIDE(i)));
4501 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4502 for (j = 0; j < level.num_android_clone_elements; j++)
4503 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4505 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4507 /* ---------- CAN_CHANGE ----------------------------------------------- */
4508 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4509 for (j = 0; j < element_info[i].num_change_pages; j++)
4510 if (element_info[i].change_page[j].can_change)
4511 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4513 /* ---------- HAS_ACTION ----------------------------------------------- */
4514 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4515 for (j = 0; j < element_info[i].num_change_pages; j++)
4516 if (element_info[i].change_page[j].has_action)
4517 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4519 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4520 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4523 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4524 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4525 element_info[i].crumbled[ACTION_DEFAULT] !=
4526 element_info[i].graphic[ACTION_DEFAULT]);
4528 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4529 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4530 IS_EDITOR_CASCADE_INACTIVE(i)));
4533 /* dynamically adjust element properties according to game engine version */
4535 static int ep_em_slippery_wall[] =
4540 EL_EXPANDABLE_WALL_HORIZONTAL,
4541 EL_EXPANDABLE_WALL_VERTICAL,
4542 EL_EXPANDABLE_WALL_ANY,
4543 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4544 EL_EXPANDABLE_STEELWALL_VERTICAL,
4545 EL_EXPANDABLE_STEELWALL_ANY,
4546 EL_EXPANDABLE_STEELWALL_GROWING,
4550 static int ep_em_explodes_by_fire[] =
4553 EL_EM_DYNAMITE_ACTIVE,
4558 /* special EM style gems behaviour */
4559 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4560 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4561 level.em_slippery_gems);
4563 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4564 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4565 (level.em_slippery_gems &&
4566 engine_version > VERSION_IDENT(2,0,1,0)));
4568 /* special EM style explosion behaviour regarding chain reactions */
4569 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4570 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4571 level.em_explodes_by_fire);
4574 /* this is needed because some graphics depend on element properties */
4575 if (game_status == GAME_MODE_PLAYING)
4576 InitElementGraphicInfo();
4579 void InitElementPropertiesAfterLoading(int engine_version)
4583 /* set some other uninitialized values of custom elements in older levels */
4584 if (engine_version < VERSION_IDENT(3,1,0,0))
4586 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4588 int element = EL_CUSTOM_START + i;
4590 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4592 element_info[element].explosion_delay = 17;
4593 element_info[element].ignition_delay = 8;
4598 void InitElementPropertiesGfxElement()
4602 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4604 struct ElementInfo *ei = &element_info[i];
4606 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4610 static void InitGlobal()
4615 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4617 /* check if element_name_info entry defined for each element in "main.h" */
4618 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4619 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4621 element_info[i].token_name = element_name_info[i].token_name;
4622 element_info[i].class_name = element_name_info[i].class_name;
4623 element_info[i].editor_description= element_name_info[i].editor_description;
4626 /* create hash from image config list */
4627 image_config_hash = newSetupFileHash();
4628 for (i = 0; image_config[i].token != NULL; i++)
4629 setHashEntry(image_config_hash,
4630 image_config[i].token,
4631 image_config[i].value);
4633 /* create hash from element token list */
4634 element_token_hash = newSetupFileHash();
4635 for (i = 0; element_name_info[i].token_name != NULL; i++)
4636 setHashEntry(element_token_hash,
4637 element_name_info[i].token_name,
4640 /* create hash from graphic token list */
4641 graphic_token_hash = newSetupFileHash();
4642 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4643 if (strSuffix(image_config[i].value, ".png") ||
4644 strSuffix(image_config[i].value, ".pcx") ||
4645 strSuffix(image_config[i].value, ".wav") ||
4646 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4647 setHashEntry(graphic_token_hash,
4648 image_config[i].token,
4649 int2str(graphic++, 0));
4651 /* create hash from font token list */
4652 font_token_hash = newSetupFileHash();
4653 for (i = 0; font_info[i].token_name != NULL; i++)
4654 setHashEntry(font_token_hash,
4655 font_info[i].token_name,
4658 /* set default filenames for all cloned graphics in static configuration */
4659 for (i = 0; image_config[i].token != NULL; i++)
4661 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4663 char *token = image_config[i].token;
4664 char *token_clone_from = getStringCat2(token, ".clone_from");
4665 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4667 if (token_cloned != NULL)
4669 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4671 if (value_cloned != NULL)
4673 /* set default filename in static configuration */
4674 image_config[i].value = value_cloned;
4676 /* set default filename in image config hash */
4677 setHashEntry(image_config_hash, token, value_cloned);
4681 free(token_clone_from);
4685 /* always start with reliable default values (all elements) */
4686 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4687 ActiveElement[i] = i;
4689 /* now add all entries that have an active state (active elements) */
4690 for (i = 0; element_with_active_state[i].element != -1; i++)
4692 int element = element_with_active_state[i].element;
4693 int element_active = element_with_active_state[i].element_active;
4695 ActiveElement[element] = element_active;
4698 /* always start with reliable default values (all buttons) */
4699 for (i = 0; i < NUM_IMAGE_FILES; i++)
4700 ActiveButton[i] = i;
4702 /* now add all entries that have an active state (active buttons) */
4703 for (i = 0; button_with_active_state[i].button != -1; i++)
4705 int button = button_with_active_state[i].button;
4706 int button_active = button_with_active_state[i].button_active;
4708 ActiveButton[button] = button_active;
4711 /* always start with reliable default values (all fonts) */
4712 for (i = 0; i < NUM_FONTS; i++)
4715 /* now add all entries that have an active state (active fonts) */
4716 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4718 int font = font_with_active_state[i].font_nr;
4719 int font_active = font_with_active_state[i].font_nr_active;
4721 ActiveFont[font] = font_active;
4724 global.autoplay_leveldir = NULL;
4725 global.convert_leveldir = NULL;
4726 global.create_images_dir = NULL;
4728 global.frames_per_second = 0;
4730 global.border_status = GAME_MODE_LOADING;
4731 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4733 global.use_envelope_request = FALSE;
4736 void Execute_Command(char *command)
4740 if (strEqual(command, "print graphicsinfo.conf"))
4742 Print("# You can configure additional/alternative image files here.\n");
4743 Print("# (The entries below are default and therefore commented out.)\n");
4745 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4747 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4750 for (i = 0; image_config[i].token != NULL; i++)
4751 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4752 image_config[i].value));
4756 else if (strEqual(command, "print soundsinfo.conf"))
4758 Print("# You can configure additional/alternative sound files here.\n");
4759 Print("# (The entries below are default and therefore commented out.)\n");
4761 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4763 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4766 for (i = 0; sound_config[i].token != NULL; i++)
4767 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4768 sound_config[i].value));
4772 else if (strEqual(command, "print musicinfo.conf"))
4774 Print("# You can configure additional/alternative music files here.\n");
4775 Print("# (The entries below are default and therefore commented out.)\n");
4777 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4779 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4782 for (i = 0; music_config[i].token != NULL; i++)
4783 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4784 music_config[i].value));
4788 else if (strEqual(command, "print editorsetup.conf"))
4790 Print("# You can configure your personal editor element list here.\n");
4791 Print("# (The entries below are default and therefore commented out.)\n");
4794 /* this is needed to be able to check element list for cascade elements */
4795 InitElementPropertiesStatic();
4796 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4798 PrintEditorElementList();
4802 else if (strEqual(command, "print helpanim.conf"))
4804 Print("# You can configure different element help animations here.\n");
4805 Print("# (The entries below are default and therefore commented out.)\n");
4808 for (i = 0; helpanim_config[i].token != NULL; i++)
4810 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4811 helpanim_config[i].value));
4813 if (strEqual(helpanim_config[i].token, "end"))
4819 else if (strEqual(command, "print helptext.conf"))
4821 Print("# You can configure different element help text here.\n");
4822 Print("# (The entries below are default and therefore commented out.)\n");
4825 for (i = 0; helptext_config[i].token != NULL; i++)
4826 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4827 helptext_config[i].value));
4831 else if (strPrefix(command, "dump level "))
4833 char *filename = &command[11];
4835 if (!fileExists(filename))
4836 Error(ERR_EXIT, "cannot open file '%s'", filename);
4838 LoadLevelFromFilename(&level, filename);
4843 else if (strPrefix(command, "dump tape "))
4845 char *filename = &command[10];
4847 if (!fileExists(filename))
4848 Error(ERR_EXIT, "cannot open file '%s'", filename);
4850 LoadTapeFromFilename(filename);
4855 else if (strPrefix(command, "autotest ") ||
4856 strPrefix(command, "autoplay ") ||
4857 strPrefix(command, "autoffwd "))
4859 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4861 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4862 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4863 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4865 while (*str_ptr != '\0') /* continue parsing string */
4867 /* cut leading whitespace from string, replace it by string terminator */
4868 while (*str_ptr == ' ' || *str_ptr == '\t')
4871 if (*str_ptr == '\0') /* end of string reached */
4874 if (global.autoplay_leveldir == NULL) /* read level set string */
4876 global.autoplay_leveldir = str_ptr;
4877 global.autoplay_all = TRUE; /* default: play all tapes */
4879 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4880 global.autoplay_level[i] = FALSE;
4882 else /* read level number string */
4884 int level_nr = atoi(str_ptr); /* get level_nr value */
4886 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4887 global.autoplay_level[level_nr] = TRUE;
4889 global.autoplay_all = FALSE;
4892 /* advance string pointer to the next whitespace (or end of string) */
4893 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4897 else if (strPrefix(command, "convert "))
4899 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4900 char *str_ptr = strchr(str_copy, ' ');
4902 global.convert_leveldir = str_copy;
4903 global.convert_level_nr = -1;
4905 if (str_ptr != NULL) /* level number follows */
4907 *str_ptr++ = '\0'; /* terminate leveldir string */
4908 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4911 else if (strPrefix(command, "create images "))
4913 global.create_images_dir = getStringCopy(&command[14]);
4915 if (access(global.create_images_dir, W_OK) != 0)
4916 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4917 global.create_images_dir);
4919 else if (strPrefix(command, "create CE image "))
4921 CreateCustomElementImages(&command[16]);
4927 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4931 static void InitSetup()
4933 LoadSetup(); /* global setup info */
4935 /* set some options from setup file */
4937 if (setup.options.verbose)
4938 options.verbose = TRUE;
4941 static void InitGameInfo()
4943 game.restart_level = FALSE;
4946 static void InitPlayerInfo()
4950 /* choose default local player */
4951 local_player = &stored_player[0];
4953 for (i = 0; i < MAX_PLAYERS; i++)
4954 stored_player[i].connected = FALSE;
4956 local_player->connected = TRUE;
4959 static void InitArtworkInfo()
4964 static char *get_string_in_brackets(char *string)
4966 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4968 sprintf(string_in_brackets, "[%s]", string);
4970 return string_in_brackets;
4973 static char *get_level_id_suffix(int id_nr)
4975 char *id_suffix = checked_malloc(1 + 3 + 1);
4977 if (id_nr < 0 || id_nr > 999)
4980 sprintf(id_suffix, ".%03d", id_nr);
4985 static void InitArtworkConfig()
4987 static char *image_id_prefix[MAX_NUM_ELEMENTS +
4989 NUM_GLOBAL_ANIM_TOKENS + 1];
4990 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
4991 NUM_GLOBAL_ANIM_TOKENS + 1];
4992 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4993 static char *action_id_suffix[NUM_ACTIONS + 1];
4994 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4995 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4996 static char *level_id_suffix[MAX_LEVELS + 1];
4997 static char *dummy[1] = { NULL };
4998 static char *ignore_generic_tokens[] =
5004 static char **ignore_image_tokens;
5005 static char **ignore_sound_tokens;
5006 static char **ignore_music_tokens;
5007 int num_ignore_generic_tokens;
5008 int num_ignore_image_tokens;
5009 int num_ignore_sound_tokens;
5010 int num_ignore_music_tokens;
5013 /* dynamically determine list of generic tokens to be ignored */
5014 num_ignore_generic_tokens = 0;
5015 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5016 num_ignore_generic_tokens++;
5018 /* dynamically determine list of image tokens to be ignored */
5019 num_ignore_image_tokens = num_ignore_generic_tokens;
5020 for (i = 0; image_config_vars[i].token != NULL; i++)
5021 num_ignore_image_tokens++;
5022 ignore_image_tokens =
5023 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5024 for (i = 0; i < num_ignore_generic_tokens; i++)
5025 ignore_image_tokens[i] = ignore_generic_tokens[i];
5026 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5027 ignore_image_tokens[num_ignore_generic_tokens + i] =
5028 image_config_vars[i].token;
5029 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5031 /* dynamically determine list of sound tokens to be ignored */
5032 num_ignore_sound_tokens = num_ignore_generic_tokens;
5033 ignore_sound_tokens =
5034 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5035 for (i = 0; i < num_ignore_generic_tokens; i++)
5036 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5037 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5039 /* dynamically determine list of music tokens to be ignored */
5040 num_ignore_music_tokens = num_ignore_generic_tokens;
5041 ignore_music_tokens =
5042 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5043 for (i = 0; i < num_ignore_generic_tokens; i++)
5044 ignore_music_tokens[i] = ignore_generic_tokens[i];
5045 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5047 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5048 image_id_prefix[i] = element_info[i].token_name;
5049 for (i = 0; i < NUM_FONTS; i++)
5050 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5051 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5052 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5053 global_anim_info[i].token_name;
5054 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5056 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5057 sound_id_prefix[i] = element_info[i].token_name;
5058 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5059 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5060 get_string_in_brackets(element_info[i].class_name);
5061 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5062 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5063 global_anim_info[i].token_name;
5064 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5066 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5067 music_id_prefix[i] = music_prefix_info[i].prefix;
5068 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5070 for (i = 0; i < NUM_ACTIONS; i++)
5071 action_id_suffix[i] = element_action_info[i].suffix;
5072 action_id_suffix[NUM_ACTIONS] = NULL;
5074 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5075 direction_id_suffix[i] = element_direction_info[i].suffix;
5076 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5078 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5079 special_id_suffix[i] = special_suffix_info[i].suffix;
5080 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5082 for (i = 0; i < MAX_LEVELS; i++)
5083 level_id_suffix[i] = get_level_id_suffix(i);
5084 level_id_suffix[MAX_LEVELS] = NULL;
5086 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5087 image_id_prefix, action_id_suffix, direction_id_suffix,
5088 special_id_suffix, ignore_image_tokens);
5089 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5090 sound_id_prefix, action_id_suffix, dummy,
5091 special_id_suffix, ignore_sound_tokens);
5092 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5093 music_id_prefix, special_id_suffix, level_id_suffix,
5094 dummy, ignore_music_tokens);
5097 static void InitMixer()
5104 void InitGfxBuffers()
5106 static int win_xsize_last = -1;
5107 static int win_ysize_last = -1;
5109 /* create additional image buffers for double-buffering and cross-fading */
5111 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5113 /* may contain content for cross-fading -- only re-create if changed */
5114 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5115 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5117 win_xsize_last = WIN_XSIZE;
5118 win_ysize_last = WIN_YSIZE;
5121 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5122 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5123 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5124 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5126 /* initialize screen properties */
5127 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5128 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5130 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5131 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5132 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5133 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5134 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5135 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5137 /* required if door size definitions have changed */
5138 InitGraphicCompatibilityInfo_Doors();
5140 InitGfxBuffers_EM();
5141 InitGfxBuffers_SP();
5146 struct GraphicInfo *graphic_info_last = graphic_info;
5147 char *filename_font_initial = NULL;
5148 char *filename_anim_initial = NULL;
5149 Bitmap *bitmap_font_initial = NULL;
5153 /* determine settings for initial font (for displaying startup messages) */
5154 for (i = 0; image_config[i].token != NULL; i++)
5156 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5158 char font_token[128];
5161 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5162 len_font_token = strlen(font_token);
5164 if (strEqual(image_config[i].token, font_token))
5165 filename_font_initial = image_config[i].value;
5166 else if (strlen(image_config[i].token) > len_font_token &&
5167 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5169 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5170 font_initial[j].src_x = atoi(image_config[i].value);
5171 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5172 font_initial[j].src_y = atoi(image_config[i].value);
5173 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5174 font_initial[j].width = atoi(image_config[i].value);
5175 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5176 font_initial[j].height = atoi(image_config[i].value);
5181 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5183 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5184 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5187 if (filename_font_initial == NULL) /* should not happen */
5188 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5191 InitGfxCustomArtworkInfo();
5192 InitGfxOtherSettings();
5194 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5196 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5197 font_initial[j].bitmap = bitmap_font_initial;
5199 InitFontGraphicInfo();
5201 font_height = getFontHeight(FC_RED);
5203 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5204 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5205 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5208 DrawInitText("Loading graphics", 120, FC_GREEN);
5210 /* initialize settings for busy animation with default values */
5211 int parameter[NUM_GFX_ARGS];
5212 for (i = 0; i < NUM_GFX_ARGS; i++)
5213 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5214 image_config_suffix[i].token,
5215 image_config_suffix[i].type);
5217 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5218 int len_anim_token = strlen(anim_token);
5220 /* read settings for busy animation from default custom artwork config */
5221 char *gfx_config_filename = getPath3(options.graphics_directory,
5223 GRAPHICSINFO_FILENAME);
5225 if (fileExists(gfx_config_filename))
5227 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5229 if (setup_file_hash)
5231 char *filename = getHashEntry(setup_file_hash, anim_token);
5235 filename_anim_initial = getStringCopy(filename);
5237 for (j = 0; image_config_suffix[j].token != NULL; j++)
5239 int type = image_config_suffix[j].type;
5240 char *suffix = image_config_suffix[j].token;
5241 char *token = getStringCat2(anim_token, suffix);
5242 char *value = getHashEntry(setup_file_hash, token);
5244 checked_free(token);
5247 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5251 freeSetupFileHash(setup_file_hash);
5255 if (filename_anim_initial == NULL)
5257 /* read settings for busy animation from static default artwork config */
5258 for (i = 0; image_config[i].token != NULL; i++)
5260 if (strEqual(image_config[i].token, anim_token))
5261 filename_anim_initial = getStringCopy(image_config[i].value);
5262 else if (strlen(image_config[i].token) > len_anim_token &&
5263 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5265 for (j = 0; image_config_suffix[j].token != NULL; j++)
5267 if (strEqual(&image_config[i].token[len_anim_token],
5268 image_config_suffix[j].token))
5270 get_graphic_parameter_value(image_config[i].value,
5271 image_config_suffix[j].token,
5272 image_config_suffix[j].type);
5278 if (filename_anim_initial == NULL) /* should not happen */
5279 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5281 anim_initial.bitmaps =
5282 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5284 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5285 LoadCustomImage(filename_anim_initial);
5287 checked_free(filename_anim_initial);
5289 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5291 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5293 graphic_info = graphic_info_last;
5295 init.busy.width = anim_initial.width;
5296 init.busy.height = anim_initial.height;
5298 InitMenuDesignSettings_Static();
5300 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5301 InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5302 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5304 gfx.fade_border_source_status = global.border_status;
5305 gfx.fade_border_target_status = global.border_status;
5306 gfx.masked_border_bitmap_ptr = backbuffer;
5308 /* use copy of busy animation to prevent change while reloading artwork */
5312 void InitGfxBackground()
5314 fieldbuffer = bitmap_db_field;
5315 SetDrawtoField(DRAW_BACKBUFFER);
5317 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5319 redraw_mask = REDRAW_ALL;
5322 static void InitLevelInfo()
5324 LoadLevelInfo(); /* global level info */
5325 LoadLevelSetup_LastSeries(); /* last played series info */
5326 LoadLevelSetup_SeriesInfo(); /* last played level info */
5328 if (global.autoplay_leveldir &&
5329 global.autoplay_mode != AUTOPLAY_TEST)
5331 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5332 global.autoplay_leveldir);
5333 if (leveldir_current == NULL)
5334 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5338 static void InitLevelArtworkInfo()
5340 LoadLevelArtworkInfo();
5343 static void InitImages()
5345 print_timestamp_init("InitImages");
5348 printf("::: leveldir_current->identifier == '%s'\n",
5349 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5350 printf("::: leveldir_current->graphics_path == '%s'\n",
5351 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5352 printf("::: leveldir_current->graphics_set == '%s'\n",
5353 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5354 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5355 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5358 setLevelArtworkDir(artwork.gfx_first);
5361 printf("::: leveldir_current->identifier == '%s'\n",
5362 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5363 printf("::: leveldir_current->graphics_path == '%s'\n",
5364 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5365 printf("::: leveldir_current->graphics_set == '%s'\n",
5366 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5367 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5368 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5372 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5373 leveldir_current->identifier,
5374 artwork.gfx_current_identifier,
5375 artwork.gfx_current->identifier,
5376 leveldir_current->graphics_set,
5377 leveldir_current->graphics_path);
5380 UPDATE_BUSY_STATE();
5382 ReloadCustomImages();
5383 print_timestamp_time("ReloadCustomImages");
5385 UPDATE_BUSY_STATE();
5387 LoadCustomElementDescriptions();
5388 print_timestamp_time("LoadCustomElementDescriptions");
5390 UPDATE_BUSY_STATE();
5392 LoadMenuDesignSettings();
5393 print_timestamp_time("LoadMenuDesignSettings");
5395 UPDATE_BUSY_STATE();
5397 ReinitializeGraphics();
5398 print_timestamp_time("ReinitializeGraphics");
5400 UPDATE_BUSY_STATE();
5402 print_timestamp_done("InitImages");
5405 static void InitSound(char *identifier)
5407 print_timestamp_init("InitSound");
5409 if (identifier == NULL)
5410 identifier = artwork.snd_current->identifier;
5412 /* set artwork path to send it to the sound server process */
5413 setLevelArtworkDir(artwork.snd_first);
5415 InitReloadCustomSounds(identifier);
5416 print_timestamp_time("InitReloadCustomSounds");
5418 ReinitializeSounds();
5419 print_timestamp_time("ReinitializeSounds");
5421 print_timestamp_done("InitSound");
5424 static void InitMusic(char *identifier)
5426 print_timestamp_init("InitMusic");
5428 if (identifier == NULL)
5429 identifier = artwork.mus_current->identifier;
5431 /* set artwork path to send it to the sound server process */
5432 setLevelArtworkDir(artwork.mus_first);
5434 InitReloadCustomMusic(identifier);
5435 print_timestamp_time("InitReloadCustomMusic");
5437 ReinitializeMusic();
5438 print_timestamp_time("ReinitializeMusic");
5440 print_timestamp_done("InitMusic");
5443 static void InitArtworkDone()
5445 InitGlobalAnimations();
5448 void InitNetworkServer()
5450 #if defined(NETWORK_AVALIABLE)
5454 if (!options.network)
5457 #if defined(NETWORK_AVALIABLE)
5458 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5460 if (!ConnectToServer(options.server_host, options.server_port))
5461 Error(ERR_EXIT, "cannot connect to network game server");
5463 SendToServer_PlayerName(setup.player_name);
5464 SendToServer_ProtocolVersion();
5467 SendToServer_NrWanted(nr_wanted);
5471 static boolean CheckArtworkConfigForCustomElements(char *filename)
5473 SetupFileHash *setup_file_hash;
5474 boolean redefined_ce_found = FALSE;
5476 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5478 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5480 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5482 char *token = HASH_ITERATION_TOKEN(itr);
5484 if (strPrefix(token, "custom_"))
5486 redefined_ce_found = TRUE;
5491 END_HASH_ITERATION(setup_file_hash, itr)
5493 freeSetupFileHash(setup_file_hash);
5496 return redefined_ce_found;
5499 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5501 char *filename_base, *filename_local;
5502 boolean redefined_ce_found = FALSE;
5504 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5507 printf("::: leveldir_current->identifier == '%s'\n",
5508 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5509 printf("::: leveldir_current->graphics_path == '%s'\n",
5510 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5511 printf("::: leveldir_current->graphics_set == '%s'\n",
5512 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5513 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5514 leveldir_current == NULL ? "[NULL]" :
5515 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5518 /* first look for special artwork configured in level series config */
5519 filename_base = getCustomArtworkLevelConfigFilename(type);
5522 printf("::: filename_base == '%s'\n", filename_base);
5525 if (fileExists(filename_base))
5526 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5528 filename_local = getCustomArtworkConfigFilename(type);
5531 printf("::: filename_local == '%s'\n", filename_local);
5534 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5535 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5538 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5541 return redefined_ce_found;
5544 static void InitOverrideArtwork()
5546 boolean redefined_ce_found = FALSE;
5548 /* to check if this level set redefines any CEs, do not use overriding */
5549 gfx.override_level_graphics = FALSE;
5550 gfx.override_level_sounds = FALSE;
5551 gfx.override_level_music = FALSE;
5553 /* now check if this level set has definitions for custom elements */
5554 if (setup.override_level_graphics == AUTO ||
5555 setup.override_level_sounds == AUTO ||
5556 setup.override_level_music == AUTO)
5557 redefined_ce_found =
5558 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5559 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5560 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5563 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5566 if (redefined_ce_found)
5568 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5569 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5570 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5571 gfx.override_level_music = (setup.override_level_music == TRUE);
5575 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5576 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5577 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5578 gfx.override_level_music = (setup.override_level_music != FALSE);
5582 printf("::: => %d, %d, %d\n",
5583 gfx.override_level_graphics,
5584 gfx.override_level_sounds,
5585 gfx.override_level_music);
5589 static char *getNewArtworkIdentifier(int type)
5591 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5592 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5593 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5594 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5595 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5596 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5597 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5598 char *leveldir_identifier = leveldir_current->identifier;
5599 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5600 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5601 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5602 char *artwork_current_identifier;
5603 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5605 /* leveldir_current may be invalid (level group, parent link) */
5606 if (!validLevelSeries(leveldir_current))
5609 /* 1st step: determine artwork set to be activated in descending order:
5610 --------------------------------------------------------------------
5611 1. setup artwork (when configured to override everything else)
5612 2. artwork set configured in "levelinfo.conf" of current level set
5613 (artwork in level directory will have priority when loading later)
5614 3. artwork in level directory (stored in artwork sub-directory)
5615 4. setup artwork (currently configured in setup menu) */
5617 if (setup_override_artwork)
5618 artwork_current_identifier = setup_artwork_set;
5619 else if (leveldir_artwork_set != NULL)
5620 artwork_current_identifier = leveldir_artwork_set;
5621 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5622 artwork_current_identifier = leveldir_identifier;
5624 artwork_current_identifier = setup_artwork_set;
5627 /* 2nd step: check if it is really needed to reload artwork set
5628 ------------------------------------------------------------ */
5630 /* ---------- reload if level set and also artwork set has changed ------- */
5631 if (leveldir_current_identifier[type] != leveldir_identifier &&
5632 (last_has_level_artwork_set[type] || has_level_artwork_set))
5633 artwork_new_identifier = artwork_current_identifier;
5635 leveldir_current_identifier[type] = leveldir_identifier;
5636 last_has_level_artwork_set[type] = has_level_artwork_set;
5638 /* ---------- reload if "override artwork" setting has changed ----------- */
5639 if (last_override_level_artwork[type] != setup_override_artwork)
5640 artwork_new_identifier = artwork_current_identifier;
5642 last_override_level_artwork[type] = setup_override_artwork;
5644 /* ---------- reload if current artwork identifier has changed ----------- */
5645 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5646 artwork_current_identifier))
5647 artwork_new_identifier = artwork_current_identifier;
5649 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5651 /* ---------- do not reload directly after starting ---------------------- */
5652 if (!initialized[type])
5653 artwork_new_identifier = NULL;
5655 initialized[type] = TRUE;
5657 return artwork_new_identifier;
5660 void ReloadCustomArtwork(int force_reload)
5662 int last_game_status = game_status; /* save current game status */
5663 char *gfx_new_identifier;
5664 char *snd_new_identifier;
5665 char *mus_new_identifier;
5666 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5667 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5668 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5669 boolean reload_needed;
5671 InitOverrideArtwork();
5673 force_reload_gfx |= AdjustGraphicsForEMC();
5675 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5676 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5677 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5679 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5680 snd_new_identifier != NULL || force_reload_snd ||
5681 mus_new_identifier != NULL || force_reload_mus);
5686 print_timestamp_init("ReloadCustomArtwork");
5688 SetGameStatus(GAME_MODE_LOADING);
5690 FadeOut(REDRAW_ALL);
5692 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5693 print_timestamp_time("ClearRectangle");
5697 if (gfx_new_identifier != NULL || force_reload_gfx)
5700 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5701 artwork.gfx_current_identifier,
5703 artwork.gfx_current->identifier,
5704 leveldir_current->graphics_set);
5708 print_timestamp_time("InitImages");
5711 if (snd_new_identifier != NULL || force_reload_snd)
5713 InitSound(snd_new_identifier);
5714 print_timestamp_time("InitSound");
5717 if (mus_new_identifier != NULL || force_reload_mus)
5719 InitMusic(mus_new_identifier);
5720 print_timestamp_time("InitMusic");
5725 SetGameStatus(last_game_status); /* restore current game status */
5727 init_last = init; /* switch to new busy animation */
5729 FadeOut(REDRAW_ALL);
5731 RedrawGlobalBorder();
5733 /* force redraw of (open or closed) door graphics */
5734 SetDoorState(DOOR_OPEN_ALL);
5735 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5737 FadeSetEnterScreen();
5738 FadeSkipNextFadeOut();
5740 print_timestamp_done("ReloadCustomArtwork");
5742 LimitScreenUpdates(FALSE);
5745 void KeyboardAutoRepeatOffUnlessAutoplay()
5747 if (global.autoplay_leveldir == NULL)
5748 KeyboardAutoRepeatOff();
5751 void DisplayExitMessage(char *format, va_list ap)
5753 // check if draw buffer and fonts for exit message are already available
5754 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5757 int font_1 = FC_RED;
5758 int font_2 = FC_YELLOW;
5759 int font_3 = FC_BLUE;
5760 int font_width = getFontWidth(font_2);
5761 int font_height = getFontHeight(font_2);
5764 int sxsize = WIN_XSIZE - 2 * sx;
5765 int sysize = WIN_YSIZE - 2 * sy;
5766 int line_length = sxsize / font_width;
5767 int max_lines = sysize / font_height;
5768 int num_lines_printed;
5772 gfx.sxsize = sxsize;
5773 gfx.sysize = sysize;
5777 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5779 DrawTextSCentered(sy, font_1, "Fatal error:");
5780 sy += 3 * font_height;;
5783 DrawTextBufferVA(sx, sy, format, ap, font_2,
5784 line_length, line_length, max_lines,
5785 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5786 sy += (num_lines_printed + 3) * font_height;
5788 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5789 sy += 3 * font_height;
5792 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5793 line_length, line_length, max_lines,
5794 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5796 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5798 redraw_mask = REDRAW_ALL;
5800 /* force drawing exit message even if screen updates are currently limited */
5801 LimitScreenUpdates(FALSE);
5805 /* deactivate toons on error message screen */
5806 setup.toons = FALSE;
5808 WaitForEventToContinue();
5812 /* ========================================================================= */
5814 /* ========================================================================= */
5818 print_timestamp_init("OpenAll");
5820 SetGameStatus(GAME_MODE_LOADING);
5824 InitGlobal(); /* initialize some global variables */
5826 print_timestamp_time("[init global stuff]");
5830 print_timestamp_time("[init setup/config stuff (1)]");
5832 if (options.execute_command)
5833 Execute_Command(options.execute_command);
5835 if (options.serveronly)
5837 #if defined(PLATFORM_UNIX)
5838 NetworkServer(options.server_port, options.serveronly);
5840 Error(ERR_WARN, "networking only supported in Unix version");
5843 exit(0); /* never reached, server loops forever */
5847 print_timestamp_time("[init setup/config stuff (2)]");
5849 print_timestamp_time("[init setup/config stuff (3)]");
5850 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5851 print_timestamp_time("[init setup/config stuff (4)]");
5852 InitArtworkConfig(); /* needed before forking sound child process */
5853 print_timestamp_time("[init setup/config stuff (5)]");
5855 print_timestamp_time("[init setup/config stuff (6)]");
5857 InitRND(NEW_RANDOMIZE);
5858 InitSimpleRandom(NEW_RANDOMIZE);
5862 print_timestamp_time("[init setup/config stuff]");
5865 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5867 InitEventFilter(FilterEvents);
5869 print_timestamp_time("[init video stuff]");
5871 InitElementPropertiesStatic();
5872 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5873 InitElementPropertiesGfxElement();
5875 print_timestamp_time("[init element properties stuff]");
5879 print_timestamp_time("InitGfx");
5882 print_timestamp_time("InitLevelInfo");
5884 InitLevelArtworkInfo();
5885 print_timestamp_time("InitLevelArtworkInfo");
5887 InitOverrideArtwork(); /* needs to know current level directory */
5888 print_timestamp_time("InitOverrideArtwork");
5890 InitImages(); /* needs to know current level directory */
5891 print_timestamp_time("InitImages");
5893 InitSound(NULL); /* needs to know current level directory */
5894 print_timestamp_time("InitSound");
5896 InitMusic(NULL); /* needs to know current level directory */
5897 print_timestamp_time("InitMusic");
5901 InitGfxBackground();
5906 if (global.autoplay_leveldir)
5911 else if (global.convert_leveldir)
5916 else if (global.create_images_dir)
5918 CreateLevelSketchImages();
5922 SetGameStatus(GAME_MODE_MAIN);
5924 FadeSetEnterScreen();
5925 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5926 FadeSkipNextFadeOut();
5928 print_timestamp_time("[post-artwork]");
5930 print_timestamp_done("OpenAll");
5934 InitNetworkServer();
5937 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5939 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5940 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5941 #if defined(PLATFORM_ANDROID)
5942 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5943 SDL_AndroidGetInternalStoragePath());
5944 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5945 SDL_AndroidGetExternalStoragePath());
5946 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5947 (SDL_AndroidGetExternalStorageState() ==
5948 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5949 SDL_AndroidGetExternalStorageState() ==
5950 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5955 void CloseAllAndExit(int exit_value)
5960 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5967 #if defined(TARGET_SDL)
5968 #if defined(TARGET_SDL2)
5970 // set a flag to tell the network server thread to quit and wait for it
5971 // using SDL_WaitThread()
5973 if (network_server) /* terminate network server */
5974 SDL_KillThread(server_thread);
5978 CloseVideoDisplay();
5979 ClosePlatformDependentStuff();
5981 if (exit_value != 0)
5983 /* fall back to default level set (current set may have caused an error) */
5984 SaveLevelSetup_LastSeries_Deactivate();
5986 /* tell user where to find error log file which may contain more details */
5987 // (error notification now directly displayed on screen inside R'n'D
5988 // NotifyUserAboutErrorFile(); /* currently only works for Windows */