summaryrefslogtreecommitdiff
path: root/src/town_cmd.cpp
diff options
context:
space:
mode:
authorPeterN <peter@fuzzle.org>2019-03-03 22:28:55 +0000
committerGitHub <noreply@github.com>2019-03-03 22:28:55 +0000
commitebc3934ee642e2528768d6747ce6c09869f32b76 (patch)
tree93a65882fea114d3e655f07f86ec9b7a1c56fb03 /src/town_cmd.cpp
parent3c94bddbc221a604dab184f6f1133764bfef03e1 (diff)
downloadopenttd-ebc3934ee642e2528768d6747ce6c09869f32b76.tar.xz
Fix #7043, Fix #7274: Delete town owned bridge based on adjacent tile ownership, not nearest town. (#7284)
This only affects failed town generation, as towns do not delete bridges under any other circumstances. The existing test performed badly with a large number of towns due to having to calculate the nearest town, and also by its nature assumed a bridge was built by the nearest town, leading to bridges of nearby large towns be removed incorrectly. If we gain the ability to quickly retrieve the correct town (which is _not_ the nearest town) from the bridge, this change should be reviewed.
Diffstat (limited to 'src/town_cmd.cpp')
-rw-r--r--src/town_cmd.cpp44
1 files changed, 38 insertions, 6 deletions
diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp
index 84c7d44f3..32875974c 100644
--- a/src/town_cmd.cpp
+++ b/src/town_cmd.cpp
@@ -59,6 +59,31 @@ CargoTypes _town_cargoes_accepted; ///< Bitmap of all cargoes accepted by houses
TownPool _town_pool("Town");
INSTANTIATE_POOL_METHODS(Town)
+/**
+ * Check if a town 'owns' a bridge.
+ * Bridges to not directly have an owner, so we check the tiles adjacent to the bridge ends.
+ * If either adjacent tile belongs to the town then it will be assumed that the town built
+ * the bridge.
+ * @param tile Bridge tile to test
+ * @param t Town we are interested in
+ * @return true if town 'owns' a bridge.
+ */
+static bool TestTownOwnsBridge(TileIndex tile, const Town *t)
+{
+ if (!IsTileOwner(tile, OWNER_TOWN)) return false;
+
+ TileIndex adjacent = tile + TileOffsByDiagDir(ReverseDiagDir(GetTunnelBridgeDirection(tile)));
+ bool town_owned = IsTileType(adjacent, MP_ROAD) && IsTileOwner(adjacent, OWNER_TOWN) && GetTownIndex(adjacent) == t->index;
+
+ if (!town_owned) {
+ /* Or other adjacent road */
+ TileIndex adjacent = tile + TileOffsByDiagDir(ReverseDiagDir(GetTunnelBridgeDirection(GetOtherTunnelBridgeEnd(tile))));
+ town_owned = IsTileType(adjacent, MP_ROAD) && IsTileOwner(adjacent, OWNER_TOWN) && GetTownIndex(adjacent) == t->index;
+ }
+
+ return town_owned;
+}
+
Town::~Town()
{
free(this->name);
@@ -90,7 +115,7 @@ Town::~Town()
break;
case MP_TUNNELBRIDGE:
- assert(!IsTileOwner(tile, OWNER_TOWN) || ClosestTownFromTile(tile, UINT_MAX) != this);
+ assert(!TestTownOwnsBridge(tile, this));
break;
default:
@@ -2730,7 +2755,18 @@ CommandCost CmdDeleteTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
if (d->town == t) return CMD_ERROR;
}
- /* Check all tiles for town ownership. */
+ /* Check all tiles for town ownership. First check for bridge tiles, as
+ * these do not directly have an owner so we need to check adjacent
+ * tiles. This won't work correctly in the same loop if the adjacent
+ * tile was already deleted earlier in the loop. */
+ for (TileIndex tile = 0; tile < MapSize(); ++tile) {
+ if (IsTileType(tile, MP_TUNNELBRIDGE) && TestTownOwnsBridge(tile, t)) {
+ CommandCost ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+ if (ret.Failed()) return ret;
+ }
+ }
+
+ /* Check all remaining tiles for town ownership. */
for (TileIndex tile = 0; tile < MapSize(); ++tile) {
bool try_clear = false;
switch (GetTileType(tile)) {
@@ -2738,10 +2774,6 @@ CommandCost CmdDeleteTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
try_clear = HasTownOwnedRoad(tile) && GetTownIndex(tile) == t->index;
break;
- case MP_TUNNELBRIDGE:
- try_clear = IsTileOwner(tile, OWNER_TOWN) && ClosestTownFromTile(tile, UINT_MAX) == t;
- break;
-
case MP_HOUSE:
try_clear = GetTownIndex(tile) == t->index;
break;