From f30f808b5042c50227a392079a52f652c2ddd4a5 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 14 Aug 2025 19:35:32 +0100 Subject: [PATCH] Codechange: Implement tile proc handler to test for building bridge over tile. --- src/clear_cmd.cpp | 7 +++++ src/industry_cmd.cpp | 1 + src/object_cmd.cpp | 11 +++++++ src/rail_cmd.cpp | 6 ++++ src/road_cmd.cpp | 6 ++++ src/station_cmd.cpp | 1 + src/tile_cmd.h | 11 +++++++ src/town_cmd.cpp | 1 + src/tree_cmd.cpp | 1 + src/tunnelbridge_cmd.cpp | 65 ++++++++++++++++------------------------ src/void_cmd.cpp | 1 + src/water_cmd.cpp | 6 ++++ 12 files changed, 77 insertions(+), 40 deletions(-) diff --git a/src/clear_cmd.cpp b/src/clear_cmd.cpp index 92363bb184..a9dc5c567f 100644 --- a/src/clear_cmd.cpp +++ b/src/clear_cmd.cpp @@ -390,6 +390,12 @@ static CommandCost TerraformTile_Clear(TileIndex tile, DoCommandFlags flags, int return Command::Do(flags, tile); } +static CommandCost CheckBuildAbove_Clear(TileIndex, DoCommandFlags, Axis, int) +{ + /* Can always build above clear tiles. */ + return CommandCost(); +} + extern const TileTypeProcs _tile_type_clear_procs = { DrawTile_Clear, ///< draw_tile_proc GetSlopePixelZ_Clear, ///< get_slope_z_proc @@ -405,4 +411,5 @@ extern const TileTypeProcs _tile_type_clear_procs = { nullptr, ///< vehicle_enter_tile_proc GetFoundation_Clear, ///< get_foundation_proc TerraformTile_Clear, ///< terraform_tile_proc + CheckBuildAbove_Clear, // check_build_above_proc }; diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index b0b7d8bb87..e0a5693610 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -3224,6 +3224,7 @@ extern const TileTypeProcs _tile_type_industry_procs = { nullptr, // vehicle_enter_tile_proc GetFoundation_Industry, // get_foundation_proc TerraformTile_Industry, // terraform_tile_proc + nullptr, // check_build_above_proc }; bool IndustryCompare::operator() (const IndustryListEntry &lhs, const IndustryListEntry &rhs) const diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp index 195e510e72..b17b30c9c3 100644 --- a/src/object_cmd.cpp +++ b/src/object_cmd.cpp @@ -929,6 +929,16 @@ static CommandCost TerraformTile_Object(TileIndex tile, DoCommandFlags flags, in return Command::Do(flags, tile); } +static CommandCost CheckBuildAbove_Object(TileIndex tile, DoCommandFlags flags, Axis, int height) +{ + const ObjectSpec *spec = ObjectSpec::GetByTile(tile); + if (spec->flags.Test(ObjectFlag::AllowUnderBridge) && GetTileMaxZ(tile) + spec->height <= height) { + return CommandCost(); + } + + return Command::Do(flags, tile); +} + extern const TileTypeProcs _tile_type_object_procs = { DrawTile_Object, // draw_tile_proc GetSlopePixelZ_Object, // get_slope_z_proc @@ -944,4 +954,5 @@ extern const TileTypeProcs _tile_type_object_procs = { nullptr, // vehicle_enter_tile_proc GetFoundation_Object, // get_foundation_proc TerraformTile_Object, // terraform_tile_proc + CheckBuildAbove_Object, // check_build_above_proc }; diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 6c1f3eb4f7..08728bb403 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -3076,6 +3076,11 @@ static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlags flags, int return Command::Do(flags, tile); } +static CommandCost CheckBuildAbove_Track(TileIndex tile, DoCommandFlags flags, Axis, int) +{ + if (IsPlainRail(tile)) return CommandCost(); + return Command::Do(flags, tile); +} extern const TileTypeProcs _tile_type_rail_procs = { DrawTile_Track, // draw_tile_proc @@ -3092,4 +3097,5 @@ extern const TileTypeProcs _tile_type_rail_procs = { VehicleEnter_Track, // vehicle_enter_tile_proc GetFoundation_Track, // get_foundation_proc TerraformTile_Track, // terraform_tile_proc + CheckBuildAbove_Track, // check_build_above_proc }; diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index f923eddbee..b6384e1d65 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -2626,6 +2626,11 @@ CommandCost CmdConvertRoad(DoCommandFlags flags, TileIndex tile, TileIndex area_ return found_convertible_road ? cost : error; } +static CommandCost CheckBuildAbove_Road(TileIndex tile, DoCommandFlags flags, Axis, int) +{ + if (!IsRoadDepot(tile)) return CommandCost(); + return Command::Do(flags, tile); +} /** Tile callback functions for road tiles */ extern const TileTypeProcs _tile_type_road_procs = { @@ -2643,4 +2648,5 @@ extern const TileTypeProcs _tile_type_road_procs = { VehicleEnter_Road, // vehicle_enter_tile_proc GetFoundation_Road, // get_foundation_proc TerraformTile_Road, // terraform_tile_proc + CheckBuildAbove_Road, // check_build_above_proc }; diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 61848a2308..5bf8a33679 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -5165,4 +5165,5 @@ extern const TileTypeProcs _tile_type_station_procs = { VehicleEnter_Station, // vehicle_enter_tile_proc GetFoundation_Station, // get_foundation_proc TerraformTile_Station, // terraform_tile_proc + nullptr, // check_build_above_proc }; diff --git a/src/tile_cmd.h b/src/tile_cmd.h index fb60cec092..6a12f88fe8 100644 --- a/src/tile_cmd.h +++ b/src/tile_cmd.h @@ -135,6 +135,16 @@ typedef Foundation GetFoundationProc(TileIndex tile, Slope tileh); */ typedef CommandCost TerraformTileProc(TileIndex tile, DoCommandFlags flags, int z_new, Slope tileh_new); +/** + * Tile callback function signature to test if a bridge can be built above a tile. + * @param tile The involved tile. + * @param flags Command flags passed to the build command. + * @param axis Axis of bridge being built. + * @param height Absolute height of bridge platform. + * @return Error code or extra cost for building bridge above the tile. + */ +using CheckBuildAboveProc = CommandCost(TileIndex tile, DoCommandFlags flags, Axis axis, int height); + /** * Set of callback functions for performing tile operations of a given tile type. * @see TileType @@ -154,6 +164,7 @@ struct TileTypeProcs { VehicleEnterTileProc *vehicle_enter_tile_proc; ///< Called when a vehicle enters a tile GetFoundationProc *get_foundation_proc; TerraformTileProc *terraform_tile_proc; ///< Called when a terraforming operation is about to take place + CheckBuildAboveProc *check_build_above_proc; }; extern const TileTypeProcs * const _tile_type_procs[16]; diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index 9f4f1a7125..0b0cdb8915 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -4162,6 +4162,7 @@ extern const TileTypeProcs _tile_type_town_procs = { nullptr, // vehicle_enter_tile_proc GetFoundation_Town, // get_foundation_proc TerraformTile_Town, // terraform_tile_proc + nullptr, // check_build_above_proc }; std::span GetTownDrawTileData() diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index ad7203dc00..49901b8796 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -1031,4 +1031,5 @@ extern const TileTypeProcs _tile_type_trees_procs = { nullptr, // vehicle_enter_tile_proc GetFoundation_Trees, // get_foundation_proc TerraformTile_Trees, // terraform_tile_proc + nullptr, // check_build_above_proc }; diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index 1bbb1b864b..92da362954 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -12,7 +12,6 @@ */ #include "stdafx.h" -#include "newgrf_object.h" #include "viewport_func.h" #include "command_func.h" #include "town.h" @@ -20,7 +19,6 @@ #include "ship.h" #include "roadveh.h" #include "pathfinder/yapf/yapf_cache.h" -#include "pathfinder/water_regions.h" #include "newgrf_sound.h" #include "autoslope.h" #include "tunnelbridge_map.h" @@ -39,7 +37,6 @@ #include "object_base.h" #include "water.h" #include "company_gui.h" -#include "station_func.h" #include "tunnelbridge_cmd.h" #include "landscape_cmd.h" #include "terraform_cmd.h" @@ -278,6 +275,16 @@ static Money TunnelBridgeClearCost(TileIndex tile, Price base_price) return base_cost; } +static CommandCost CheckBuildAbove(TileIndex tile, DoCommandFlags flags, Axis axis, int height) +{ + if (_tile_type_procs[GetTileType(tile)]->check_build_above_proc != nullptr) { + return _tile_type_procs[GetTileType(tile)]->check_build_above_proc(tile, flags, axis, height); + } + + /* A tile without a handler must be cleared. */ + return Command::Do(flags, tile); +} + /** * Build a Bridge * @param flags type of operation @@ -484,43 +491,9 @@ CommandCost CmdBuildBridge(DoCommandFlags flags, TileIndex tile_end, TileIndex t return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); } - switch (GetTileType(tile)) { - case MP_WATER: - if (!IsWater(tile) && !IsCoast(tile)) goto not_valid_below; - break; - - case MP_RAILWAY: - if (!IsPlainRail(tile)) goto not_valid_below; - break; - - case MP_ROAD: - if (IsRoadDepot(tile)) goto not_valid_below; - break; - - case MP_TUNNELBRIDGE: - if (IsTunnel(tile)) break; - if (direction == DiagDirToAxis(GetTunnelBridgeDirection(tile))) goto not_valid_below; - if (z_start < GetBridgeHeight(tile)) goto not_valid_below; - break; - - case MP_OBJECT: { - const ObjectSpec *spec = ObjectSpec::GetByTile(tile); - if (!spec->flags.Test(ObjectFlag::AllowUnderBridge)) goto not_valid_below; - if (GetTileMaxZ(tile) + spec->height > z_start) goto not_valid_below; - break; - } - - case MP_CLEAR: - break; - - default: - not_valid_below:; - /* try and clear the middle landscape */ - ret = Command::Do(flags, tile); - if (ret.Failed()) return ret; - cost.AddCost(ret.GetCost()); - break; - } + ret = CheckBuildAbove(tile, flags, direction, z_start); + if (ret.Failed()) return ret; + cost.AddCost(ret.GetCost()); if (flags.Test(DoCommandFlag::Execute)) { /* We do this here because when replacing a bridge with another @@ -2119,6 +2092,17 @@ static CommandCost TerraformTile_TunnelBridge(TileIndex tile, DoCommandFlags fla return Command::Do(flags, tile); } +static CommandCost CheckBuildAbove_TunnelBridge(TileIndex tile, DoCommandFlags flags, Axis axis, int height) +{ + if (IsTunnel(tile)) return CommandCost(); + + if (axis != DiagDirToAxis(GetTunnelBridgeDirection(tile)) && height >= GetBridgeHeight(tile)) { + return CommandCost(); + } + + return Command::Do(flags, tile); +} + extern const TileTypeProcs _tile_type_tunnelbridge_procs = { DrawTile_TunnelBridge, // draw_tile_proc GetSlopePixelZ_TunnelBridge, // get_slope_z_proc @@ -2134,4 +2118,5 @@ extern const TileTypeProcs _tile_type_tunnelbridge_procs = { VehicleEnter_TunnelBridge, // vehicle_enter_tile_proc GetFoundation_TunnelBridge, // get_foundation_proc TerraformTile_TunnelBridge, // terraform_tile_proc + CheckBuildAbove_TunnelBridge, // check_build_above_proc }; diff --git a/src/void_cmd.cpp b/src/void_cmd.cpp index 5334824997..2665f4d2bf 100644 --- a/src/void_cmd.cpp +++ b/src/void_cmd.cpp @@ -87,4 +87,5 @@ extern const TileTypeProcs _tile_type_void_procs = { nullptr, // vehicle_enter_tile_proc GetFoundation_Void, // get_foundation_proc TerraformTile_Void, // terraform_tile_proc + nullptr, // check_build_above_proc }; diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp index 0077fc107b..47cdcf9b08 100644 --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -1412,6 +1412,11 @@ static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlags flags, int return Command::Do(flags, tile); } +static CommandCost CheckBuildAbove_Water(TileIndex tile, DoCommandFlags flags, Axis, int) +{ + if (IsWater(tile) || IsCoast(tile)) return CommandCost(); + return Command::Do(flags, tile); +} extern const TileTypeProcs _tile_type_water_procs = { DrawTile_Water, // draw_tile_proc @@ -1428,4 +1433,5 @@ extern const TileTypeProcs _tile_type_water_procs = { VehicleEnter_Water, // vehicle_enter_tile_proc GetFoundation_Water, // get_foundation_proc TerraformTile_Water, // terraform_tile_proc + CheckBuildAbove_Water, // check_build_above_proc };