Add inclined foundation option to object edge foundation mode

Bump feature version
This commit is contained in:
Jonathan G Rennison
2022-01-23 13:17:13 +00:00
parent e7c12f2ad4
commit 2e7f8d2e1e
9 changed files with 90 additions and 34 deletions

View File

@@ -44,7 +44,7 @@ extern const GRFFeatureInfo _grf_feature_list[] = {
GRFFeatureInfo("action0_signals_extra_aspects", 1), GRFFeatureInfo("action0_signals_extra_aspects", 1),
GRFFeatureInfo("action3_signals_custom_signal_sprites", 1), GRFFeatureInfo("action3_signals_custom_signal_sprites", 1),
GRFFeatureInfo("action0_object_use_land_ground", 1), GRFFeatureInfo("action0_object_use_land_ground", 1),
GRFFeatureInfo("action0_object_edge_foundation_mode", 1), GRFFeatureInfo("action0_object_edge_foundation_mode", 2),
GRFFeatureInfo("action0_object_flood_resistant", 1), GRFFeatureInfo("action0_object_flood_resistant", 1),
GRFFeatureInfo(), GRFFeatureInfo(),
}; };

View File

@@ -52,6 +52,7 @@ enum ObjectEdgeFoundationFlags {
/* Bits 0 and 1 use for edge DiagDirection */ /* 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_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. OBJECT_EF_FLAG_FOUNDATION_LOWER = 1 << 3, ///< If edge is lower than tile max z, add foundation.
OBJECT_EF_FLAG_INCLINE_FOUNDATION = 1 << 4, ///< Use inclined foundations where possible when edge at tile max z.
}; };
DECLARE_ENUM_AS_BIT_SET(ObjectEdgeFoundationFlags) DECLARE_ENUM_AS_BIT_SET(ObjectEdgeFoundationFlags)

View File

@@ -75,23 +75,18 @@ void InitializeObjects()
* Set the object has no effective foundation flag for this tile. * Set the object has no effective foundation flag for this tile.
* Set tileh to SLOPE_ELEVATED if not known, it will be redetermined if required. * Set tileh to SLOPE_ELEVATED if not known, it will be redetermined if required.
*/ */
void SetShouldObjectHaveNoFoundation(TileIndex tile, Slope tileh, ObjectType type, const ObjectSpec *spec) void SetObjectFoundationType(TileIndex tile, Slope tileh, ObjectType type, const ObjectSpec *spec)
{ {
if (type == OBJECT_OWNED_LAND) { if (type == OBJECT_OWNED_LAND) {
SetObjectHasNoEffectiveFoundation(tile, true); SetObjectEffectiveFoundationType(tile, OEFT_NONE);
return; return;
} }
if (((spec->flags & OBJECT_FLAG_HAS_NO_FOUNDATION) == 0) && (spec->ctrl_flags & OBJECT_CTRL_FLAG_EDGE_FOUNDATION)) { if (((spec->flags & OBJECT_FLAG_HAS_NO_FOUNDATION) == 0) && (spec->ctrl_flags & OBJECT_CTRL_FLAG_EDGE_FOUNDATION)) {
if (tileh == SLOPE_ELEVATED) tileh = GetTileSlope(tile); if (tileh == SLOPE_ELEVATED) tileh = GetTileSlope(tile);
if (IsSteepSlope(tileh)) {
SetObjectHasNoEffectiveFoundation(tile, false);
return;
}
if (tileh == SLOPE_FLAT) { if (tileh == SLOPE_FLAT) {
SetObjectHasNoEffectiveFoundation(tile, true); SetObjectEffectiveFoundationType(tile, OEFT_NONE);
return; return;
} }
@@ -99,9 +94,32 @@ void SetShouldObjectHaveNoFoundation(TileIndex tile, Slope tileh, ObjectType typ
DiagDirection edge = (DiagDirection)GB(flags, 0, 2); DiagDirection edge = (DiagDirection)GB(flags, 0, 2);
Slope incline = InclinedSlope(edge); Slope incline = InclinedSlope(edge);
SetObjectHasNoEffectiveFoundation(tile, !(IsOddParity(incline & tileh) || (flags & OBJECT_EF_FLAG_FOUNDATION_LOWER && !(tileh & incline)))); if (IsSteepSlope(tileh)) {
if ((flags & OBJECT_EF_FLAG_INCLINE_FOUNDATION) && (incline & tileh)) {
SetObjectEffectiveFoundationType(tile, DiagDirToAxis(edge) == AXIS_X ? OEFT_INCLINE_X : OEFT_INCLINE_Y);
return;
}
SetObjectEffectiveFoundationType(tile, OEFT_FLAT);
return;
}
if ((flags & OBJECT_EF_FLAG_FOUNDATION_LOWER) && !(tileh & incline)) {
SetObjectEffectiveFoundationType(tile, OEFT_FLAT);
return;
}
if (IsOddParity(incline & tileh)) {
if ((flags & OBJECT_EF_FLAG_INCLINE_FOUNDATION) && IsSlopeWithOneCornerRaised(tileh)) {
SetObjectEffectiveFoundationType(tile, DiagDirToAxis(edge) == AXIS_X ? OEFT_INCLINE_X : OEFT_INCLINE_Y);
} else { } else {
SetObjectHasNoEffectiveFoundation(tile, false); SetObjectEffectiveFoundationType(tile, OEFT_FLAT);
}
} else {
SetObjectEffectiveFoundationType(tile, OEFT_NONE);
}
} else {
SetObjectEffectiveFoundationType(tile, OEFT_FLAT);
} }
} }
@@ -163,7 +181,7 @@ void BuildObject(ObjectType type, TileIndex tile, CompanyID owner, Town *town, u
if ((spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) && wc == WATER_CLASS_INVALID) { if ((spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) && wc == WATER_CLASS_INVALID) {
SetObjectGroundTypeDensity(t, OBJECT_GROUND_GRASS, 0); SetObjectGroundTypeDensity(t, OBJECT_GROUND_GRASS, 0);
} }
SetShouldObjectHaveNoFoundation(t, SLOPE_ELEVATED, type, spec); SetObjectFoundationType(t, SLOPE_ELEVATED, type, spec);
MarkTileDirtyByTile(t, VMDF_NOT_MAP_MODE); MarkTileDirtyByTile(t, VMDF_NOT_MAP_MODE);
} }
@@ -566,16 +584,30 @@ static void DrawTile_Object(TileInfo *ti, DrawTileProcParams params)
uint8 flags = spec->edge_foundation[obj->view]; uint8 flags = spec->edge_foundation[obj->view];
DiagDirection edge = (DiagDirection)GB(flags, 0, 2); DiagDirection edge = (DiagDirection)GB(flags, 0, 2);
Slope incline = InclinedSlope(edge); Slope incline = InclinedSlope(edge);
if (IsSteepSlope(ti->tileh) || IsOddParity(incline & ti->tileh)) { Foundation foundation = GetFoundation_Object(ti->tile, ti->tileh);
/* Steep slope, or odd number of matching bits indicating that edge is not level */ switch (foundation) {
DrawFoundation(ti, GetFoundation_Object(ti->tile, ti->tileh)); case FOUNDATION_NONE:
} else if (flags & OBJECT_EF_FLAG_FOUNDATION_LOWER && !(ti->tileh & incline)) { if (flags & OBJECT_EF_FLAG_ADJUST_Z && 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 */ /* The edge is elevated relative to the lowest tile height, adjust z */
building_z_offset = TILE_HEIGHT; building_z_offset = TILE_HEIGHT;
} }
break;
case FOUNDATION_LEVELED:
break;
case FOUNDATION_INCLINED_X:
case FOUNDATION_INCLINED_Y:
if (flags & OBJECT_EF_FLAG_ADJUST_Z) {
/* The edge is elevated relative to the lowest tile height, adjust z */
building_z_offset = TILE_HEIGHT;
}
break;
default:
NOT_REACHED();
}
if (foundation != FOUNDATION_NONE) DrawFoundation(ti, foundation);
} else { } else {
DrawFoundation(ti, GetFoundation_Object(ti->tile, ti->tileh)); DrawFoundation(ti, GetFoundation_Object(ti->tile, ti->tileh));
} }
@@ -640,7 +672,23 @@ static int GetSlopePixelZ_Object(TileIndex tile, uint x, uint y)
static Foundation GetFoundation_Object(TileIndex tile, Slope tileh) static Foundation GetFoundation_Object(TileIndex tile, Slope tileh)
{ {
return GetObjectHasNoEffectiveFoundation(tile) ? FOUNDATION_NONE : FlatteningFoundation(tileh); if (tileh == SLOPE_FLAT) return FOUNDATION_NONE;
switch (GetObjectEffectiveFoundationType(tile)) {
case OEFT_NONE:
return FOUNDATION_NONE;
case OEFT_FLAT:
return FOUNDATION_LEVELED;
case OEFT_INCLINE_X:
return FOUNDATION_INCLINED_X;
case OEFT_INCLINE_Y:
return FOUNDATION_INCLINED_Y;
default:
NOT_REACHED();
}
} }
/** /**
@@ -1148,7 +1196,7 @@ static CommandCost TerraformTile_Object(TileIndex tile, DoCommandFlag flags, int
auto pre_success_checks = [&]() { auto pre_success_checks = [&]() {
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
SetShouldObjectHaveNoFoundation(tile, tileh_new, type, spec); SetObjectFoundationType(tile, tileh_new, type, spec);
if (spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) SetObjectGroundTypeDensity(tile, OBJECT_GROUND_GRASS, 0); if (spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) SetObjectGroundTypeDensity(tile, OBJECT_GROUND_GRASS, 0);
} }
}; };

View File

@@ -156,16 +156,16 @@ static inline void SetObjectGroundTypeDensity(TileIndex t, ObjectGround type, ui
_m[t].m4 = 0 << 5 | type << 2 | density; _m[t].m4 = 0 << 5 | type << 2 | density;
} }
static inline bool GetObjectHasNoEffectiveFoundation(TileIndex t) static inline ObjectEffectiveFoundationType GetObjectEffectiveFoundationType(TileIndex t)
{ {
assert_tile(IsTileType(t, MP_OBJECT), t); assert_tile(IsTileType(t, MP_OBJECT), t);
return GB(_m[t].m4, 4, 1); return (ObjectEffectiveFoundationType)GB(_me[t].m6, 0, 2);
} }
static inline void SetObjectHasNoEffectiveFoundation(TileIndex t, bool no_foundation) static inline void SetObjectEffectiveFoundationType(TileIndex t, ObjectEffectiveFoundationType foundation_type)
{ {
assert_tile(IsTileType(t, MP_OBJECT), t); assert_tile(IsTileType(t, MP_OBJECT), t);
SB(_m[t].m4, 4, 1, no_foundation ? 1 : 0); SB(_me[t].m6, 0, 2, foundation_type);
} }
/** /**

View File

@@ -33,4 +33,11 @@ struct ObjectSpec;
static const ObjectID INVALID_OBJECT = 0xFFFFFFFF; ///< An invalid object static const ObjectID INVALID_OBJECT = 0xFFFFFFFF; ///< An invalid object
enum ObjectEffectiveFoundationType {
OEFT_NONE,
OEFT_FLAT,
OEFT_INCLINE_X,
OEFT_INCLINE_Y,
};
#endif /* OBJECT_TYPE_H */ #endif /* OBJECT_TYPE_H */

