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("InitToons");
2127 print_timestamp_time("InitDoors");
2129 print_timestamp_done("ReinitializeGraphics");
2132 static void ReinitializeSounds()
2134 InitSoundInfo(); /* sound properties mapping */
2135 InitElementSoundInfo(); /* element game sound mapping */
2136 InitGameModeSoundInfo(); /* game mode sound mapping */
2137 InitGlobalAnimSoundInfo(); /* global animation sound settings */
2139 InitPlayLevelSound(); /* internal game sound settings */
2142 static void ReinitializeMusic()
2144 InitMusicInfo(); /* music properties mapping */
2145 InitGameModeMusicInfo(); /* game mode music mapping */
2148 static int get_special_property_bit(int element, int property_bit_nr)
2150 struct PropertyBitInfo
2156 static struct PropertyBitInfo pb_can_move_into_acid[] =
2158 /* the player may be able fall into acid when gravity is activated */
2163 { EL_SP_MURPHY, 0 },
2164 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2166 /* all elements that can move may be able to also move into acid */
2169 { EL_BUG_RIGHT, 1 },
2172 { EL_SPACESHIP, 2 },
2173 { EL_SPACESHIP_LEFT, 2 },
2174 { EL_SPACESHIP_RIGHT, 2 },
2175 { EL_SPACESHIP_UP, 2 },
2176 { EL_SPACESHIP_DOWN, 2 },
2177 { EL_BD_BUTTERFLY, 3 },
2178 { EL_BD_BUTTERFLY_LEFT, 3 },
2179 { EL_BD_BUTTERFLY_RIGHT, 3 },
2180 { EL_BD_BUTTERFLY_UP, 3 },
2181 { EL_BD_BUTTERFLY_DOWN, 3 },
2182 { EL_BD_FIREFLY, 4 },
2183 { EL_BD_FIREFLY_LEFT, 4 },
2184 { EL_BD_FIREFLY_RIGHT, 4 },
2185 { EL_BD_FIREFLY_UP, 4 },
2186 { EL_BD_FIREFLY_DOWN, 4 },
2188 { EL_YAMYAM_LEFT, 5 },
2189 { EL_YAMYAM_RIGHT, 5 },
2190 { EL_YAMYAM_UP, 5 },
2191 { EL_YAMYAM_DOWN, 5 },
2192 { EL_DARK_YAMYAM, 6 },
2195 { EL_PACMAN_LEFT, 8 },
2196 { EL_PACMAN_RIGHT, 8 },
2197 { EL_PACMAN_UP, 8 },
2198 { EL_PACMAN_DOWN, 8 },
2200 { EL_MOLE_LEFT, 9 },
2201 { EL_MOLE_RIGHT, 9 },
2203 { EL_MOLE_DOWN, 9 },
2207 { EL_SATELLITE, 13 },
2208 { EL_SP_SNIKSNAK, 14 },
2209 { EL_SP_ELECTRON, 15 },
2212 { EL_EMC_ANDROID, 18 },
2217 static struct PropertyBitInfo pb_dont_collide_with[] =
2219 { EL_SP_SNIKSNAK, 0 },
2220 { EL_SP_ELECTRON, 1 },
2228 struct PropertyBitInfo *pb_info;
2231 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2232 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2237 struct PropertyBitInfo *pb_info = NULL;
2240 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2241 if (pb_definition[i].bit_nr == property_bit_nr)
2242 pb_info = pb_definition[i].pb_info;
2244 if (pb_info == NULL)
2247 for (i = 0; pb_info[i].element != -1; i++)
2248 if (pb_info[i].element == element)
2249 return pb_info[i].bit_nr;
2254 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2255 boolean property_value)
2257 int bit_nr = get_special_property_bit(element, property_bit_nr);
2262 *bitfield |= (1 << bit_nr);
2264 *bitfield &= ~(1 << bit_nr);
2268 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2270 int bit_nr = get_special_property_bit(element, property_bit_nr);
2273 return ((*bitfield & (1 << bit_nr)) != 0);
2278 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2280 static int group_nr;
2281 static struct ElementGroupInfo *group;
2282 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2285 if (actual_group == NULL) /* not yet initialized */
2288 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2290 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2291 group_element - EL_GROUP_START + 1);
2293 /* replace element which caused too deep recursion by question mark */
2294 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2299 if (recursion_depth == 0) /* initialization */
2301 group = actual_group;
2302 group_nr = GROUP_NR(group_element);
2304 group->num_elements_resolved = 0;
2305 group->choice_pos = 0;
2307 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2308 element_info[i].in_group[group_nr] = FALSE;
2311 for (i = 0; i < actual_group->num_elements; i++)
2313 int element = actual_group->element[i];
2315 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2318 if (IS_GROUP_ELEMENT(element))
2319 ResolveGroupElementExt(element, recursion_depth + 1);
2322 group->element_resolved[group->num_elements_resolved++] = element;
2323 element_info[element].in_group[group_nr] = TRUE;
2328 void ResolveGroupElement(int group_element)
2330 ResolveGroupElementExt(group_element, 0);
2333 void InitElementPropertiesStatic()
2335 static boolean clipboard_elements_initialized = FALSE;
2337 static int ep_diggable[] =
2342 EL_SP_BUGGY_BASE_ACTIVATING,
2345 EL_INVISIBLE_SAND_ACTIVE,
2348 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2349 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2354 EL_SP_BUGGY_BASE_ACTIVE,
2361 static int ep_collectible_only[] =
2383 EL_DYNABOMB_INCREASE_NUMBER,
2384 EL_DYNABOMB_INCREASE_SIZE,
2385 EL_DYNABOMB_INCREASE_POWER,
2403 /* !!! handle separately !!! */
2404 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2410 static int ep_dont_run_into[] =
2412 /* same elements as in 'ep_dont_touch' */
2418 /* same elements as in 'ep_dont_collide_with' */
2430 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2435 EL_SP_BUGGY_BASE_ACTIVE,
2442 static int ep_dont_collide_with[] =
2444 /* same elements as in 'ep_dont_touch' */
2461 static int ep_dont_touch[] =
2471 static int ep_indestructible[] =
2475 EL_ACID_POOL_TOPLEFT,
2476 EL_ACID_POOL_TOPRIGHT,
2477 EL_ACID_POOL_BOTTOMLEFT,
2478 EL_ACID_POOL_BOTTOM,
2479 EL_ACID_POOL_BOTTOMRIGHT,
2480 EL_SP_HARDWARE_GRAY,
2481 EL_SP_HARDWARE_GREEN,
2482 EL_SP_HARDWARE_BLUE,
2484 EL_SP_HARDWARE_YELLOW,
2485 EL_SP_HARDWARE_BASE_1,
2486 EL_SP_HARDWARE_BASE_2,
2487 EL_SP_HARDWARE_BASE_3,
2488 EL_SP_HARDWARE_BASE_4,
2489 EL_SP_HARDWARE_BASE_5,
2490 EL_SP_HARDWARE_BASE_6,
2491 EL_INVISIBLE_STEELWALL,
2492 EL_INVISIBLE_STEELWALL_ACTIVE,
2493 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2494 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2495 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2496 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2497 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2498 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2499 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2500 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2501 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2502 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2503 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2504 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2506 EL_LIGHT_SWITCH_ACTIVE,
2507 EL_SIGN_EXCLAMATION,
2508 EL_SIGN_RADIOACTIVITY,
2515 EL_SIGN_ENTRY_FORBIDDEN,
2516 EL_SIGN_EMERGENCY_EXIT,
2524 EL_STEEL_EXIT_CLOSED,
2526 EL_STEEL_EXIT_OPENING,
2527 EL_STEEL_EXIT_CLOSING,
2528 EL_EM_STEEL_EXIT_CLOSED,
2529 EL_EM_STEEL_EXIT_OPEN,
2530 EL_EM_STEEL_EXIT_OPENING,
2531 EL_EM_STEEL_EXIT_CLOSING,
2532 EL_DC_STEELWALL_1_LEFT,
2533 EL_DC_STEELWALL_1_RIGHT,
2534 EL_DC_STEELWALL_1_TOP,
2535 EL_DC_STEELWALL_1_BOTTOM,
2536 EL_DC_STEELWALL_1_HORIZONTAL,
2537 EL_DC_STEELWALL_1_VERTICAL,
2538 EL_DC_STEELWALL_1_TOPLEFT,
2539 EL_DC_STEELWALL_1_TOPRIGHT,
2540 EL_DC_STEELWALL_1_BOTTOMLEFT,
2541 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2542 EL_DC_STEELWALL_1_TOPLEFT_2,
2543 EL_DC_STEELWALL_1_TOPRIGHT_2,
2544 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2545 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2546 EL_DC_STEELWALL_2_LEFT,
2547 EL_DC_STEELWALL_2_RIGHT,
2548 EL_DC_STEELWALL_2_TOP,
2549 EL_DC_STEELWALL_2_BOTTOM,
2550 EL_DC_STEELWALL_2_HORIZONTAL,
2551 EL_DC_STEELWALL_2_VERTICAL,
2552 EL_DC_STEELWALL_2_MIDDLE,
2553 EL_DC_STEELWALL_2_SINGLE,
2554 EL_STEELWALL_SLIPPERY,
2568 EL_GATE_1_GRAY_ACTIVE,
2569 EL_GATE_2_GRAY_ACTIVE,
2570 EL_GATE_3_GRAY_ACTIVE,
2571 EL_GATE_4_GRAY_ACTIVE,
2580 EL_EM_GATE_1_GRAY_ACTIVE,
2581 EL_EM_GATE_2_GRAY_ACTIVE,
2582 EL_EM_GATE_3_GRAY_ACTIVE,
2583 EL_EM_GATE_4_GRAY_ACTIVE,
2592 EL_EMC_GATE_5_GRAY_ACTIVE,
2593 EL_EMC_GATE_6_GRAY_ACTIVE,
2594 EL_EMC_GATE_7_GRAY_ACTIVE,
2595 EL_EMC_GATE_8_GRAY_ACTIVE,
2597 EL_DC_GATE_WHITE_GRAY,
2598 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2599 EL_DC_GATE_FAKE_GRAY,
2601 EL_SWITCHGATE_OPENING,
2602 EL_SWITCHGATE_CLOSED,
2603 EL_SWITCHGATE_CLOSING,
2604 EL_DC_SWITCHGATE_SWITCH_UP,
2605 EL_DC_SWITCHGATE_SWITCH_DOWN,
2607 EL_TIMEGATE_OPENING,
2609 EL_TIMEGATE_CLOSING,
2610 EL_DC_TIMEGATE_SWITCH,
2611 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2615 EL_TUBE_VERTICAL_LEFT,
2616 EL_TUBE_VERTICAL_RIGHT,
2617 EL_TUBE_HORIZONTAL_UP,
2618 EL_TUBE_HORIZONTAL_DOWN,
2623 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2624 EL_EXPANDABLE_STEELWALL_VERTICAL,
2625 EL_EXPANDABLE_STEELWALL_ANY,
2630 static int ep_slippery[] =
2644 EL_ROBOT_WHEEL_ACTIVE,
2650 EL_ACID_POOL_TOPLEFT,
2651 EL_ACID_POOL_TOPRIGHT,
2661 EL_STEELWALL_SLIPPERY,
2664 EL_EMC_WALL_SLIPPERY_1,
2665 EL_EMC_WALL_SLIPPERY_2,
2666 EL_EMC_WALL_SLIPPERY_3,
2667 EL_EMC_WALL_SLIPPERY_4,
2669 EL_EMC_MAGIC_BALL_ACTIVE,
2674 static int ep_can_change[] =
2679 static int ep_can_move[] =
2681 /* same elements as in 'pb_can_move_into_acid' */
2704 static int ep_can_fall[] =
2718 EL_QUICKSAND_FAST_FULL,
2720 EL_BD_MAGIC_WALL_FULL,
2721 EL_DC_MAGIC_WALL_FULL,
2735 static int ep_can_smash_player[] =
2761 static int ep_can_smash_enemies[] =
2770 static int ep_can_smash_everything[] =
2779 static int ep_explodes_by_fire[] =
2781 /* same elements as in 'ep_explodes_impact' */
2786 /* same elements as in 'ep_explodes_smashed' */
2796 EL_EM_DYNAMITE_ACTIVE,
2797 EL_DYNABOMB_PLAYER_1_ACTIVE,
2798 EL_DYNABOMB_PLAYER_2_ACTIVE,
2799 EL_DYNABOMB_PLAYER_3_ACTIVE,
2800 EL_DYNABOMB_PLAYER_4_ACTIVE,
2801 EL_DYNABOMB_INCREASE_NUMBER,
2802 EL_DYNABOMB_INCREASE_SIZE,
2803 EL_DYNABOMB_INCREASE_POWER,
2804 EL_SP_DISK_RED_ACTIVE,
2818 static int ep_explodes_smashed[] =
2820 /* same elements as in 'ep_explodes_impact' */
2834 static int ep_explodes_impact[] =
2843 static int ep_walkable_over[] =
2847 EL_SOKOBAN_FIELD_EMPTY,
2854 EL_EM_STEEL_EXIT_OPEN,
2855 EL_EM_STEEL_EXIT_OPENING,
2864 EL_GATE_1_GRAY_ACTIVE,
2865 EL_GATE_2_GRAY_ACTIVE,
2866 EL_GATE_3_GRAY_ACTIVE,
2867 EL_GATE_4_GRAY_ACTIVE,
2875 static int ep_walkable_inside[] =
2880 EL_TUBE_VERTICAL_LEFT,
2881 EL_TUBE_VERTICAL_RIGHT,
2882 EL_TUBE_HORIZONTAL_UP,
2883 EL_TUBE_HORIZONTAL_DOWN,
2892 static int ep_walkable_under[] =
2897 static int ep_passable_over[] =
2907 EL_EM_GATE_1_GRAY_ACTIVE,
2908 EL_EM_GATE_2_GRAY_ACTIVE,
2909 EL_EM_GATE_3_GRAY_ACTIVE,
2910 EL_EM_GATE_4_GRAY_ACTIVE,
2919 EL_EMC_GATE_5_GRAY_ACTIVE,
2920 EL_EMC_GATE_6_GRAY_ACTIVE,
2921 EL_EMC_GATE_7_GRAY_ACTIVE,
2922 EL_EMC_GATE_8_GRAY_ACTIVE,
2924 EL_DC_GATE_WHITE_GRAY,
2925 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2932 static int ep_passable_inside[] =
2938 EL_SP_PORT_HORIZONTAL,
2939 EL_SP_PORT_VERTICAL,
2941 EL_SP_GRAVITY_PORT_LEFT,
2942 EL_SP_GRAVITY_PORT_RIGHT,
2943 EL_SP_GRAVITY_PORT_UP,
2944 EL_SP_GRAVITY_PORT_DOWN,
2945 EL_SP_GRAVITY_ON_PORT_LEFT,
2946 EL_SP_GRAVITY_ON_PORT_RIGHT,
2947 EL_SP_GRAVITY_ON_PORT_UP,
2948 EL_SP_GRAVITY_ON_PORT_DOWN,
2949 EL_SP_GRAVITY_OFF_PORT_LEFT,
2950 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2951 EL_SP_GRAVITY_OFF_PORT_UP,
2952 EL_SP_GRAVITY_OFF_PORT_DOWN,
2957 static int ep_passable_under[] =
2962 static int ep_droppable[] =
2967 static int ep_explodes_1x1_old[] =
2972 static int ep_pushable[] =
2984 EL_SOKOBAN_FIELD_FULL,
2993 static int ep_explodes_cross_old[] =
2998 static int ep_protected[] =
3000 /* same elements as in 'ep_walkable_inside' */
3004 EL_TUBE_VERTICAL_LEFT,
3005 EL_TUBE_VERTICAL_RIGHT,
3006 EL_TUBE_HORIZONTAL_UP,
3007 EL_TUBE_HORIZONTAL_DOWN,
3013 /* same elements as in 'ep_passable_over' */
3022 EL_EM_GATE_1_GRAY_ACTIVE,
3023 EL_EM_GATE_2_GRAY_ACTIVE,
3024 EL_EM_GATE_3_GRAY_ACTIVE,
3025 EL_EM_GATE_4_GRAY_ACTIVE,
3034 EL_EMC_GATE_5_GRAY_ACTIVE,
3035 EL_EMC_GATE_6_GRAY_ACTIVE,
3036 EL_EMC_GATE_7_GRAY_ACTIVE,
3037 EL_EMC_GATE_8_GRAY_ACTIVE,
3039 EL_DC_GATE_WHITE_GRAY,
3040 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3044 /* same elements as in 'ep_passable_inside' */
3049 EL_SP_PORT_HORIZONTAL,
3050 EL_SP_PORT_VERTICAL,
3052 EL_SP_GRAVITY_PORT_LEFT,
3053 EL_SP_GRAVITY_PORT_RIGHT,
3054 EL_SP_GRAVITY_PORT_UP,
3055 EL_SP_GRAVITY_PORT_DOWN,
3056 EL_SP_GRAVITY_ON_PORT_LEFT,
3057 EL_SP_GRAVITY_ON_PORT_RIGHT,
3058 EL_SP_GRAVITY_ON_PORT_UP,
3059 EL_SP_GRAVITY_ON_PORT_DOWN,
3060 EL_SP_GRAVITY_OFF_PORT_LEFT,
3061 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3062 EL_SP_GRAVITY_OFF_PORT_UP,
3063 EL_SP_GRAVITY_OFF_PORT_DOWN,
3068 static int ep_throwable[] =
3073 static int ep_can_explode[] =
3075 /* same elements as in 'ep_explodes_impact' */
3080 /* same elements as in 'ep_explodes_smashed' */
3086 /* elements that can explode by explosion or by dragonfire */
3090 EL_EM_DYNAMITE_ACTIVE,
3091 EL_DYNABOMB_PLAYER_1_ACTIVE,
3092 EL_DYNABOMB_PLAYER_2_ACTIVE,
3093 EL_DYNABOMB_PLAYER_3_ACTIVE,
3094 EL_DYNABOMB_PLAYER_4_ACTIVE,
3095 EL_DYNABOMB_INCREASE_NUMBER,
3096 EL_DYNABOMB_INCREASE_SIZE,
3097 EL_DYNABOMB_INCREASE_POWER,
3098 EL_SP_DISK_RED_ACTIVE,
3106 /* elements that can explode only by explosion */
3112 static int ep_gravity_reachable[] =
3118 EL_INVISIBLE_SAND_ACTIVE,
3123 EL_SP_PORT_HORIZONTAL,
3124 EL_SP_PORT_VERTICAL,
3126 EL_SP_GRAVITY_PORT_LEFT,
3127 EL_SP_GRAVITY_PORT_RIGHT,
3128 EL_SP_GRAVITY_PORT_UP,
3129 EL_SP_GRAVITY_PORT_DOWN,
3130 EL_SP_GRAVITY_ON_PORT_LEFT,
3131 EL_SP_GRAVITY_ON_PORT_RIGHT,
3132 EL_SP_GRAVITY_ON_PORT_UP,
3133 EL_SP_GRAVITY_ON_PORT_DOWN,
3134 EL_SP_GRAVITY_OFF_PORT_LEFT,
3135 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3136 EL_SP_GRAVITY_OFF_PORT_UP,
3137 EL_SP_GRAVITY_OFF_PORT_DOWN,
3143 static int ep_player[] =
3150 EL_SOKOBAN_FIELD_PLAYER,
3156 static int ep_can_pass_magic_wall[] =
3170 static int ep_can_pass_dc_magic_wall[] =
3186 static int ep_switchable[] =
3190 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3191 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3192 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3193 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3194 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3195 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3196 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3197 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3198 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3199 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3200 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3201 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3202 EL_SWITCHGATE_SWITCH_UP,
3203 EL_SWITCHGATE_SWITCH_DOWN,
3204 EL_DC_SWITCHGATE_SWITCH_UP,
3205 EL_DC_SWITCHGATE_SWITCH_DOWN,
3207 EL_LIGHT_SWITCH_ACTIVE,
3209 EL_DC_TIMEGATE_SWITCH,
3210 EL_BALLOON_SWITCH_LEFT,
3211 EL_BALLOON_SWITCH_RIGHT,
3212 EL_BALLOON_SWITCH_UP,
3213 EL_BALLOON_SWITCH_DOWN,
3214 EL_BALLOON_SWITCH_ANY,
3215 EL_BALLOON_SWITCH_NONE,
3218 EL_EMC_MAGIC_BALL_SWITCH,
3219 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3224 static int ep_bd_element[] =
3258 static int ep_sp_element[] =
3260 /* should always be valid */
3263 /* standard classic Supaplex elements */
3270 EL_SP_HARDWARE_GRAY,
3278 EL_SP_GRAVITY_PORT_RIGHT,
3279 EL_SP_GRAVITY_PORT_DOWN,
3280 EL_SP_GRAVITY_PORT_LEFT,
3281 EL_SP_GRAVITY_PORT_UP,
3286 EL_SP_PORT_VERTICAL,
3287 EL_SP_PORT_HORIZONTAL,
3293 EL_SP_HARDWARE_BASE_1,
3294 EL_SP_HARDWARE_GREEN,
3295 EL_SP_HARDWARE_BLUE,
3297 EL_SP_HARDWARE_YELLOW,
3298 EL_SP_HARDWARE_BASE_2,
3299 EL_SP_HARDWARE_BASE_3,
3300 EL_SP_HARDWARE_BASE_4,
3301 EL_SP_HARDWARE_BASE_5,
3302 EL_SP_HARDWARE_BASE_6,
3306 /* additional elements that appeared in newer Supaplex levels */
3309 /* additional gravity port elements (not switching, but setting gravity) */
3310 EL_SP_GRAVITY_ON_PORT_LEFT,
3311 EL_SP_GRAVITY_ON_PORT_RIGHT,
3312 EL_SP_GRAVITY_ON_PORT_UP,
3313 EL_SP_GRAVITY_ON_PORT_DOWN,
3314 EL_SP_GRAVITY_OFF_PORT_LEFT,
3315 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3316 EL_SP_GRAVITY_OFF_PORT_UP,
3317 EL_SP_GRAVITY_OFF_PORT_DOWN,
3319 /* more than one Murphy in a level results in an inactive clone */
3322 /* runtime Supaplex elements */
3323 EL_SP_DISK_RED_ACTIVE,
3324 EL_SP_TERMINAL_ACTIVE,
3325 EL_SP_BUGGY_BASE_ACTIVATING,
3326 EL_SP_BUGGY_BASE_ACTIVE,
3333 static int ep_sb_element[] =
3338 EL_SOKOBAN_FIELD_EMPTY,
3339 EL_SOKOBAN_FIELD_FULL,
3340 EL_SOKOBAN_FIELD_PLAYER,
3345 EL_INVISIBLE_STEELWALL,
3350 static int ep_gem[] =
3362 static int ep_food_dark_yamyam[] =
3390 static int ep_food_penguin[] =
3404 static int ep_food_pig[] =
3416 static int ep_historic_wall[] =
3427 EL_GATE_1_GRAY_ACTIVE,
3428 EL_GATE_2_GRAY_ACTIVE,
3429 EL_GATE_3_GRAY_ACTIVE,
3430 EL_GATE_4_GRAY_ACTIVE,
3439 EL_EM_GATE_1_GRAY_ACTIVE,
3440 EL_EM_GATE_2_GRAY_ACTIVE,
3441 EL_EM_GATE_3_GRAY_ACTIVE,
3442 EL_EM_GATE_4_GRAY_ACTIVE,
3449 EL_EXPANDABLE_WALL_HORIZONTAL,
3450 EL_EXPANDABLE_WALL_VERTICAL,
3451 EL_EXPANDABLE_WALL_ANY,
3452 EL_EXPANDABLE_WALL_GROWING,
3453 EL_BD_EXPANDABLE_WALL,
3460 EL_SP_HARDWARE_GRAY,
3461 EL_SP_HARDWARE_GREEN,
3462 EL_SP_HARDWARE_BLUE,
3464 EL_SP_HARDWARE_YELLOW,
3465 EL_SP_HARDWARE_BASE_1,
3466 EL_SP_HARDWARE_BASE_2,
3467 EL_SP_HARDWARE_BASE_3,
3468 EL_SP_HARDWARE_BASE_4,
3469 EL_SP_HARDWARE_BASE_5,
3470 EL_SP_HARDWARE_BASE_6,
3472 EL_SP_TERMINAL_ACTIVE,
3475 EL_INVISIBLE_STEELWALL,
3476 EL_INVISIBLE_STEELWALL_ACTIVE,
3478 EL_INVISIBLE_WALL_ACTIVE,
3479 EL_STEELWALL_SLIPPERY,
3496 static int ep_historic_solid[] =
3500 EL_EXPANDABLE_WALL_HORIZONTAL,
3501 EL_EXPANDABLE_WALL_VERTICAL,
3502 EL_EXPANDABLE_WALL_ANY,
3503 EL_BD_EXPANDABLE_WALL,
3516 EL_QUICKSAND_FILLING,
3517 EL_QUICKSAND_EMPTYING,
3519 EL_MAGIC_WALL_ACTIVE,
3520 EL_MAGIC_WALL_EMPTYING,
3521 EL_MAGIC_WALL_FILLING,
3525 EL_BD_MAGIC_WALL_ACTIVE,
3526 EL_BD_MAGIC_WALL_EMPTYING,
3527 EL_BD_MAGIC_WALL_FULL,
3528 EL_BD_MAGIC_WALL_FILLING,
3529 EL_BD_MAGIC_WALL_DEAD,
3538 EL_SP_TERMINAL_ACTIVE,
3542 EL_INVISIBLE_WALL_ACTIVE,
3543 EL_SWITCHGATE_SWITCH_UP,
3544 EL_SWITCHGATE_SWITCH_DOWN,
3545 EL_DC_SWITCHGATE_SWITCH_UP,
3546 EL_DC_SWITCHGATE_SWITCH_DOWN,
3548 EL_TIMEGATE_SWITCH_ACTIVE,
3549 EL_DC_TIMEGATE_SWITCH,
3550 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3562 /* the following elements are a direct copy of "indestructible" elements,
3563 except "EL_ACID", which is "indestructible", but not "solid"! */
3568 EL_ACID_POOL_TOPLEFT,
3569 EL_ACID_POOL_TOPRIGHT,
3570 EL_ACID_POOL_BOTTOMLEFT,
3571 EL_ACID_POOL_BOTTOM,
3572 EL_ACID_POOL_BOTTOMRIGHT,
3573 EL_SP_HARDWARE_GRAY,
3574 EL_SP_HARDWARE_GREEN,
3575 EL_SP_HARDWARE_BLUE,
3577 EL_SP_HARDWARE_YELLOW,
3578 EL_SP_HARDWARE_BASE_1,
3579 EL_SP_HARDWARE_BASE_2,
3580 EL_SP_HARDWARE_BASE_3,
3581 EL_SP_HARDWARE_BASE_4,
3582 EL_SP_HARDWARE_BASE_5,
3583 EL_SP_HARDWARE_BASE_6,
3584 EL_INVISIBLE_STEELWALL,
3585 EL_INVISIBLE_STEELWALL_ACTIVE,
3586 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3587 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3588 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3589 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3590 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3591 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3592 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3593 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3594 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3595 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3596 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3597 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3599 EL_LIGHT_SWITCH_ACTIVE,
3600 EL_SIGN_EXCLAMATION,
3601 EL_SIGN_RADIOACTIVITY,
3608 EL_SIGN_ENTRY_FORBIDDEN,
3609 EL_SIGN_EMERGENCY_EXIT,
3617 EL_STEEL_EXIT_CLOSED,
3619 EL_DC_STEELWALL_1_LEFT,
3620 EL_DC_STEELWALL_1_RIGHT,
3621 EL_DC_STEELWALL_1_TOP,
3622 EL_DC_STEELWALL_1_BOTTOM,
3623 EL_DC_STEELWALL_1_HORIZONTAL,
3624 EL_DC_STEELWALL_1_VERTICAL,
3625 EL_DC_STEELWALL_1_TOPLEFT,
3626 EL_DC_STEELWALL_1_TOPRIGHT,
3627 EL_DC_STEELWALL_1_BOTTOMLEFT,
3628 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3629 EL_DC_STEELWALL_1_TOPLEFT_2,
3630 EL_DC_STEELWALL_1_TOPRIGHT_2,
3631 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3632 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3633 EL_DC_STEELWALL_2_LEFT,
3634 EL_DC_STEELWALL_2_RIGHT,
3635 EL_DC_STEELWALL_2_TOP,
3636 EL_DC_STEELWALL_2_BOTTOM,
3637 EL_DC_STEELWALL_2_HORIZONTAL,
3638 EL_DC_STEELWALL_2_VERTICAL,
3639 EL_DC_STEELWALL_2_MIDDLE,
3640 EL_DC_STEELWALL_2_SINGLE,
3641 EL_STEELWALL_SLIPPERY,
3655 EL_GATE_1_GRAY_ACTIVE,
3656 EL_GATE_2_GRAY_ACTIVE,
3657 EL_GATE_3_GRAY_ACTIVE,
3658 EL_GATE_4_GRAY_ACTIVE,
3667 EL_EM_GATE_1_GRAY_ACTIVE,
3668 EL_EM_GATE_2_GRAY_ACTIVE,
3669 EL_EM_GATE_3_GRAY_ACTIVE,
3670 EL_EM_GATE_4_GRAY_ACTIVE,
3672 EL_SWITCHGATE_OPENING,
3673 EL_SWITCHGATE_CLOSED,
3674 EL_SWITCHGATE_CLOSING,
3676 EL_TIMEGATE_OPENING,
3678 EL_TIMEGATE_CLOSING,
3682 EL_TUBE_VERTICAL_LEFT,
3683 EL_TUBE_VERTICAL_RIGHT,
3684 EL_TUBE_HORIZONTAL_UP,
3685 EL_TUBE_HORIZONTAL_DOWN,
3694 static int ep_classic_enemy[] =
3711 static int ep_belt[] =
3713 EL_CONVEYOR_BELT_1_LEFT,
3714 EL_CONVEYOR_BELT_1_MIDDLE,
3715 EL_CONVEYOR_BELT_1_RIGHT,
3716 EL_CONVEYOR_BELT_2_LEFT,
3717 EL_CONVEYOR_BELT_2_MIDDLE,
3718 EL_CONVEYOR_BELT_2_RIGHT,
3719 EL_CONVEYOR_BELT_3_LEFT,
3720 EL_CONVEYOR_BELT_3_MIDDLE,
3721 EL_CONVEYOR_BELT_3_RIGHT,
3722 EL_CONVEYOR_BELT_4_LEFT,
3723 EL_CONVEYOR_BELT_4_MIDDLE,
3724 EL_CONVEYOR_BELT_4_RIGHT,
3729 static int ep_belt_active[] =
3731 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3732 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3733 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3734 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3735 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3736 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3737 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3738 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3739 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3740 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3741 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3742 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3747 static int ep_belt_switch[] =
3749 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3750 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3751 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3752 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3753 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3754 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3755 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3756 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3757 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3758 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3759 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3760 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3765 static int ep_tube[] =
3772 EL_TUBE_HORIZONTAL_UP,
3773 EL_TUBE_HORIZONTAL_DOWN,
3775 EL_TUBE_VERTICAL_LEFT,
3776 EL_TUBE_VERTICAL_RIGHT,
3782 static int ep_acid_pool[] =
3784 EL_ACID_POOL_TOPLEFT,
3785 EL_ACID_POOL_TOPRIGHT,
3786 EL_ACID_POOL_BOTTOMLEFT,
3787 EL_ACID_POOL_BOTTOM,
3788 EL_ACID_POOL_BOTTOMRIGHT,
3793 static int ep_keygate[] =
3803 EL_GATE_1_GRAY_ACTIVE,
3804 EL_GATE_2_GRAY_ACTIVE,
3805 EL_GATE_3_GRAY_ACTIVE,
3806 EL_GATE_4_GRAY_ACTIVE,
3815 EL_EM_GATE_1_GRAY_ACTIVE,
3816 EL_EM_GATE_2_GRAY_ACTIVE,
3817 EL_EM_GATE_3_GRAY_ACTIVE,
3818 EL_EM_GATE_4_GRAY_ACTIVE,
3827 EL_EMC_GATE_5_GRAY_ACTIVE,
3828 EL_EMC_GATE_6_GRAY_ACTIVE,
3829 EL_EMC_GATE_7_GRAY_ACTIVE,
3830 EL_EMC_GATE_8_GRAY_ACTIVE,
3832 EL_DC_GATE_WHITE_GRAY,
3833 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3838 static int ep_amoeboid[] =
3850 static int ep_amoebalive[] =
3861 static int ep_has_editor_content[] =
3867 EL_SOKOBAN_FIELD_PLAYER,
3884 static int ep_can_turn_each_move[] =
3886 /* !!! do something with this one !!! */
3890 static int ep_can_grow[] =
3904 static int ep_active_bomb[] =
3907 EL_EM_DYNAMITE_ACTIVE,
3908 EL_DYNABOMB_PLAYER_1_ACTIVE,
3909 EL_DYNABOMB_PLAYER_2_ACTIVE,
3910 EL_DYNABOMB_PLAYER_3_ACTIVE,
3911 EL_DYNABOMB_PLAYER_4_ACTIVE,
3912 EL_SP_DISK_RED_ACTIVE,
3917 static int ep_inactive[] =
3927 EL_QUICKSAND_FAST_EMPTY,
3950 EL_GATE_1_GRAY_ACTIVE,
3951 EL_GATE_2_GRAY_ACTIVE,
3952 EL_GATE_3_GRAY_ACTIVE,
3953 EL_GATE_4_GRAY_ACTIVE,
3962 EL_EM_GATE_1_GRAY_ACTIVE,
3963 EL_EM_GATE_2_GRAY_ACTIVE,
3964 EL_EM_GATE_3_GRAY_ACTIVE,
3965 EL_EM_GATE_4_GRAY_ACTIVE,
3974 EL_EMC_GATE_5_GRAY_ACTIVE,
3975 EL_EMC_GATE_6_GRAY_ACTIVE,
3976 EL_EMC_GATE_7_GRAY_ACTIVE,
3977 EL_EMC_GATE_8_GRAY_ACTIVE,
3979 EL_DC_GATE_WHITE_GRAY,
3980 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3981 EL_DC_GATE_FAKE_GRAY,
3984 EL_INVISIBLE_STEELWALL,
3992 EL_WALL_EMERALD_YELLOW,
3993 EL_DYNABOMB_INCREASE_NUMBER,
3994 EL_DYNABOMB_INCREASE_SIZE,
3995 EL_DYNABOMB_INCREASE_POWER,
3999 EL_SOKOBAN_FIELD_EMPTY,
4000 EL_SOKOBAN_FIELD_FULL,
4001 EL_WALL_EMERALD_RED,
4002 EL_WALL_EMERALD_PURPLE,
4003 EL_ACID_POOL_TOPLEFT,
4004 EL_ACID_POOL_TOPRIGHT,
4005 EL_ACID_POOL_BOTTOMLEFT,
4006 EL_ACID_POOL_BOTTOM,
4007 EL_ACID_POOL_BOTTOMRIGHT,
4011 EL_BD_MAGIC_WALL_DEAD,
4013 EL_DC_MAGIC_WALL_DEAD,
4014 EL_AMOEBA_TO_DIAMOND,
4022 EL_SP_GRAVITY_PORT_RIGHT,
4023 EL_SP_GRAVITY_PORT_DOWN,
4024 EL_SP_GRAVITY_PORT_LEFT,
4025 EL_SP_GRAVITY_PORT_UP,
4026 EL_SP_PORT_HORIZONTAL,
4027 EL_SP_PORT_VERTICAL,
4038 EL_SP_HARDWARE_GRAY,
4039 EL_SP_HARDWARE_GREEN,
4040 EL_SP_HARDWARE_BLUE,
4042 EL_SP_HARDWARE_YELLOW,
4043 EL_SP_HARDWARE_BASE_1,
4044 EL_SP_HARDWARE_BASE_2,
4045 EL_SP_HARDWARE_BASE_3,
4046 EL_SP_HARDWARE_BASE_4,
4047 EL_SP_HARDWARE_BASE_5,
4048 EL_SP_HARDWARE_BASE_6,
4049 EL_SP_GRAVITY_ON_PORT_LEFT,
4050 EL_SP_GRAVITY_ON_PORT_RIGHT,
4051 EL_SP_GRAVITY_ON_PORT_UP,
4052 EL_SP_GRAVITY_ON_PORT_DOWN,
4053 EL_SP_GRAVITY_OFF_PORT_LEFT,
4054 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4055 EL_SP_GRAVITY_OFF_PORT_UP,
4056 EL_SP_GRAVITY_OFF_PORT_DOWN,
4057 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4058 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4059 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4060 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4061 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4062 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4063 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4064 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4065 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4066 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4067 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4068 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4069 EL_SIGN_EXCLAMATION,
4070 EL_SIGN_RADIOACTIVITY,
4077 EL_SIGN_ENTRY_FORBIDDEN,
4078 EL_SIGN_EMERGENCY_EXIT,
4086 EL_DC_STEELWALL_1_LEFT,
4087 EL_DC_STEELWALL_1_RIGHT,
4088 EL_DC_STEELWALL_1_TOP,
4089 EL_DC_STEELWALL_1_BOTTOM,
4090 EL_DC_STEELWALL_1_HORIZONTAL,
4091 EL_DC_STEELWALL_1_VERTICAL,
4092 EL_DC_STEELWALL_1_TOPLEFT,
4093 EL_DC_STEELWALL_1_TOPRIGHT,
4094 EL_DC_STEELWALL_1_BOTTOMLEFT,
4095 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4096 EL_DC_STEELWALL_1_TOPLEFT_2,
4097 EL_DC_STEELWALL_1_TOPRIGHT_2,
4098 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4099 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4100 EL_DC_STEELWALL_2_LEFT,
4101 EL_DC_STEELWALL_2_RIGHT,
4102 EL_DC_STEELWALL_2_TOP,
4103 EL_DC_STEELWALL_2_BOTTOM,
4104 EL_DC_STEELWALL_2_HORIZONTAL,
4105 EL_DC_STEELWALL_2_VERTICAL,
4106 EL_DC_STEELWALL_2_MIDDLE,
4107 EL_DC_STEELWALL_2_SINGLE,
4108 EL_STEELWALL_SLIPPERY,
4113 EL_EMC_WALL_SLIPPERY_1,
4114 EL_EMC_WALL_SLIPPERY_2,
4115 EL_EMC_WALL_SLIPPERY_3,
4116 EL_EMC_WALL_SLIPPERY_4,
4137 static int ep_em_slippery_wall[] =
4142 static int ep_gfx_crumbled[] =
4153 static int ep_editor_cascade_active[] =
4155 EL_INTERNAL_CASCADE_BD_ACTIVE,
4156 EL_INTERNAL_CASCADE_EM_ACTIVE,
4157 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4158 EL_INTERNAL_CASCADE_RND_ACTIVE,
4159 EL_INTERNAL_CASCADE_SB_ACTIVE,
4160 EL_INTERNAL_CASCADE_SP_ACTIVE,
4161 EL_INTERNAL_CASCADE_DC_ACTIVE,
4162 EL_INTERNAL_CASCADE_DX_ACTIVE,
4163 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4164 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4165 EL_INTERNAL_CASCADE_CE_ACTIVE,
4166 EL_INTERNAL_CASCADE_GE_ACTIVE,
4167 EL_INTERNAL_CASCADE_REF_ACTIVE,
4168 EL_INTERNAL_CASCADE_USER_ACTIVE,
4169 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4174 static int ep_editor_cascade_inactive[] =
4176 EL_INTERNAL_CASCADE_BD,
4177 EL_INTERNAL_CASCADE_EM,
4178 EL_INTERNAL_CASCADE_EMC,
4179 EL_INTERNAL_CASCADE_RND,
4180 EL_INTERNAL_CASCADE_SB,
4181 EL_INTERNAL_CASCADE_SP,
4182 EL_INTERNAL_CASCADE_DC,
4183 EL_INTERNAL_CASCADE_DX,
4184 EL_INTERNAL_CASCADE_CHARS,
4185 EL_INTERNAL_CASCADE_STEEL_CHARS,
4186 EL_INTERNAL_CASCADE_CE,
4187 EL_INTERNAL_CASCADE_GE,
4188 EL_INTERNAL_CASCADE_REF,
4189 EL_INTERNAL_CASCADE_USER,
4190 EL_INTERNAL_CASCADE_DYNAMIC,
4195 static int ep_obsolete[] =
4199 EL_EM_KEY_1_FILE_OBSOLETE,
4200 EL_EM_KEY_2_FILE_OBSOLETE,
4201 EL_EM_KEY_3_FILE_OBSOLETE,
4202 EL_EM_KEY_4_FILE_OBSOLETE,
4203 EL_ENVELOPE_OBSOLETE,
4212 } element_properties[] =
4214 { ep_diggable, EP_DIGGABLE },
4215 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4216 { ep_dont_run_into, EP_DONT_RUN_INTO },
4217 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4218 { ep_dont_touch, EP_DONT_TOUCH },
4219 { ep_indestructible, EP_INDESTRUCTIBLE },
4220 { ep_slippery, EP_SLIPPERY },
4221 { ep_can_change, EP_CAN_CHANGE },
4222 { ep_can_move, EP_CAN_MOVE },
4223 { ep_can_fall, EP_CAN_FALL },
4224 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4225 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4226 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4227 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4228 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4229 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4230 { ep_walkable_over, EP_WALKABLE_OVER },
4231 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4232 { ep_walkable_under, EP_WALKABLE_UNDER },
4233 { ep_passable_over, EP_PASSABLE_OVER },
4234 { ep_passable_inside, EP_PASSABLE_INSIDE },
4235 { ep_passable_under, EP_PASSABLE_UNDER },
4236 { ep_droppable, EP_DROPPABLE },
4237 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4238 { ep_pushable, EP_PUSHABLE },
4239 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4240 { ep_protected, EP_PROTECTED },
4241 { ep_throwable, EP_THROWABLE },
4242 { ep_can_explode, EP_CAN_EXPLODE },
4243 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4245 { ep_player, EP_PLAYER },
4246 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4247 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4248 { ep_switchable, EP_SWITCHABLE },
4249 { ep_bd_element, EP_BD_ELEMENT },
4250 { ep_sp_element, EP_SP_ELEMENT },
4251 { ep_sb_element, EP_SB_ELEMENT },
4253 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4254 { ep_food_penguin, EP_FOOD_PENGUIN },
4255 { ep_food_pig, EP_FOOD_PIG },
4256 { ep_historic_wall, EP_HISTORIC_WALL },
4257 { ep_historic_solid, EP_HISTORIC_SOLID },
4258 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4259 { ep_belt, EP_BELT },
4260 { ep_belt_active, EP_BELT_ACTIVE },
4261 { ep_belt_switch, EP_BELT_SWITCH },
4262 { ep_tube, EP_TUBE },
4263 { ep_acid_pool, EP_ACID_POOL },
4264 { ep_keygate, EP_KEYGATE },
4265 { ep_amoeboid, EP_AMOEBOID },
4266 { ep_amoebalive, EP_AMOEBALIVE },
4267 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4268 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4269 { ep_can_grow, EP_CAN_GROW },
4270 { ep_active_bomb, EP_ACTIVE_BOMB },
4271 { ep_inactive, EP_INACTIVE },
4273 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4275 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4277 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4278 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4280 { ep_obsolete, EP_OBSOLETE },
4287 /* always start with reliable default values (element has no properties) */
4288 /* (but never initialize clipboard elements after the very first time) */
4289 /* (to be able to use clipboard elements between several levels) */
4290 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4291 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4292 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4293 SET_PROPERTY(i, j, FALSE);
4295 /* set all base element properties from above array definitions */
4296 for (i = 0; element_properties[i].elements != NULL; i++)
4297 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4298 SET_PROPERTY((element_properties[i].elements)[j],
4299 element_properties[i].property, TRUE);
4301 /* copy properties to some elements that are only stored in level file */
4302 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4303 for (j = 0; copy_properties[j][0] != -1; j++)
4304 if (HAS_PROPERTY(copy_properties[j][0], i))
4305 for (k = 1; k <= 4; k++)
4306 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4308 /* set static element properties that are not listed in array definitions */
4309 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4310 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4312 clipboard_elements_initialized = TRUE;
4315 void InitElementPropertiesEngine(int engine_version)
4317 static int no_wall_properties[] =
4320 EP_COLLECTIBLE_ONLY,
4322 EP_DONT_COLLIDE_WITH,
4325 EP_CAN_SMASH_PLAYER,
4326 EP_CAN_SMASH_ENEMIES,
4327 EP_CAN_SMASH_EVERYTHING,
4332 EP_FOOD_DARK_YAMYAM,
4348 /* important: after initialization in InitElementPropertiesStatic(), the
4349 elements are not again initialized to a default value; therefore all
4350 changes have to make sure that they leave the element with a defined
4351 property (which means that conditional property changes must be set to
4352 a reliable default value before) */
4354 /* resolve group elements */
4355 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4356 ResolveGroupElement(EL_GROUP_START + i);
4358 /* set all special, combined or engine dependent element properties */
4359 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4361 /* do not change (already initialized) clipboard elements here */
4362 if (IS_CLIPBOARD_ELEMENT(i))
4365 /* ---------- INACTIVE ------------------------------------------------- */
4366 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4367 i <= EL_CHAR_END) ||
4368 (i >= EL_STEEL_CHAR_START &&
4369 i <= EL_STEEL_CHAR_END)));
4371 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4372 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4373 IS_WALKABLE_INSIDE(i) ||
4374 IS_WALKABLE_UNDER(i)));
4376 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4377 IS_PASSABLE_INSIDE(i) ||
4378 IS_PASSABLE_UNDER(i)));
4380 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4381 IS_PASSABLE_OVER(i)));
4383 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4384 IS_PASSABLE_INSIDE(i)));
4386 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4387 IS_PASSABLE_UNDER(i)));
4389 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4392 /* ---------- COLLECTIBLE ---------------------------------------------- */
4393 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4397 /* ---------- SNAPPABLE ------------------------------------------------ */
4398 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4399 IS_COLLECTIBLE(i) ||
4403 /* ---------- WALL ----------------------------------------------------- */
4404 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4406 for (j = 0; no_wall_properties[j] != -1; j++)
4407 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4408 i >= EL_FIRST_RUNTIME_UNREAL)
4409 SET_PROPERTY(i, EP_WALL, FALSE);
4411 if (IS_HISTORIC_WALL(i))
4412 SET_PROPERTY(i, EP_WALL, TRUE);
4414 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4415 if (engine_version < VERSION_IDENT(2,2,0,0))
4416 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4418 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4420 !IS_COLLECTIBLE(i)));
4422 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4423 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4424 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4426 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4427 IS_INDESTRUCTIBLE(i)));
4429 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4431 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4432 else if (engine_version < VERSION_IDENT(2,2,0,0))
4433 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4435 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4439 if (IS_CUSTOM_ELEMENT(i))
4441 /* these are additional properties which are initially false when set */
4443 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4445 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4446 if (DONT_COLLIDE_WITH(i))
4447 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4449 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4450 if (CAN_SMASH_EVERYTHING(i))
4451 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4452 if (CAN_SMASH_ENEMIES(i))
4453 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4456 /* ---------- CAN_SMASH ------------------------------------------------ */
4457 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4458 CAN_SMASH_ENEMIES(i) ||
4459 CAN_SMASH_EVERYTHING(i)));
4461 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4462 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4463 EXPLODES_BY_FIRE(i)));
4465 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4466 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4467 EXPLODES_SMASHED(i)));
4469 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4470 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4471 EXPLODES_IMPACT(i)));
4473 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4474 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4476 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4477 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4478 i == EL_BLACK_ORB));
4480 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4481 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4483 IS_CUSTOM_ELEMENT(i)));
4485 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4486 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4487 i == EL_SP_ELECTRON));
4489 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4490 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4491 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4492 getMoveIntoAcidProperty(&level, i));
4494 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4495 if (MAYBE_DONT_COLLIDE_WITH(i))
4496 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4497 getDontCollideWithProperty(&level, i));
4499 /* ---------- SP_PORT -------------------------------------------------- */
4500 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4501 IS_PASSABLE_INSIDE(i)));
4503 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4504 for (j = 0; j < level.num_android_clone_elements; j++)
4505 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4507 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4509 /* ---------- CAN_CHANGE ----------------------------------------------- */
4510 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4511 for (j = 0; j < element_info[i].num_change_pages; j++)
4512 if (element_info[i].change_page[j].can_change)
4513 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4515 /* ---------- HAS_ACTION ----------------------------------------------- */
4516 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4517 for (j = 0; j < element_info[i].num_change_pages; j++)
4518 if (element_info[i].change_page[j].has_action)
4519 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4521 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4522 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4525 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4526 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4527 element_info[i].crumbled[ACTION_DEFAULT] !=
4528 element_info[i].graphic[ACTION_DEFAULT]);
4530 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4531 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4532 IS_EDITOR_CASCADE_INACTIVE(i)));
4535 /* dynamically adjust element properties according to game engine version */
4537 static int ep_em_slippery_wall[] =
4542 EL_EXPANDABLE_WALL_HORIZONTAL,
4543 EL_EXPANDABLE_WALL_VERTICAL,
4544 EL_EXPANDABLE_WALL_ANY,
4545 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4546 EL_EXPANDABLE_STEELWALL_VERTICAL,
4547 EL_EXPANDABLE_STEELWALL_ANY,
4548 EL_EXPANDABLE_STEELWALL_GROWING,
4552 static int ep_em_explodes_by_fire[] =
4555 EL_EM_DYNAMITE_ACTIVE,
4560 /* special EM style gems behaviour */
4561 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4562 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4563 level.em_slippery_gems);
4565 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4566 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4567 (level.em_slippery_gems &&
4568 engine_version > VERSION_IDENT(2,0,1,0)));
4570 /* special EM style explosion behaviour regarding chain reactions */
4571 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4572 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4573 level.em_explodes_by_fire);
4576 /* this is needed because some graphics depend on element properties */
4577 if (game_status == GAME_MODE_PLAYING)
4578 InitElementGraphicInfo();
4581 void InitElementPropertiesAfterLoading(int engine_version)
4585 /* set some other uninitialized values of custom elements in older levels */
4586 if (engine_version < VERSION_IDENT(3,1,0,0))
4588 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4590 int element = EL_CUSTOM_START + i;
4592 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4594 element_info[element].explosion_delay = 17;
4595 element_info[element].ignition_delay = 8;
4600 void InitElementPropertiesGfxElement()
4604 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4606 struct ElementInfo *ei = &element_info[i];
4608 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4612 static void InitGlobal()
4617 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4619 /* check if element_name_info entry defined for each element in "main.h" */
4620 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4621 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4623 element_info[i].token_name = element_name_info[i].token_name;
4624 element_info[i].class_name = element_name_info[i].class_name;
4625 element_info[i].editor_description= element_name_info[i].editor_description;
4628 /* create hash from image config list */
4629 image_config_hash = newSetupFileHash();
4630 for (i = 0; image_config[i].token != NULL; i++)
4631 setHashEntry(image_config_hash,
4632 image_config[i].token,
4633 image_config[i].value);
4635 /* create hash from element token list */
4636 element_token_hash = newSetupFileHash();
4637 for (i = 0; element_name_info[i].token_name != NULL; i++)
4638 setHashEntry(element_token_hash,
4639 element_name_info[i].token_name,
4642 /* create hash from graphic token list */
4643 graphic_token_hash = newSetupFileHash();
4644 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4645 if (strSuffix(image_config[i].value, ".png") ||
4646 strSuffix(image_config[i].value, ".pcx") ||
4647 strSuffix(image_config[i].value, ".wav") ||
4648 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4649 setHashEntry(graphic_token_hash,
4650 image_config[i].token,
4651 int2str(graphic++, 0));
4653 /* create hash from font token list */
4654 font_token_hash = newSetupFileHash();
4655 for (i = 0; font_info[i].token_name != NULL; i++)
4656 setHashEntry(font_token_hash,
4657 font_info[i].token_name,
4660 /* set default filenames for all cloned graphics in static configuration */
4661 for (i = 0; image_config[i].token != NULL; i++)
4663 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4665 char *token = image_config[i].token;
4666 char *token_clone_from = getStringCat2(token, ".clone_from");
4667 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4669 if (token_cloned != NULL)
4671 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4673 if (value_cloned != NULL)
4675 /* set default filename in static configuration */
4676 image_config[i].value = value_cloned;
4678 /* set default filename in image config hash */
4679 setHashEntry(image_config_hash, token, value_cloned);
4683 free(token_clone_from);
4687 /* always start with reliable default values (all elements) */
4688 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4689 ActiveElement[i] = i;
4691 /* now add all entries that have an active state (active elements) */
4692 for (i = 0; element_with_active_state[i].element != -1; i++)
4694 int element = element_with_active_state[i].element;
4695 int element_active = element_with_active_state[i].element_active;
4697 ActiveElement[element] = element_active;
4700 /* always start with reliable default values (all buttons) */
4701 for (i = 0; i < NUM_IMAGE_FILES; i++)
4702 ActiveButton[i] = i;
4704 /* now add all entries that have an active state (active buttons) */
4705 for (i = 0; button_with_active_state[i].button != -1; i++)
4707 int button = button_with_active_state[i].button;
4708 int button_active = button_with_active_state[i].button_active;
4710 ActiveButton[button] = button_active;
4713 /* always start with reliable default values (all fonts) */
4714 for (i = 0; i < NUM_FONTS; i++)
4717 /* now add all entries that have an active state (active fonts) */
4718 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4720 int font = font_with_active_state[i].font_nr;
4721 int font_active = font_with_active_state[i].font_nr_active;
4723 ActiveFont[font] = font_active;
4726 global.autoplay_leveldir = NULL;
4727 global.convert_leveldir = NULL;
4728 global.create_images_dir = NULL;
4730 global.frames_per_second = 0;
4732 global.border_status = GAME_MODE_LOADING;
4733 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4735 global.use_envelope_request = FALSE;
4738 void Execute_Command(char *command)
4742 if (strEqual(command, "print graphicsinfo.conf"))
4744 Print("# You can configure additional/alternative image files here.\n");
4745 Print("# (The entries below are default and therefore commented out.)\n");
4747 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4749 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4752 for (i = 0; image_config[i].token != NULL; i++)
4753 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4754 image_config[i].value));
4758 else if (strEqual(command, "print soundsinfo.conf"))
4760 Print("# You can configure additional/alternative sound files here.\n");
4761 Print("# (The entries below are default and therefore commented out.)\n");
4763 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4765 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4768 for (i = 0; sound_config[i].token != NULL; i++)
4769 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4770 sound_config[i].value));
4774 else if (strEqual(command, "print musicinfo.conf"))
4776 Print("# You can configure additional/alternative music files here.\n");
4777 Print("# (The entries below are default and therefore commented out.)\n");
4779 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4781 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4784 for (i = 0; music_config[i].token != NULL; i++)
4785 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4786 music_config[i].value));
4790 else if (strEqual(command, "print editorsetup.conf"))
4792 Print("# You can configure your personal editor element list here.\n");
4793 Print("# (The entries below are default and therefore commented out.)\n");
4796 /* this is needed to be able to check element list for cascade elements */
4797 InitElementPropertiesStatic();
4798 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4800 PrintEditorElementList();
4804 else if (strEqual(command, "print helpanim.conf"))
4806 Print("# You can configure different element help animations here.\n");
4807 Print("# (The entries below are default and therefore commented out.)\n");
4810 for (i = 0; helpanim_config[i].token != NULL; i++)
4812 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4813 helpanim_config[i].value));
4815 if (strEqual(helpanim_config[i].token, "end"))
4821 else if (strEqual(command, "print helptext.conf"))
4823 Print("# You can configure different element help text here.\n");
4824 Print("# (The entries below are default and therefore commented out.)\n");
4827 for (i = 0; helptext_config[i].token != NULL; i++)
4828 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4829 helptext_config[i].value));
4833 else if (strPrefix(command, "dump level "))
4835 char *filename = &command[11];
4837 if (!fileExists(filename))
4838 Error(ERR_EXIT, "cannot open file '%s'", filename);
4840 LoadLevelFromFilename(&level, filename);
4845 else if (strPrefix(command, "dump tape "))
4847 char *filename = &command[10];
4849 if (!fileExists(filename))
4850 Error(ERR_EXIT, "cannot open file '%s'", filename);
4852 LoadTapeFromFilename(filename);
4857 else if (strPrefix(command, "autotest ") ||
4858 strPrefix(command, "autoplay ") ||
4859 strPrefix(command, "autoffwd "))
4861 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4863 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4864 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4865 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4867 while (*str_ptr != '\0') /* continue parsing string */
4869 /* cut leading whitespace from string, replace it by string terminator */
4870 while (*str_ptr == ' ' || *str_ptr == '\t')
4873 if (*str_ptr == '\0') /* end of string reached */
4876 if (global.autoplay_leveldir == NULL) /* read level set string */
4878 global.autoplay_leveldir = str_ptr;
4879 global.autoplay_all = TRUE; /* default: play all tapes */
4881 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4882 global.autoplay_level[i] = FALSE;
4884 else /* read level number string */
4886 int level_nr = atoi(str_ptr); /* get level_nr value */
4888 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4889 global.autoplay_level[level_nr] = TRUE;
4891 global.autoplay_all = FALSE;
4894 /* advance string pointer to the next whitespace (or end of string) */
4895 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4899 else if (strPrefix(command, "convert "))
4901 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4902 char *str_ptr = strchr(str_copy, ' ');
4904 global.convert_leveldir = str_copy;
4905 global.convert_level_nr = -1;
4907 if (str_ptr != NULL) /* level number follows */
4909 *str_ptr++ = '\0'; /* terminate leveldir string */
4910 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4913 else if (strPrefix(command, "create images "))
4915 global.create_images_dir = getStringCopy(&command[14]);
4917 if (access(global.create_images_dir, W_OK) != 0)
4918 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4919 global.create_images_dir);
4921 else if (strPrefix(command, "create CE image "))
4923 CreateCustomElementImages(&command[16]);
4929 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4933 static void InitSetup()
4935 LoadSetup(); /* global setup info */
4937 /* set some options from setup file */
4939 if (setup.options.verbose)
4940 options.verbose = TRUE;
4943 static void InitGameInfo()
4945 game.restart_level = FALSE;
4948 static void InitPlayerInfo()
4952 /* choose default local player */
4953 local_player = &stored_player[0];
4955 for (i = 0; i < MAX_PLAYERS; i++)
4956 stored_player[i].connected = FALSE;
4958 local_player->connected = TRUE;
4961 static void InitArtworkInfo()
4966 static char *get_string_in_brackets(char *string)
4968 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4970 sprintf(string_in_brackets, "[%s]", string);
4972 return string_in_brackets;
4975 static char *get_level_id_suffix(int id_nr)
4977 char *id_suffix = checked_malloc(1 + 3 + 1);
4979 if (id_nr < 0 || id_nr > 999)
4982 sprintf(id_suffix, ".%03d", id_nr);
4987 static void InitArtworkConfig()
4989 static char *image_id_prefix[MAX_NUM_ELEMENTS +
4991 NUM_GLOBAL_ANIM_TOKENS + 1];
4992 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
4993 NUM_GLOBAL_ANIM_TOKENS + 1];
4994 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4995 static char *action_id_suffix[NUM_ACTIONS + 1];
4996 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4997 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4998 static char *level_id_suffix[MAX_LEVELS + 1];
4999 static char *dummy[1] = { NULL };
5000 static char *ignore_generic_tokens[] =
5006 static char **ignore_image_tokens;
5007 static char **ignore_sound_tokens;
5008 static char **ignore_music_tokens;
5009 int num_ignore_generic_tokens;
5010 int num_ignore_image_tokens;
5011 int num_ignore_sound_tokens;
5012 int num_ignore_music_tokens;
5015 /* dynamically determine list of generic tokens to be ignored */
5016 num_ignore_generic_tokens = 0;
5017 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5018 num_ignore_generic_tokens++;
5020 /* dynamically determine list of image tokens to be ignored */
5021 num_ignore_image_tokens = num_ignore_generic_tokens;
5022 for (i = 0; image_config_vars[i].token != NULL; i++)
5023 num_ignore_image_tokens++;
5024 ignore_image_tokens =
5025 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5026 for (i = 0; i < num_ignore_generic_tokens; i++)
5027 ignore_image_tokens[i] = ignore_generic_tokens[i];
5028 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5029 ignore_image_tokens[num_ignore_generic_tokens + i] =
5030 image_config_vars[i].token;
5031 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5033 /* dynamically determine list of sound tokens to be ignored */
5034 num_ignore_sound_tokens = num_ignore_generic_tokens;
5035 ignore_sound_tokens =
5036 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5037 for (i = 0; i < num_ignore_generic_tokens; i++)
5038 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5039 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5041 /* dynamically determine list of music tokens to be ignored */
5042 num_ignore_music_tokens = num_ignore_generic_tokens;
5043 ignore_music_tokens =
5044 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5045 for (i = 0; i < num_ignore_generic_tokens; i++)
5046 ignore_music_tokens[i] = ignore_generic_tokens[i];
5047 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5049 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5050 image_id_prefix[i] = element_info[i].token_name;
5051 for (i = 0; i < NUM_FONTS; i++)
5052 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5053 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5054 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5055 global_anim_info[i].token_name;
5056 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5058 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5059 sound_id_prefix[i] = element_info[i].token_name;
5060 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5061 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5062 get_string_in_brackets(element_info[i].class_name);
5063 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5064 sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5065 global_anim_info[i].token_name;
5066 sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5068 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5069 music_id_prefix[i] = music_prefix_info[i].prefix;
5070 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5072 for (i = 0; i < NUM_ACTIONS; i++)
5073 action_id_suffix[i] = element_action_info[i].suffix;
5074 action_id_suffix[NUM_ACTIONS] = NULL;
5076 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5077 direction_id_suffix[i] = element_direction_info[i].suffix;
5078 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5080 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5081 special_id_suffix[i] = special_suffix_info[i].suffix;
5082 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5084 for (i = 0; i < MAX_LEVELS; i++)
5085 level_id_suffix[i] = get_level_id_suffix(i);
5086 level_id_suffix[MAX_LEVELS] = NULL;
5088 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5089 image_id_prefix, action_id_suffix, direction_id_suffix,
5090 special_id_suffix, ignore_image_tokens);
5091 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5092 sound_id_prefix, action_id_suffix, dummy,
5093 special_id_suffix, ignore_sound_tokens);
5094 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5095 music_id_prefix, special_id_suffix, level_id_suffix,
5096 dummy, ignore_music_tokens);
5099 static void InitMixer()
5106 void InitGfxBuffers()
5108 static int win_xsize_last = -1;
5109 static int win_ysize_last = -1;
5111 /* create additional image buffers for double-buffering and cross-fading */
5113 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5115 /* may contain content for cross-fading -- only re-create if changed */
5116 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5117 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5119 win_xsize_last = WIN_XSIZE;
5120 win_ysize_last = WIN_YSIZE;
5123 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5124 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5125 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5126 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5127 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5129 /* initialize screen properties */
5130 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5131 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5133 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5134 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5135 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5136 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5137 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5138 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5140 /* required if door size definitions have changed */
5141 InitGraphicCompatibilityInfo_Doors();
5143 InitGfxBuffers_EM();
5144 InitGfxBuffers_SP();
5149 struct GraphicInfo *graphic_info_last = graphic_info;
5150 char *filename_font_initial = NULL;
5151 char *filename_anim_initial = NULL;
5152 Bitmap *bitmap_font_initial = NULL;
5156 /* determine settings for initial font (for displaying startup messages) */
5157 for (i = 0; image_config[i].token != NULL; i++)
5159 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5161 char font_token[128];
5164 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5165 len_font_token = strlen(font_token);
5167 if (strEqual(image_config[i].token, font_token))
5168 filename_font_initial = image_config[i].value;
5169 else if (strlen(image_config[i].token) > len_font_token &&
5170 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5172 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5173 font_initial[j].src_x = atoi(image_config[i].value);
5174 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5175 font_initial[j].src_y = atoi(image_config[i].value);
5176 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5177 font_initial[j].width = atoi(image_config[i].value);
5178 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5179 font_initial[j].height = atoi(image_config[i].value);
5184 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5186 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5187 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5190 if (filename_font_initial == NULL) /* should not happen */
5191 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5194 InitGfxCustomArtworkInfo();
5195 InitGfxOtherSettings();
5197 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5199 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5200 font_initial[j].bitmap = bitmap_font_initial;
5202 InitFontGraphicInfo();
5204 font_height = getFontHeight(FC_RED);
5206 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5207 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5208 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5211 DrawInitText("Loading graphics", 120, FC_GREEN);
5213 /* initialize settings for busy animation with default values */
5214 int parameter[NUM_GFX_ARGS];
5215 for (i = 0; i < NUM_GFX_ARGS; i++)
5216 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5217 image_config_suffix[i].token,
5218 image_config_suffix[i].type);
5220 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5221 int len_anim_token = strlen(anim_token);
5223 /* read settings for busy animation from default custom artwork config */
5224 char *gfx_config_filename = getPath3(options.graphics_directory,
5226 GRAPHICSINFO_FILENAME);
5228 if (fileExists(gfx_config_filename))
5230 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5232 if (setup_file_hash)
5234 char *filename = getHashEntry(setup_file_hash, anim_token);
5238 filename_anim_initial = getStringCopy(filename);
5240 for (j = 0; image_config_suffix[j].token != NULL; j++)
5242 int type = image_config_suffix[j].type;
5243 char *suffix = image_config_suffix[j].token;
5244 char *token = getStringCat2(anim_token, suffix);
5245 char *value = getHashEntry(setup_file_hash, token);
5247 checked_free(token);
5250 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5254 freeSetupFileHash(setup_file_hash);
5258 if (filename_anim_initial == NULL)
5260 /* read settings for busy animation from static default artwork config */
5261 for (i = 0; image_config[i].token != NULL; i++)
5263 if (strEqual(image_config[i].token, anim_token))
5264 filename_anim_initial = getStringCopy(image_config[i].value);
5265 else if (strlen(image_config[i].token) > len_anim_token &&
5266 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5268 for (j = 0; image_config_suffix[j].token != NULL; j++)
5270 if (strEqual(&image_config[i].token[len_anim_token],
5271 image_config_suffix[j].token))
5273 get_graphic_parameter_value(image_config[i].value,
5274 image_config_suffix[j].token,
5275 image_config_suffix[j].type);
5281 if (filename_anim_initial == NULL) /* should not happen */
5282 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5284 anim_initial.bitmaps =
5285 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5287 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5288 LoadCustomImage(filename_anim_initial);
5290 checked_free(filename_anim_initial);
5292 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5294 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5296 graphic_info = graphic_info_last;
5298 init.busy.width = anim_initial.width;
5299 init.busy.height = anim_initial.height;
5301 InitMenuDesignSettings_Static();
5303 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5304 InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5305 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5307 gfx.fade_border_source_status = global.border_status;
5308 gfx.fade_border_target_status = global.border_status;
5309 gfx.masked_border_bitmap_ptr = backbuffer;
5311 /* use copy of busy animation to prevent change while reloading artwork */
5315 void InitGfxBackground()
5317 fieldbuffer = bitmap_db_field;
5318 SetDrawtoField(DRAW_BACKBUFFER);
5320 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5322 redraw_mask = REDRAW_ALL;
5325 static void InitLevelInfo()
5327 LoadLevelInfo(); /* global level info */
5328 LoadLevelSetup_LastSeries(); /* last played series info */
5329 LoadLevelSetup_SeriesInfo(); /* last played level info */
5331 if (global.autoplay_leveldir &&
5332 global.autoplay_mode != AUTOPLAY_TEST)
5334 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5335 global.autoplay_leveldir);
5336 if (leveldir_current == NULL)
5337 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5341 static void InitLevelArtworkInfo()
5343 LoadLevelArtworkInfo();
5346 static void InitImages()
5348 print_timestamp_init("InitImages");
5351 printf("::: leveldir_current->identifier == '%s'\n",
5352 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5353 printf("::: leveldir_current->graphics_path == '%s'\n",
5354 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5355 printf("::: leveldir_current->graphics_set == '%s'\n",
5356 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5357 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5358 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5361 setLevelArtworkDir(artwork.gfx_first);
5364 printf("::: leveldir_current->identifier == '%s'\n",
5365 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5366 printf("::: leveldir_current->graphics_path == '%s'\n",
5367 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5368 printf("::: leveldir_current->graphics_set == '%s'\n",
5369 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5370 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5371 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5375 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5376 leveldir_current->identifier,
5377 artwork.gfx_current_identifier,
5378 artwork.gfx_current->identifier,
5379 leveldir_current->graphics_set,
5380 leveldir_current->graphics_path);
5383 UPDATE_BUSY_STATE();
5385 ReloadCustomImages();
5386 print_timestamp_time("ReloadCustomImages");
5388 UPDATE_BUSY_STATE();
5390 LoadCustomElementDescriptions();
5391 print_timestamp_time("LoadCustomElementDescriptions");
5393 UPDATE_BUSY_STATE();
5395 LoadMenuDesignSettings();
5396 print_timestamp_time("LoadMenuDesignSettings");
5398 UPDATE_BUSY_STATE();
5400 ReinitializeGraphics();
5401 print_timestamp_time("ReinitializeGraphics");
5403 UPDATE_BUSY_STATE();
5405 print_timestamp_done("InitImages");
5408 static void InitSound(char *identifier)
5410 print_timestamp_init("InitSound");
5412 if (identifier == NULL)
5413 identifier = artwork.snd_current->identifier;
5415 /* set artwork path to send it to the sound server process */
5416 setLevelArtworkDir(artwork.snd_first);
5418 InitReloadCustomSounds(identifier);
5419 print_timestamp_time("InitReloadCustomSounds");
5421 ReinitializeSounds();
5422 print_timestamp_time("ReinitializeSounds");
5424 print_timestamp_done("InitSound");
5427 static void InitMusic(char *identifier)
5429 print_timestamp_init("InitMusic");
5431 if (identifier == NULL)
5432 identifier = artwork.mus_current->identifier;
5434 /* set artwork path to send it to the sound server process */
5435 setLevelArtworkDir(artwork.mus_first);
5437 InitReloadCustomMusic(identifier);
5438 print_timestamp_time("InitReloadCustomMusic");
5440 ReinitializeMusic();
5441 print_timestamp_time("ReinitializeMusic");
5443 print_timestamp_done("InitMusic");
5446 static void InitArtworkDone()
5448 InitGlobalAnimations();
5451 void InitNetworkServer()
5453 #if defined(NETWORK_AVALIABLE)
5457 if (!options.network)
5460 #if defined(NETWORK_AVALIABLE)
5461 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5463 if (!ConnectToServer(options.server_host, options.server_port))
5464 Error(ERR_EXIT, "cannot connect to network game server");
5466 SendToServer_PlayerName(setup.player_name);
5467 SendToServer_ProtocolVersion();
5470 SendToServer_NrWanted(nr_wanted);
5474 static boolean CheckArtworkConfigForCustomElements(char *filename)
5476 SetupFileHash *setup_file_hash;
5477 boolean redefined_ce_found = FALSE;
5479 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5481 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5483 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5485 char *token = HASH_ITERATION_TOKEN(itr);
5487 if (strPrefix(token, "custom_"))
5489 redefined_ce_found = TRUE;
5494 END_HASH_ITERATION(setup_file_hash, itr)
5496 freeSetupFileHash(setup_file_hash);
5499 return redefined_ce_found;
5502 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5504 char *filename_base, *filename_local;
5505 boolean redefined_ce_found = FALSE;
5507 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5510 printf("::: leveldir_current->identifier == '%s'\n",
5511 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5512 printf("::: leveldir_current->graphics_path == '%s'\n",
5513 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5514 printf("::: leveldir_current->graphics_set == '%s'\n",
5515 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5516 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5517 leveldir_current == NULL ? "[NULL]" :
5518 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5521 /* first look for special artwork configured in level series config */
5522 filename_base = getCustomArtworkLevelConfigFilename(type);
5525 printf("::: filename_base == '%s'\n", filename_base);
5528 if (fileExists(filename_base))
5529 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5531 filename_local = getCustomArtworkConfigFilename(type);
5534 printf("::: filename_local == '%s'\n", filename_local);
5537 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5538 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5541 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5544 return redefined_ce_found;
5547 static void InitOverrideArtwork()
5549 boolean redefined_ce_found = FALSE;
5551 /* to check if this level set redefines any CEs, do not use overriding */
5552 gfx.override_level_graphics = FALSE;
5553 gfx.override_level_sounds = FALSE;
5554 gfx.override_level_music = FALSE;
5556 /* now check if this level set has definitions for custom elements */
5557 if (setup.override_level_graphics == AUTO ||
5558 setup.override_level_sounds == AUTO ||
5559 setup.override_level_music == AUTO)
5560 redefined_ce_found =
5561 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5562 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5563 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5566 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5569 if (redefined_ce_found)
5571 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5572 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5573 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5574 gfx.override_level_music = (setup.override_level_music == TRUE);
5578 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5579 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5580 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5581 gfx.override_level_music = (setup.override_level_music != FALSE);
5585 printf("::: => %d, %d, %d\n",
5586 gfx.override_level_graphics,
5587 gfx.override_level_sounds,
5588 gfx.override_level_music);
5592 static char *getNewArtworkIdentifier(int type)
5594 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5595 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5596 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5597 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5598 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5599 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5600 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5601 char *leveldir_identifier = leveldir_current->identifier;
5602 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5603 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5604 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5605 char *artwork_current_identifier;
5606 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5608 /* leveldir_current may be invalid (level group, parent link) */
5609 if (!validLevelSeries(leveldir_current))
5612 /* 1st step: determine artwork set to be activated in descending order:
5613 --------------------------------------------------------------------
5614 1. setup artwork (when configured to override everything else)
5615 2. artwork set configured in "levelinfo.conf" of current level set
5616 (artwork in level directory will have priority when loading later)
5617 3. artwork in level directory (stored in artwork sub-directory)
5618 4. setup artwork (currently configured in setup menu) */
5620 if (setup_override_artwork)
5621 artwork_current_identifier = setup_artwork_set;
5622 else if (leveldir_artwork_set != NULL)
5623 artwork_current_identifier = leveldir_artwork_set;
5624 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5625 artwork_current_identifier = leveldir_identifier;
5627 artwork_current_identifier = setup_artwork_set;
5630 /* 2nd step: check if it is really needed to reload artwork set
5631 ------------------------------------------------------------ */
5633 /* ---------- reload if level set and also artwork set has changed ------- */
5634 if (leveldir_current_identifier[type] != leveldir_identifier &&
5635 (last_has_level_artwork_set[type] || has_level_artwork_set))
5636 artwork_new_identifier = artwork_current_identifier;
5638 leveldir_current_identifier[type] = leveldir_identifier;
5639 last_has_level_artwork_set[type] = has_level_artwork_set;
5641 /* ---------- reload if "override artwork" setting has changed ----------- */
5642 if (last_override_level_artwork[type] != setup_override_artwork)
5643 artwork_new_identifier = artwork_current_identifier;
5645 last_override_level_artwork[type] = setup_override_artwork;
5647 /* ---------- reload if current artwork identifier has changed ----------- */
5648 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5649 artwork_current_identifier))
5650 artwork_new_identifier = artwork_current_identifier;
5652 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5654 /* ---------- do not reload directly after starting ---------------------- */
5655 if (!initialized[type])
5656 artwork_new_identifier = NULL;
5658 initialized[type] = TRUE;
5660 return artwork_new_identifier;
5663 void ReloadCustomArtwork(int force_reload)
5665 int last_game_status = game_status; /* save current game status */
5666 char *gfx_new_identifier;
5667 char *snd_new_identifier;
5668 char *mus_new_identifier;
5669 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5670 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5671 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5672 boolean reload_needed;
5674 InitOverrideArtwork();
5676 force_reload_gfx |= AdjustGraphicsForEMC();
5678 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5679 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5680 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5682 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5683 snd_new_identifier != NULL || force_reload_snd ||
5684 mus_new_identifier != NULL || force_reload_mus);
5689 print_timestamp_init("ReloadCustomArtwork");
5691 SetGameStatus(GAME_MODE_LOADING);
5693 FadeOut(REDRAW_ALL);
5695 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5696 print_timestamp_time("ClearRectangle");
5700 if (gfx_new_identifier != NULL || force_reload_gfx)
5703 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5704 artwork.gfx_current_identifier,
5706 artwork.gfx_current->identifier,
5707 leveldir_current->graphics_set);
5711 print_timestamp_time("InitImages");
5714 if (snd_new_identifier != NULL || force_reload_snd)
5716 InitSound(snd_new_identifier);
5717 print_timestamp_time("InitSound");
5720 if (mus_new_identifier != NULL || force_reload_mus)
5722 InitMusic(mus_new_identifier);
5723 print_timestamp_time("InitMusic");
5728 SetGameStatus(last_game_status); /* restore current game status */
5730 init_last = init; /* switch to new busy animation */
5732 FadeOut(REDRAW_ALL);
5734 RedrawGlobalBorder();
5736 /* force redraw of (open or closed) door graphics */
5737 SetDoorState(DOOR_OPEN_ALL);
5738 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5740 FadeSetEnterScreen();
5741 FadeSkipNextFadeOut();
5743 print_timestamp_done("ReloadCustomArtwork");
5745 LimitScreenUpdates(FALSE);
5748 void KeyboardAutoRepeatOffUnlessAutoplay()
5750 if (global.autoplay_leveldir == NULL)
5751 KeyboardAutoRepeatOff();
5754 void DisplayExitMessage(char *format, va_list ap)
5756 // check if draw buffer and fonts for exit message are already available
5757 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5760 int font_1 = FC_RED;
5761 int font_2 = FC_YELLOW;
5762 int font_3 = FC_BLUE;
5763 int font_width = getFontWidth(font_2);
5764 int font_height = getFontHeight(font_2);
5767 int sxsize = WIN_XSIZE - 2 * sx;
5768 int sysize = WIN_YSIZE - 2 * sy;
5769 int line_length = sxsize / font_width;
5770 int max_lines = sysize / font_height;
5771 int num_lines_printed;
5775 gfx.sxsize = sxsize;
5776 gfx.sysize = sysize;
5780 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5782 DrawTextSCentered(sy, font_1, "Fatal error:");
5783 sy += 3 * font_height;;
5786 DrawTextBufferVA(sx, sy, format, ap, font_2,
5787 line_length, line_length, max_lines,
5788 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5789 sy += (num_lines_printed + 3) * font_height;
5791 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5792 sy += 3 * font_height;
5795 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5796 line_length, line_length, max_lines,
5797 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5799 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5801 redraw_mask = REDRAW_ALL;
5803 /* force drawing exit message even if screen updates are currently limited */
5804 LimitScreenUpdates(FALSE);
5808 /* deactivate toons on error message screen */
5809 setup.toons = FALSE;
5811 WaitForEventToContinue();
5815 /* ========================================================================= */
5817 /* ========================================================================= */
5821 print_timestamp_init("OpenAll");
5823 SetGameStatus(GAME_MODE_LOADING);
5827 InitGlobal(); /* initialize some global variables */
5829 print_timestamp_time("[init global stuff]");
5833 print_timestamp_time("[init setup/config stuff (1)]");
5835 if (options.execute_command)
5836 Execute_Command(options.execute_command);
5838 if (options.serveronly)
5840 #if defined(PLATFORM_UNIX)
5841 NetworkServer(options.server_port, options.serveronly);
5843 Error(ERR_WARN, "networking only supported in Unix version");
5846 exit(0); /* never reached, server loops forever */
5850 print_timestamp_time("[init setup/config stuff (2)]");
5852 print_timestamp_time("[init setup/config stuff (3)]");
5853 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5854 print_timestamp_time("[init setup/config stuff (4)]");
5855 InitArtworkConfig(); /* needed before forking sound child process */
5856 print_timestamp_time("[init setup/config stuff (5)]");
5858 print_timestamp_time("[init setup/config stuff (6)]");
5860 InitRND(NEW_RANDOMIZE);
5861 InitSimpleRandom(NEW_RANDOMIZE);
5865 print_timestamp_time("[init setup/config stuff]");
5868 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5870 InitEventFilter(FilterEvents);
5872 print_timestamp_time("[init video stuff]");
5874 InitElementPropertiesStatic();
5875 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5876 InitElementPropertiesGfxElement();
5878 print_timestamp_time("[init element properties stuff]");
5882 print_timestamp_time("InitGfx");
5885 print_timestamp_time("InitLevelInfo");
5887 InitLevelArtworkInfo();
5888 print_timestamp_time("InitLevelArtworkInfo");
5890 InitOverrideArtwork(); /* needs to know current level directory */
5891 print_timestamp_time("InitOverrideArtwork");
5893 InitImages(); /* needs to know current level directory */
5894 print_timestamp_time("InitImages");
5896 InitSound(NULL); /* needs to know current level directory */
5897 print_timestamp_time("InitSound");
5899 InitMusic(NULL); /* needs to know current level directory */
5900 print_timestamp_time("InitMusic");
5904 InitGfxBackground();
5909 if (global.autoplay_leveldir)
5914 else if (global.convert_leveldir)
5919 else if (global.create_images_dir)
5921 CreateLevelSketchImages();
5925 SetGameStatus(GAME_MODE_MAIN);
5927 FadeSetEnterScreen();
5928 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5929 FadeSkipNextFadeOut();
5931 print_timestamp_time("[post-artwork]");
5933 print_timestamp_done("OpenAll");
5937 InitNetworkServer();
5940 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5942 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5943 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5944 #if defined(PLATFORM_ANDROID)
5945 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5946 SDL_AndroidGetInternalStoragePath());
5947 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5948 SDL_AndroidGetExternalStoragePath());
5949 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5950 (SDL_AndroidGetExternalStorageState() ==
5951 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5952 SDL_AndroidGetExternalStorageState() ==
5953 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5958 void CloseAllAndExit(int exit_value)
5963 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5970 #if defined(TARGET_SDL)
5971 #if defined(TARGET_SDL2)
5973 // set a flag to tell the network server thread to quit and wait for it
5974 // using SDL_WaitThread()
5976 if (network_server) /* terminate network server */
5977 SDL_KillThread(server_thread);
5981 CloseVideoDisplay();
5982 ClosePlatformDependentStuff();
5984 if (exit_value != 0)
5986 /* fall back to default level set (current set may have caused an error) */
5987 SaveLevelSetup_LastSeries_Deactivate();
5989 /* tell user where to find error log file which may contain more details */
5990 // (error notification now directly displayed on screen inside R'n'D
5991 // NotifyUserAboutErrorFile(); /* currently only works for Windows */