Changeset - r23400:cd24ee6d788d
[Not reviewed]
master
0 1 0
PeterN - 5 years ago 2019-03-03 22:28:55
peter@fuzzle.org
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.
1 file changed with 38 insertions and 6 deletions:
0 comments (0 inline, 0 general)
src/town_cmd.cpp
Show inline comments
 
@@ -59,6 +59,31 @@ CargoTypes _town_cargoes_accepted; ///< 
 
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
 
		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
 
				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;
0 comments (0 inline, 0 general)