View File

@@ -3980,13 +3980,13 @@ bool AfterLoadGame()
} }
} }
if (SlXvIsFeatureMissing(XSLFI_OBJECT_GROUND_TYPES)) { if (SlXvIsFeatureMissing(XSLFI_OBJECT_GROUND_TYPES, 2)) {
for (TileIndex t = 0; t < map_size; t++) { for (TileIndex t = 0; t < map_size; t++) {
if (IsTileType(t, MP_OBJECT)) { if (IsTileType(t, MP_OBJECT)) {
_m[t].m4 = 0; if (SlXvIsFeatureMissing(XSLFI_OBJECT_GROUND_TYPES)) _m[t].m4 = 0;
ObjectType type = GetObjectType(t); ObjectType type = GetObjectType(t);
extern void SetShouldObjectHaveNoFoundation(TileIndex tile, Slope tileh, ObjectType type, const ObjectSpec *spec); extern void SetObjectFoundationType(TileIndex tile, Slope tileh, ObjectType type, const ObjectSpec *spec);
SetShouldObjectHaveNoFoundation(t, SLOPE_ELEVATED, type, ObjectSpec::Get(type)); SetObjectFoundationType(t, SLOPE_ELEVATED, type, ObjectSpec::Get(type));
} }
} }
} }

