Add NewGRF object property for new edge foundation mode

This commit is contained in:
Jonathan G Rennison
2021-12-05 18:05:58 +00:00
parent 2c8b462708
commit d9116106ca
8 changed files with 68 additions and 14 deletions

View File

@@ -4301,6 +4301,14 @@ static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, const G
SB(spec->ctrl_flags, OBJECT_CTRL_FLAG_USE_LAND_GROUND, 1, (buf->ReadByte() != 0 ? 1 : 0)); SB(spec->ctrl_flags, OBJECT_CTRL_FLAG_USE_LAND_GROUND, 1, (buf->ReadByte() != 0 ? 1 : 0));
break; break;
case A0RPI_OBJECT_EDGE_FOUNDATION_MODE:
if (MappedPropertyLengthMismatch(buf, 4, mapping_entry)) break;
SetBit(spec->ctrl_flags, OBJECT_CTRL_FLAG_EDGE_FOUNDATION);
for (int i = 0; i < 4; i++) {
spec->edge_foundation[i] = buf->ReadByte();
}
break;
default: default:
ret = HandleAction0PropertyDefault(buf, prop); ret = HandleAction0PropertyDefault(buf, prop);
break; break;

View File

@@ -68,6 +68,7 @@ extern const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = {
GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_ENABLE_SIGNAL_RECOLOUR, "signals_enable_signal_recolour"), GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_ENABLE_SIGNAL_RECOLOUR, "signals_enable_signal_recolour"),
GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_EXTRA_ASPECTS, "signals_extra_aspects"), GRFPropertyMapDefinition(GSF_SIGNALS, A0RPI_SIGNALS_EXTRA_ASPECTS, "signals_extra_aspects"),
GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_USE_LAND_GROUND, "object_use_land_ground"), GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_USE_LAND_GROUND, "object_use_land_ground"),
GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_EDGE_FOUNDATION_MODE, "object_edge_foundation_mode"),
GRFPropertyMapDefinition(), GRFPropertyMapDefinition(),
}; };

View File

@@ -33,6 +33,7 @@ enum Action0RemapPropertyIds {
A0RPI_SIGNALS_ENABLE_SIGNAL_RECOLOUR, A0RPI_SIGNALS_ENABLE_SIGNAL_RECOLOUR,
A0RPI_SIGNALS_EXTRA_ASPECTS, A0RPI_SIGNALS_EXTRA_ASPECTS,
A0RPI_OBJECT_USE_LAND_GROUND, A0RPI_OBJECT_USE_LAND_GROUND,
A0RPI_OBJECT_EDGE_FOUNDATION_MODE,
}; };

View File

