diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index d2c38e8760..4ac63d5de1 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -1297,13 +1297,51 @@ static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection t GrowTownWithRoad(t1, tile, rcmd); } +/** + * Checks whether a road can be followed or is a dead end, that can not be extended to the next tile. + * This only checks trivial but often cases. + * @param tile Start tile for road. + * @param dir Direction for road to follow or build. + * @return true If road is or can be connected in the specified direction. + */ +static bool CanFollowRoad(TileIndex tile, DiagDirection dir) +{ + TileIndex target_tile = tile + TileOffsByDiagDir(dir); + if (!IsValidTile(target_tile)) return false; + if (HasTileWaterGround(target_tile)) return false; + + RoadBits target_rb = GetTownRoadBits(target_tile); + if (_settings_game.economy.allow_town_roads || _generating_world) { + /* Check whether a road connection exists or can be build. */ + switch (GetTileType(target_tile)) { + case MP_ROAD: + return target_rb != ROAD_NONE; + + case MP_HOUSE: + case MP_STATION: + case MP_INDUSTRY: + case MP_OBJECT: + return false; + + default: + /* Checked for void and water earlier */ + return true; + } + } else { + /* Check whether a road connection already exists, + * and it leads somewhere else. */ + RoadBits back_rb = DiagDirToRoadBits(ReverseDiagDir(dir)); + return (target_rb & back_rb) != 0 && (target_rb & ~back_rb) != 0; + } +} + /** * Returns "growth" if a house was built, or no if the build failed. * @param t town to inquiry * @param tile to inquiry - * @return something other than zero(0)if town expansion was possible + * @return true if town expansion was possible */ -static int GrowTownAtRoad(Town *t, TileIndex tile) +static bool GrowTownAtRoad(Town *t, TileIndex tile) { /* Special case. * @see GrowTownInTile Check the else if @@ -1340,7 +1378,7 @@ static int GrowTownAtRoad(Town *t, TileIndex tile) * and return if no more road blocks available */ if (IsValidDiagDirection(target_dir)) cur_rb &= ~DiagDirToRoadBits(ReverseDiagDir(target_dir)); if (cur_rb == ROAD_NONE) { - return _grow_town_result; + return _grow_town_result == GROWTH_SUCCEED; } if (IsTileType(tile, MP_TUNNELBRIDGE)) { @@ -1349,14 +1387,22 @@ static int GrowTownAtRoad(Town *t, TileIndex tile) } else { /* Select a random bit from the blockmask, walk a step * and continue the search from there. */ - do target_dir = RandomDiagDir(); while (!(cur_rb & DiagDirToRoadBits(target_dir))); + do { + if (cur_rb == ROAD_NONE) return false; + RoadBits target_bits; + do { + target_dir = RandomDiagDir(); + target_bits = DiagDirToRoadBits(target_dir); + } while (!(cur_rb & target_bits)); + cur_rb &= ~target_bits; + } while (!CanFollowRoad(tile, target_dir)); } tile = TileAddByDiagDir(tile, target_dir); if (IsTileType(tile, MP_ROAD) && !IsRoadDepot(tile) && HasTileRoadType(tile, ROADTYPE_ROAD)) { /* Don't allow building over roads of other cities */ if (IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN) && Town::GetByTile(tile) != t) { - _grow_town_result = GROWTH_SUCCEED; + return false; } else if (IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_NONE) && _game_mode == GM_EDITOR) { /* If we are in the SE, and this road-piece has no town owner yet, it just found an * owner :) (happy happy happy road now) */ @@ -1368,7 +1414,7 @@ static int GrowTownAtRoad(Town *t, TileIndex tile) /* Max number of times is checked. */ } while (--_grow_town_result >= 0); - return (_grow_town_result == -2); + return _grow_town_result == GROWTH_SUCCEED - 1; } /** @@ -1390,7 +1436,7 @@ static RoadBits GenRandomRoadBits() /** * Grow the town * @param t town to grow - * @return true iff a house was built + * @return true iff something (house, road, bridge, ...) was built */ static bool GrowTown(Town *t) { @@ -1419,9 +1465,9 @@ static bool GrowTown(Town *t) const TileIndexDiffC *ptr; for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) { if (GetTownRoadBits(tile) != ROAD_NONE) { - int r = GrowTownAtRoad(t, tile); + bool success = GrowTownAtRoad(t, tile); cur_company.Restore(); - return r != 0; + return success; } tile = TILE_ADD(tile, ToTileIndexDiff(*ptr)); }