View File

@@ -160,7 +160,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_DEPOT_ORDER_EXTRA_FLAGS,XSCF_IGNORABLE_UNKNOWN, 1, 1, "depot_order_extra_flags", nullptr, nullptr, nullptr }, { XSLFI_DEPOT_ORDER_EXTRA_FLAGS,XSCF_IGNORABLE_UNKNOWN, 1, 1, "depot_order_extra_flags", nullptr, nullptr, nullptr },
{ XSLFI_EXTRA_SIGNAL_TYPES, XSCF_NULL, 1, 1, "extra_signal_types", nullptr, nullptr, nullptr }, { XSLFI_EXTRA_SIGNAL_TYPES, XSCF_NULL, 1, 1, "extra_signal_types", nullptr, nullptr, nullptr },
{ XSLFI_BANKRUPTCY_EXTRA, XSCF_NULL, 1, 1, "bankruptcy_extra", nullptr, nullptr, nullptr }, { XSLFI_BANKRUPTCY_EXTRA, XSCF_NULL, 1, 1, "bankruptcy_extra", nullptr, nullptr, nullptr },
{ XSLFI_OBJECT_GROUND_TYPES, XSCF_NULL, 1, 1, "object_ground_types", nullptr, nullptr, nullptr }, { XSLFI_OBJECT_GROUND_TYPES, XSCF_NULL, 2, 2, "object_ground_types", nullptr, nullptr, nullptr },
{ XSLFI_LINKGRAPH_AIRCRAFT, XSCF_NULL, 1, 1, "linkgraph_aircraft", nullptr, nullptr, nullptr }, { XSLFI_LINKGRAPH_AIRCRAFT, XSCF_NULL, 1, 1, "linkgraph_aircraft", nullptr, nullptr, nullptr },
{ XSLFI_COMPANY_PW, XSCF_IGNORABLE_ALL, 1, 1, "company_password", nullptr, nullptr, "PLYP" }, { XSLFI_COMPANY_PW, XSCF_IGNORABLE_ALL, 1, 1, "company_password", nullptr, nullptr, "PLYP" },
{ XSLFI_ST_INDUSTRY_CARGO_MODE, XSCF_IGNORABLE_UNKNOWN, 1, 1, "st_industry_cargo_mode", nullptr, nullptr, nullptr }, { XSLFI_ST_INDUSTRY_CARGO_MODE, XSCF_IGNORABLE_UNKNOWN, 1, 1, "st_industry_cargo_mode", nullptr, nullptr, nullptr },

