diff --git a/src/newgrf_extension.cpp b/src/newgrf_extension.cpp index 81175256ad..168a815c35 100644 --- a/src/newgrf_extension.cpp +++ b/src/newgrf_extension.cpp @@ -44,7 +44,7 @@ extern const GRFFeatureInfo _grf_feature_list[] = { GRFFeatureInfo("action0_signals_extra_aspects", 1), GRFFeatureInfo("action3_signals_custom_signal_sprites", 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(), }; diff --git a/src/newgrf_object.h b/src/newgrf_object.h index d31e4c35b8..3869846889 100644 --- a/src/newgrf_object.h +++ b/src/newgrf_object.h @@ -52,6 +52,7 @@ 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. + OBJECT_EF_FLAG_INCLINE_FOUNDATION = 1 << 4, ///< Use inclined foundations where possible when edge at tile max z. }; DECLARE_ENUM_AS_BIT_SET(ObjectEdgeFoundationFlags) diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp index 026ae8b922..e0d46b92b1 100644 --- a/src/object_cmd.cpp +++ b/src/object_cmd.cpp @@ -75,23 +75,18 @@ void InitializeObjects() * 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. */ -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) { - SetObjectHasNoEffectiveFoundation(tile, true); + SetObjectEffectiveFoundationType(tile, OEFT_NONE); return; } 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 (IsSteepSlope(tileh)) { - SetObjectHasNoEffectiveFoundation(tile, false); - return; - } - if (tileh == SLOPE_FLAT) { - SetObjectHasNoEffectiveFoundation(tile, true); + SetObjectEffectiveFoundationType(tile, OEFT_NONE); return; } @@ -99,9 +94,32 @@ void SetShouldObjectHaveNoFoundation(TileIndex tile, Slope tileh, ObjectType typ DiagDirection edge = (DiagDirection)GB(flags, 0, 2); 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 { + SetObjectEffectiveFoundationType(tile, OEFT_FLAT); + } + } else { + SetObjectEffectiveFoundationType(tile, OEFT_NONE); + } } else { - SetObjectHasNoEffectiveFoundation(tile, false); + 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) { SetObjectGroundTypeDensity(t, OBJECT_GROUND_GRASS, 0); } - SetShouldObjectHaveNoFoundation(t, SLOPE_ELEVATED, type, spec); + SetObjectFoundationType(t, SLOPE_ELEVATED, type, spec); 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]; 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; + Foundation foundation = GetFoundation_Object(ti->tile, ti->tileh); + switch (foundation) { + case FOUNDATION_NONE: + 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; + } + 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 { 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) { - 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 = [&]() { 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); } }; diff --git a/src/object_map.h b/src/object_map.h index 571030223d..626f3a035a 100644 --- a/src/object_map.h +++ b/src/object_map.h @@ -156,16 +156,16 @@ static inline void SetObjectGroundTypeDensity(TileIndex t, ObjectGround type, ui _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); - 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); - SB(_m[t].m4, 4, 1, no_foundation ? 1 : 0); + SB(_me[t].m6, 0, 2, foundation_type); } /** diff --git a/src/object_type.h b/src/object_type.h index 52aedc6540..3bdf80818d 100644 --- a/src/object_type.h +++ b/src/object_type.h @@ -33,4 +33,11 @@ struct ObjectSpec; 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 */ diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 3461afe091..b59b95c416 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -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++) { if (IsTileType(t, MP_OBJECT)) { - _m[t].m4 = 0; + if (SlXvIsFeatureMissing(XSLFI_OBJECT_GROUND_TYPES)) _m[t].m4 = 0; ObjectType type = GetObjectType(t); - extern void SetShouldObjectHaveNoFoundation(TileIndex tile, Slope tileh, ObjectType type, const ObjectSpec *spec); - SetShouldObjectHaveNoFoundation(t, SLOPE_ELEVATED, type, ObjectSpec::Get(type)); + extern void SetObjectFoundationType(TileIndex tile, Slope tileh, ObjectType type, const ObjectSpec *spec); + SetObjectFoundationType(t, SLOPE_ELEVATED, type, ObjectSpec::Get(type)); } } } diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 25038310d3..0e55855f88 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -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_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_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_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 }, diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 787bdf12a8..786088d441 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -864,7 +864,7 @@ class NIHObject : public NIHelper { 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); 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); 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)); diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp index 0137f782ac..97755ef187 100644 --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -1309,7 +1309,7 @@ void TileLoop_Water(TileIndex tile) /* 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_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; Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;