+ {
+ if (direction > -1)
+ element_info[element].direction_graphic[action][direction] = graphic;
+ else
+ element_info[element].graphic[action] = graphic;
+ }
+ }
+
+ /* initialize normal element/graphic mapping from dynamic configuration */
+ for (i = 0; i < num_property_mappings; i++)
+ {
+ int element = property_mapping[i].base_index;
+ int action = property_mapping[i].ext1_index;
+ int direction = property_mapping[i].ext2_index;
+ int special = property_mapping[i].ext3_index;
+ int graphic = property_mapping[i].artwork_index;
+ boolean crumbled = FALSE;
+
+#if 0
+ if ((element == EL_EM_DYNAMITE ||
+ element == EL_EM_DYNAMITE_ACTIVE) &&
+ action == ACTION_ACTIVE &&
+ (special == GFX_SPECIAL_ARG_EDITOR ||
+ special == GFX_SPECIAL_ARG_PANEL))
+ printf("::: DYNAMIC: %d, %d, %d -> %d\n",
+ element, action, special, graphic);
+#endif
+
+ if (special == GFX_SPECIAL_ARG_CRUMBLED)
+ {
+ special = -1;
+ crumbled = TRUE;
+ }
+
+ if (graphic_info[graphic].bitmap == NULL)
+ continue;
+
+ if (element >= MAX_NUM_ELEMENTS || special != -1)
+ continue;
+
+ if (action < 0)
+ action = ACTION_DEFAULT;
+
+ if (crumbled)
+ {
+ if (direction < 0)
+ for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
+ element_info[element].direction_crumbled[action][dir] = -1;
+
+ if (direction > -1)
+ element_info[element].direction_crumbled[action][direction] = graphic;
+ else
+ element_info[element].crumbled[action] = graphic;
+ }
+ else
+ {
+ if (direction < 0)
+ for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
+ element_info[element].direction_graphic[action][dir] = -1;
+
+ if (direction > -1)
+ element_info[element].direction_graphic[action][direction] = graphic;
+ else
+ element_info[element].graphic[action] = graphic;
+ }
+ }
+
+ /* now copy all graphics that are defined to be cloned from other graphics */
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ {
+ int graphic = element_info[i].graphic[ACTION_DEFAULT];
+ int crumbled_like, diggable_like;
+
+ if (graphic == -1)
+ continue;
+
+ crumbled_like = graphic_info[graphic].crumbled_like;
+ diggable_like = graphic_info[graphic].diggable_like;
+
+ if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
+ {
+ for (act = 0; act < NUM_ACTIONS; act++)
+ element_info[i].crumbled[act] =
+ element_info[crumbled_like].crumbled[act];
+ for (act = 0; act < NUM_ACTIONS; act++)
+ for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
+ element_info[i].direction_crumbled[act][dir] =
+ element_info[crumbled_like].direction_crumbled[act][dir];
+ }
+
+ if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
+ {
+ element_info[i].graphic[ACTION_DIGGING] =
+ element_info[diggable_like].graphic[ACTION_DIGGING];
+ for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
+ element_info[i].direction_graphic[ACTION_DIGGING][dir] =
+ element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
+ }
+ }
+
+#if 1
+ /* set hardcoded definitions for some runtime elements without graphic */
+ element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
+#endif
+
+#if 1
+ /* set hardcoded definitions for some internal elements without graphic */
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ {
+ if (IS_EDITOR_CASCADE_INACTIVE(i))
+ element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
+ else if (IS_EDITOR_CASCADE_ACTIVE(i))
+ element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
+ }
+#endif
+
+ /* now set all undefined/invalid graphics to -1 to set to default after it */
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ {
+ for (act = 0; act < NUM_ACTIONS; act++)
+ {
+ int graphic;
+
+ graphic = element_info[i].graphic[act];
+ if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
+ element_info[i].graphic[act] = -1;
+
+ graphic = element_info[i].crumbled[act];
+ if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
+ element_info[i].crumbled[act] = -1;
+
+ for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
+ {
+ graphic = element_info[i].direction_graphic[act][dir];
+ if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
+ element_info[i].direction_graphic[act][dir] = -1;
+
+ graphic = element_info[i].direction_crumbled[act][dir];
+ if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
+ element_info[i].direction_crumbled[act][dir] = -1;
+ }
+ }
+ }
+
+ UPDATE_BUSY_STATE();
+
+ /* adjust graphics with 2nd tile for movement according to direction
+ (do this before correcting '-1' values to minimize calculations) */
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ {
+ for (act = 0; act < NUM_ACTIONS; act++)
+ {
+ for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
+ {
+ int graphic = element_info[i].direction_graphic[act][dir];
+ int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
+
+ if (act == ACTION_FALLING) /* special case */
+ graphic = element_info[i].graphic[act];
+
+ if (graphic != -1 &&
+ graphic_info[graphic].double_movement &&
+ graphic_info[graphic].swap_double_tiles != 0)
+ {
+ struct GraphicInfo *g = &graphic_info[graphic];
+ int src_x_front = g->src_x;
+ int src_y_front = g->src_y;
+ int src_x_back = g->src_x + g->offset2_x;
+ int src_y_back = g->src_y + g->offset2_y;
+ boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
+ g->offset_y != 0);
+ boolean front_is_left_or_upper = (src_x_front < src_x_back ||
+ src_y_front < src_y_back);
+ boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
+ boolean swap_movement_tiles_autodetected =
+ (!frames_are_ordered_diagonally &&
+ ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
+ (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
+ (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
+ (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
+ Bitmap *dummy;
+
+ /* swap frontside and backside graphic tile coordinates, if needed */
+ if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
+ {
+ /* get current (wrong) backside tile coordinates */
+ getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
+ TRUE);
+
+ /* set frontside tile coordinates to backside tile coordinates */
+ g->src_x = src_x_back;
+ g->src_y = src_y_back;
+
+ /* invert tile offset to point to new backside tile coordinates */
+ g->offset2_x *= -1;
+ g->offset2_y *= -1;
+
+ /* do not swap front and backside tiles again after correction */
+ g->swap_double_tiles = 0;
+ }
+ }
+ }
+ }
+ }
+
+ UPDATE_BUSY_STATE();
+
+ /* now set all '-1' values to element specific default values */
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ {
+ int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
+ int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
+ int default_direction_graphic[NUM_DIRECTIONS_FULL];
+ int default_direction_crumbled[NUM_DIRECTIONS_FULL];
+
+ if (default_graphic == -1)
+ default_graphic = IMG_UNKNOWN;
+#if 1
+ if (default_crumbled == -1)
+ default_crumbled = default_graphic;
+#else
+ /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
+ if (default_crumbled == -1)
+ default_crumbled = IMG_EMPTY;
+#endif
+
+ for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
+ {
+ default_direction_graphic[dir] =
+ element_info[i].direction_graphic[ACTION_DEFAULT][dir];
+ default_direction_crumbled[dir] =
+ element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
+
+ if (default_direction_graphic[dir] == -1)
+ default_direction_graphic[dir] = default_graphic;
+#if 1
+ if (default_direction_crumbled[dir] == -1)
+ default_direction_crumbled[dir] = default_direction_graphic[dir];
+#else
+ /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
+ if (default_direction_crumbled[dir] == -1)
+ default_direction_crumbled[dir] = default_crumbled;
+#endif
+ }
+
+ for (act = 0; act < NUM_ACTIONS; act++)
+ {
+ boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
+ (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
+ (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
+ boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
+ act == ACTION_TURNING_FROM_RIGHT ||
+ act == ACTION_TURNING_FROM_UP ||
+ act == ACTION_TURNING_FROM_DOWN);
+
+ /* generic default action graphic (defined by "[default]" directive) */
+ int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
+ int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
+ int default_remove_graphic = IMG_EMPTY;
+
+ if (act_remove && default_action_graphic != -1)
+ default_remove_graphic = default_action_graphic;
+
+ /* look for special default action graphic (classic game specific) */
+ if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
+ default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
+ if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
+ default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
+ if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
+ default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
+
+ if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
+ default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
+ if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
+ default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
+ if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
+ default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
+
+#if 1
+ /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
+ /* !!! make this better !!! */
+ if (i == EL_EMPTY_SPACE)
+ {
+ default_action_graphic = element_info[EL_DEFAULT].graphic[act];
+ default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
+ }
+#endif
+
+ if (default_action_graphic == -1)
+ default_action_graphic = default_graphic;
+#if 1
+ if (default_action_crumbled == -1)
+ default_action_crumbled = default_action_graphic;
+#else
+ /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
+ if (default_action_crumbled == -1)
+ default_action_crumbled = default_crumbled;
+#endif
+
+ for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
+ {
+ /* use action graphic as the default direction graphic, if undefined */
+ int default_action_direction_graphic = element_info[i].graphic[act];
+ int default_action_direction_crumbled = element_info[i].crumbled[act];
+
+ /* no graphic for current action -- use default direction graphic */
+ if (default_action_direction_graphic == -1)
+ default_action_direction_graphic =
+ (act_remove ? default_remove_graphic :
+ act_turning ?
+ element_info[i].direction_graphic[ACTION_TURNING][dir] :
+ default_action_graphic != default_graphic ?
+ default_action_graphic :
+ default_direction_graphic[dir]);
+
+ if (element_info[i].direction_graphic[act][dir] == -1)
+ element_info[i].direction_graphic[act][dir] =
+ default_action_direction_graphic;
+
+#if 1
+ if (default_action_direction_crumbled == -1)
+ default_action_direction_crumbled =
+ element_info[i].direction_graphic[act][dir];
+#else
+ if (default_action_direction_crumbled == -1)
+ default_action_direction_crumbled =
+ (act_remove ? default_remove_graphic :
+ act_turning ?
+ element_info[i].direction_crumbled[ACTION_TURNING][dir] :
+ default_action_crumbled != default_crumbled ?
+ default_action_crumbled :
+ default_direction_crumbled[dir]);
+#endif
+
+ if (element_info[i].direction_crumbled[act][dir] == -1)
+ element_info[i].direction_crumbled[act][dir] =
+ default_action_direction_crumbled;
+ }
+
+ /* no graphic for this specific action -- use default action graphic */
+ if (element_info[i].graphic[act] == -1)
+ element_info[i].graphic[act] =
+ (act_remove ? default_remove_graphic :
+ act_turning ? element_info[i].graphic[ACTION_TURNING] :
+ default_action_graphic);
+#if 1
+ if (element_info[i].crumbled[act] == -1)
+ element_info[i].crumbled[act] = element_info[i].graphic[act];
+#else
+ if (element_info[i].crumbled[act] == -1)
+ element_info[i].crumbled[act] =
+ (act_remove ? default_remove_graphic :
+ act_turning ? element_info[i].crumbled[ACTION_TURNING] :
+ default_action_crumbled);
+#endif
+ }
+ }
+
+ UPDATE_BUSY_STATE();
+
+#if 0
+ /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
+ /* set animation mode to "none" for each graphic with only 1 frame */
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ {
+ for (act = 0; act < NUM_ACTIONS; act++)
+ {
+ int graphic = element_info[i].graphic[act];
+ int crumbled = element_info[i].crumbled[act];
+
+ if (graphic_info[graphic].anim_frames == 1)
+ graphic_info[graphic].anim_mode = ANIM_NONE;
+ if (graphic_info[crumbled].anim_frames == 1)
+ graphic_info[crumbled].anim_mode = ANIM_NONE;
+
+ for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
+ {
+ graphic = element_info[i].direction_graphic[act][dir];
+ crumbled = element_info[i].direction_crumbled[act][dir];
+
+ if (graphic_info[graphic].anim_frames == 1)
+ graphic_info[graphic].anim_mode = ANIM_NONE;
+ if (graphic_info[crumbled].anim_frames == 1)
+ graphic_info[crumbled].anim_mode = ANIM_NONE;
+ }
+ }
+ }
+#endif
+
+#if 0
+#if DEBUG
+ if (options.verbose)
+ {
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
+ i != EL_UNKNOWN)
+ Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
+ element_info[i].token_name, i);