@@ -418,7 +418,7 @@ uint16 GetObjectCallback(CallbackID callback, uint32 param1, uint32 param2, cons
* @param group The group of sprites to draw. * @param group The group of sprites to draw.
* @param spec Object spec to draw. * @param spec Object spec to draw.
*/ */
static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, const ObjectSpec *spec) static void DrawTileLayout(TileInfo *ti, const TileLayoutSpriteGroup *group, const ObjectSpec *spec, int building_z_offset)
{ {
const DrawTileSprites *dts = group->ProcessRegisters(nullptr); const DrawTileSprites *dts = group->ProcessRegisters(nullptr);
PaletteID palette = ((spec->flags & OBJECT_FLAG_2CC_COLOUR) ? SPR_2CCMAP_BASE : PALETTE_RECOLOUR_START) + Object::GetByTile(ti->tile)->colour; PaletteID palette = ((spec->flags & OBJECT_FLAG_2CC_COLOUR) ? SPR_2CCMAP_BASE : PALETTE_RECOLOUR_START) + Object::GetByTile(ti->tile)->colour;
@@ -455,7 +455,9 @@ static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *grou
} }
} }
if (building_z_offset) ti->z += building_z_offset;
DrawNewGRFTileSeq(ti, dts, TO_STRUCTURES, 0, palette); DrawNewGRFTileSeq(ti, dts, TO_STRUCTURES, 0, palette);
if (building_z_offset) ti->z -= building_z_offset;
} }
/** /**
@@ -463,7 +465,7 @@ static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *grou
* @param ti Information about the tile to draw on. * @param ti Information about the tile to draw on.
* @param spec Object spec to draw. * @param spec Object spec to draw.
*/ */
void DrawNewObjectTile(TileInfo *ti, const ObjectSpec *spec) void DrawNewObjectTile(TileInfo *ti, const ObjectSpec *spec, int building_z_offset)
{ {
Object *o = Object::GetByTile(ti->tile); Object *o = Object::GetByTile(ti->tile);
ObjectResolverObject object(spec, o, ti->tile); ObjectResolverObject object(spec, o, ti->tile);
@@ -471,7 +473,7 @@ void DrawNewObjectTile(TileInfo *ti, const ObjectSpec *spec)
const SpriteGroup *group = object.Resolve(); const SpriteGroup *group = object.Resolve();
if (group == nullptr || group->type != SGT_TILELAYOUT) return; if (group == nullptr || group->type != SGT_TILELAYOUT) return;
DrawTileLayout(ti, (const TileLayoutSpriteGroup *)group, spec); DrawTileLayout(ti, (const TileLayoutSpriteGroup *)group, spec, building_z_offset);
} }
/** /**

View File

@@ -43,9 +43,17 @@ DECLARE_ENUM_AS_BIT_SET(ObjectFlags)
enum ObjectCtrlFlags { enum ObjectCtrlFlags {
OBJECT_CTRL_FLAG_NONE = 0, ///< Just nothing. OBJECT_CTRL_FLAG_NONE = 0, ///< Just nothing.
OBJECT_CTRL_FLAG_USE_LAND_GROUND = 1 << 0, ///< Use land for ground sprite. OBJECT_CTRL_FLAG_USE_LAND_GROUND = 1 << 0, ///< Use land for ground sprite.
OBJECT_CTRL_FLAG_EDGE_FOUNDATION = 1 << 2, ///< Use edge foundation mode.
}; };
DECLARE_ENUM_AS_BIT_SET(ObjectCtrlFlags) DECLARE_ENUM_AS_BIT_SET(ObjectCtrlFlags)
enum ObjectEdgeFoundationFlags {
/* Bits 0 and 1 use for edge DiagDirection */
OBJECT_EF_FLAG_ADJUST_Z = 1 << 2, ///< Adjust sprite z position to z at edge.
OBJECT_EF_FLAG_FOUNDATION_LOWER = 1 << 3, ///< If edge is lower than tile max z, add foundation.
};
DECLARE_ENUM_AS_BIT_SET(ObjectEdgeFoundationFlags)
void ResetObjects(); void ResetObjects();
/** Class IDs for objects. */ /** Class IDs for objects. */
@@ -75,6 +83,7 @@ struct ObjectSpec {
Date end_of_life_date; ///< When can't this object be built anymore. Date end_of_life_date; ///< When can't this object be built anymore.
ObjectFlags flags; ///< Flags/settings related to the object. ObjectFlags flags; ///< Flags/settings related to the object.
ObjectCtrlFlags ctrl_flags; ///< Extra control flags. ObjectCtrlFlags ctrl_flags; ///< Extra control flags.
uint8 edge_foundation[4]; ///< Edge foundation flags
AnimationInfo animation; ///< Information about the animation. AnimationInfo animation; ///< Information about the animation.
uint16 callback_mask; ///< Bitmask of requested/allowed callbacks. uint16 callback_mask; ///< Bitmask of requested/allowed callbacks.
uint8 height; ///< The height of this structure, in heightlevels; max MAX_TILE_HEIGHT. uint8 height; ///< The height of this structure, in heightlevels; max MAX_TILE_HEIGHT.
@@ -167,7 +176,7 @@ static const CargoID CT_PURCHASE_OBJECT = 1;
uint16 GetObjectCallback(CallbackID callback, uint32 param1, uint32 param2, const ObjectSpec *spec, Object *o, TileIndex tile, uint8 view = 0); uint16 GetObjectCallback(CallbackID callback, uint32 param1, uint32 param2, const ObjectSpec *spec, Object *o, TileIndex tile, uint8 view = 0);
void DrawNewObjectTile(TileInfo *ti, const ObjectSpec *spec); void DrawNewObjectTile(TileInfo *ti, const ObjectSpec *spec, int building_z_offset);
void DrawNewObjectTileInGUI(int x, int y, const ObjectSpec *spec, uint8 view); void DrawNewObjectTileInGUI(int x, int y, const ObjectSpec *spec, uint8 view);
void AnimateNewObjectTile(TileIndex tile); void AnimateNewObjectTile(TileIndex tile);
uint8 GetNewObjectTileAnimationSpeed(TileIndex tile); uint8 GetNewObjectTileAnimationSpeed(TileIndex tile);

View File

@@ -517,13 +517,34 @@ static Foundation GetFoundation_Object(TileIndex tile, Slope tileh);
static void DrawTile_Object(TileInfo *ti, DrawTileProcParams params) static void DrawTile_Object(TileInfo *ti, DrawTileProcParams params)
{ {
ObjectType type = GetObjectType(ti->tile); const Object *obj = Object::GetByTile(ti->tile);
ObjectType type = obj->type;
const ObjectSpec *spec = ObjectSpec::Get(type); const ObjectSpec *spec = ObjectSpec::Get(type);
/* Fall back for when the object doesn't exist anymore. */ int building_z_offset = 0;
if (!spec->enabled) type = OBJECT_TRANSMITTER;
if ((spec->flags & OBJECT_FLAG_HAS_NO_FOUNDATION) == 0) DrawFoundation(ti, GetFoundation_Object(ti->tile, ti->tileh)); /* Fall back for when the object doesn't exist anymore. */
if (!spec->enabled) {
type = OBJECT_TRANSMITTER;
} else if ((spec->flags & OBJECT_FLAG_HAS_NO_FOUNDATION) == 0) {
if (spec->ctrl_flags & OBJECT_CTRL_FLAG_EDGE_FOUNDATION) {
uint8 flags = spec->edge_foundation[obj->view];
DiagDirection edge = (DiagDirection)GB(flags, 0, 2);
Slope incline = InclinedSlope(edge);
if (IsSteepSlope(ti->tileh) || IsOddParity(incline & ti->tileh)) {
/* Steep slope, or odd number of matching bits indicating that edge is not level */
DrawFoundation(ti, GetFoundation_Object(ti->tile, ti->tileh));
} else if (flags & OBJECT_EF_FLAG_FOUNDATION_LOWER && !(ti->tileh & incline)) {
/* The edge is the lower edge of an inclined slope */
DrawFoundation(ti, GetFoundation_Object(ti->tile, ti->tileh));
} else if (flags & OBJECT_EF_FLAG_ADJUST_Z && ti->tileh & incline) {
/* The edge is elevated relative to the lowest tile height, adjust z */
building_z_offset = TILE_HEIGHT;
}
} else {
DrawFoundation(ti, GetFoundation_Object(ti->tile, ti->tileh));
}
}
if (type < NEW_OBJECT_OFFSET) { if (type < NEW_OBJECT_OFFSET) {
const DrawTileSprites *dts = nullptr; const DrawTileSprites *dts = nullptr;
@@ -564,7 +585,7 @@ static void DrawTile_Object(TileInfo *ti, DrawTileProcParams params)
} }
} }
} else { } else {
DrawNewObjectTile(ti, spec); DrawNewObjectTile(ti, spec, building_z_offset);
} }
DrawBridgeMiddle(ti); DrawBridgeMiddle(ti);
@@ -1065,6 +1086,16 @@ static void ChangeTileOwner_Object(TileIndex tile, Owner old_owner, Owner new_ow
} }
} }
static int GetObjectEffectiveZ(TileIndex tile, const ObjectSpec *spec, int z, Slope tileh)
{
if ((spec->ctrl_flags & OBJECT_CTRL_FLAG_EDGE_FOUNDATION) && !(spec->flags & OBJECT_FLAG_HAS_NO_FOUNDATION)) {
uint8 flags = spec->edge_foundation[Object::GetByTile(tile)->view];
DiagDirection edge = (DiagDirection)GB(flags, 0, 2);
if (!(flags & OBJECT_EF_FLAG_FOUNDATION_LOWER) && !(tileh & InclinedSlope(edge))) return z;
}
return z + GetSlopeMaxZ(tileh);
}
static CommandCost TerraformTile_Object(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new) static CommandCost TerraformTile_Object(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
{ {
ObjectType type = GetObjectType(tile); ObjectType type = GetObjectType(tile);
@@ -1080,10 +1111,11 @@ static CommandCost TerraformTile_Object(TileIndex tile, DoCommandFlag flags, int
* - Allow autoslope by default. * - Allow autoslope by default.
* - Disallow autoslope if callback succeeds and returns non-zero. * - Disallow autoslope if callback succeeds and returns non-zero.
*/ */
Slope tileh_old = GetTileSlope(tile); int z_old;
/* TileMaxZ must not be changed. Slopes must not be steep. */ Slope tileh_old = GetTileSlope(tile, &z_old);
if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
const ObjectSpec *spec = ObjectSpec::Get(type); const ObjectSpec *spec = ObjectSpec::Get(type);
/* Object height must not be changed. Slopes must not be steep. */
if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetObjectEffectiveZ(tile, spec, z_old, tileh_old) == GetObjectEffectiveZ(tile, spec, z_new, tileh_new))) {
/* Call callback 'disable autosloping for objects'. */ /* Call callback 'disable autosloping for objects'. */
if (HasBit(spec->callback_mask, CBM_OBJ_AUTOSLOPE)) { if (HasBit(spec->callback_mask, CBM_OBJ_AUTOSLOPE)) {

View File

@@ -897,6 +897,7 @@ class NIHObject : public NIHelper {
check_flag(OBJECT_FLAG_ANIM_RANDOM_BITS, "OBJECT_FLAG_ANIM_RANDOM_BITS"); check_flag(OBJECT_FLAG_ANIM_RANDOM_BITS, "OBJECT_FLAG_ANIM_RANDOM_BITS");
check_flag(OBJECT_FLAG_SCALE_BY_WATER, "OBJECT_FLAG_SCALE_BY_WATER"); check_flag(OBJECT_FLAG_SCALE_BY_WATER, "OBJECT_FLAG_SCALE_BY_WATER");
check_ctrl_flag(OBJECT_CTRL_FLAG_USE_LAND_GROUND, "OBJECT_CTRL_FLAG_USE_LAND_GROUND"); check_ctrl_flag(OBJECT_CTRL_FLAG_USE_LAND_GROUND, "OBJECT_CTRL_FLAG_USE_LAND_GROUND");
check_ctrl_flag(OBJECT_CTRL_FLAG_EDGE_FOUNDATION, "OBJECT_CTRL_FLAG_EDGE_FOUNDATION");
} }
} }
} }

View File

@@ -121,7 +121,7 @@ static const DrawTileSprites _object_hq[] = {
#undef TILE_SPRITE_LINE #undef TILE_SPRITE_LINE
#define M(name, size, build_cost_multiplier, clear_cost_multiplier, height, climate, gen_amount, flags) { GRFFilePropsBase<2>(), INVALID_OBJECT_CLASS, name, climate, size, build_cost_multiplier, clear_cost_multiplier, 0, MAX_DAY + 1, flags, OBJECT_CTRL_FLAG_NONE, {0, 0, 0, 0}, 0, height, 1, gen_amount, true } #define M(name, size, build_cost_multiplier, clear_cost_multiplier, height, climate, gen_amount, flags) { GRFFilePropsBase<2>(), INVALID_OBJECT_CLASS, name, climate, size, build_cost_multiplier, clear_cost_multiplier, 0, MAX_DAY + 1, flags, OBJECT_CTRL_FLAG_NONE, {0, 0, 0, 0}, {0, 0, 0, 0}, 0, height, 1, gen_amount, true }
/* Climates /* Climates
* T = Temperate * T = Temperate