View File

@@ -864,7 +864,7 @@ class NIHObject : public NIHelper {
uint class_id = ObjectClass::Get(spec->cls_id)->global_id; uint class_id = ObjectClass::Get(spec->cls_id)->global_id;
seprintf(buffer, lastof(buffer), " index: %u, type ID: %u, class ID: %c%c%c%c", id, GetObjectType(index), class_id >> 24, class_id >> 16, class_id >> 8, class_id); seprintf(buffer, lastof(buffer), " index: %u, type ID: %u, class ID: %c%c%c%c", id, GetObjectType(index), class_id >> 24, class_id >> 16, class_id >> 8, class_id);
output.print(buffer); output.print(buffer);
seprintf(buffer, lastof(buffer), " view: %u, colour: %u, effective foundation: %u", obj->view, obj->colour, !GetObjectHasNoEffectiveFoundation(index)); seprintf(buffer, lastof(buffer), " view: %u, colour: %u, effective foundation: %u", obj->view, obj->colour, GetObjectEffectiveFoundationType(index));
output.print(buffer); output.print(buffer);
if (spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) { if (spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) {
seprintf(buffer, lastof(buffer), " ground type: %u, density: %u, counter: %u, water class: %u", GetObjectGroundType(index), GetObjectGroundDensity(index), GetObjectGroundCounter(index), GetWaterClass(index)); seprintf(buffer, lastof(buffer), " ground type: %u, density: %u, counter: %u, water class: %u", GetObjectGroundType(index), GetObjectGroundDensity(index), GetObjectGroundCounter(index), GetWaterClass(index));

View File

@@ -1309,7 +1309,7 @@ void TileLoop_Water(TileIndex tile)
/* TREE_GROUND_SHORE is the sign of a previous flood. */ /* TREE_GROUND_SHORE is the sign of a previous flood. */
if (IsTileType(dest, MP_TREES) && GetTreeGround(dest) == TREE_GROUND_SHORE) continue; if (IsTileType(dest, MP_TREES) && GetTreeGround(dest) == TREE_GROUND_SHORE) continue;
if (IsTileType(dest, MP_OBJECT) && (!GetObjectHasNoEffectiveFoundation(dest) || GetObjectGroundType(dest) == OBJECT_GROUND_SHORE)) continue; if (IsTileType(dest, MP_OBJECT) && (GetObjectEffectiveFoundationType(dest) != OEFT_NONE || GetObjectGroundType(dest) == OBJECT_GROUND_SHORE)) continue;
int z_dest; int z_dest;
Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP; Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;