1
0
Fork 0

Codechange: Use EnumBitSet for HouseZones. (#14137)

pull/14150/head
Peter Nelson 2025-04-28 20:27:43 +01:00 committed by GitHub
parent f5a9eae8b1
commit 2c4897c2cd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 238 additions and 233 deletions

View File

@ -52,35 +52,40 @@ static constexpr BuildingFlags BUILDING_2_TILES_X = {BuildingFlag::Size2x1, Bu
static constexpr BuildingFlags BUILDING_2_TILES_Y = {BuildingFlag::Size1x2, BuildingFlag::Size2x2}; static constexpr BuildingFlags BUILDING_2_TILES_Y = {BuildingFlag::Size1x2, BuildingFlag::Size2x2};
static constexpr BuildingFlags BUILDING_HAS_4_TILES = {BuildingFlag::Size2x2}; static constexpr BuildingFlags BUILDING_HAS_4_TILES = {BuildingFlag::Size2x2};
enum HouseZonesBits : uint8_t { enum class HouseZone : uint8_t {
HZB_BEGIN = 0, TownEdge = 0,
HZB_TOWN_EDGE = 0, TownOutskirt = 1,
HZB_TOWN_OUTSKIRT, TownOuterSuburb = 2,
HZB_TOWN_OUTER_SUBURB, TownInnerSuburb = 3,
HZB_TOWN_INNER_SUBURB, TownCentre = 4,
HZB_TOWN_CENTRE, TownEnd,
HZB_END,
};
static_assert(HZB_END == 5);
DECLARE_INCREMENT_DECREMENT_OPERATORS(HouseZonesBits) ClimateSubarcticAboveSnow = 11, ///< Building can appear in sub-arctic climate above the snow line
ClimateTemperate = 12, ///< Building can appear in temperate climate
enum HouseZones : uint16_t { ClimateSubarcticBelowSnow = 13, ///< Building can appear in sub-arctic climate below the snow line
HZ_NOZNS = 0x0000, ///< 0 This is just to get rid of zeros, meaning none ClimateSubtropic = 14, ///< Building can appear in subtropical climate
HZ_ZON1 = 1U << HZB_TOWN_EDGE, ///< 0..4 1,2,4,8,10 which town zones the building can be built in, Zone1 been the further suburb ClimateToyland = 15, ///< Building can appear in toyland climate
HZ_ZON2 = 1U << HZB_TOWN_OUTSKIRT, };
HZ_ZON3 = 1U << HZB_TOWN_OUTER_SUBURB, using HouseZones = EnumBitSet<HouseZone, uint16_t>;
HZ_ZON4 = 1U << HZB_TOWN_INNER_SUBURB,
HZ_ZON5 = 1U << HZB_TOWN_CENTRE, ///< center of town static constexpr uint NUM_HOUSE_ZONES = to_underlying(HouseZone::TownEnd);
HZ_ZONALL = 0x001F, ///< 1F This is just to englobe all above types at once static_assert(NUM_HOUSE_ZONES == 5);
HZ_SUBARTC_ABOVE = 0x0800, ///< 11 800 can appear in sub-arctic climate above the snow line
HZ_TEMP = 0x1000, ///< 12 1000 can appear in temperate climate static constexpr HouseZones HZ_ZONE_ALL = {
HZ_SUBARTC_BELOW = 0x2000, ///< 13 2000 can appear in sub-arctic climate below the snow line HouseZone::TownEdge,
HZ_SUBTROPIC = 0x4000, ///< 14 4000 can appear in subtropical climate HouseZone::TownOutskirt,
HZ_TOYLND = 0x8000, ///< 15 8000 can appear in toyland climate HouseZone::TownOuterSuburb,
HZ_CLIMALL = 0xF800, ///< Bitmask of all climate bits HouseZone::TownInnerSuburb,
HouseZone::TownCentre,
};
static constexpr HouseZones HZ_CLIMATE_ALL = {
HouseZone::ClimateSubarcticAboveSnow,
HouseZone::ClimateTemperate,
HouseZone::ClimateSubarcticBelowSnow,
HouseZone::ClimateSubtropic,
HouseZone::ClimateToyland,
}; };
DECLARE_ENUM_AS_BIT_SET(HouseZones)
enum class HouseExtraFlag : uint8_t { enum class HouseExtraFlag : uint8_t {
BuildingIsHistorical = 0, ///< this house will only appear during town generation in random games, thus the historical BuildingIsHistorical = 0, ///< this house will only appear during town generation in random games, thus the historical
@ -139,5 +144,6 @@ inline HouseID GetTranslatedHouseID(HouseID hid)
} }
void ShowBuildHousePicker(struct Window *); void ShowBuildHousePicker(struct Window *);
HouseZones GetClimateMaskForLandscape();
#endif /* HOUSE_H */ #endif /* HOUSE_H */

View File

@ -2704,19 +2704,13 @@ struct IndustryCargoesWindow : public Window {
*/ */
static bool HousesCanAccept(const std::span<const CargoType> cargoes) static bool HousesCanAccept(const std::span<const CargoType> cargoes)
{ {
HouseZones climate_mask; HouseZones climate_mask = GetClimateMaskForLandscape();
switch (_settings_game.game_creation.landscape) {
case LandscapeType::Temperate: climate_mask = HZ_TEMP; break;
case LandscapeType::Arctic: climate_mask = HZ_SUBARTC_ABOVE | HZ_SUBARTC_BELOW; break;
case LandscapeType::Tropic: climate_mask = HZ_SUBTROPIC; break;
case LandscapeType::Toyland: climate_mask = HZ_TOYLND; break;
default: NOT_REACHED();
}
for (const CargoType cargo_type : cargoes) { for (const CargoType cargo_type : cargoes) {
if (!IsValidCargoType(cargo_type)) continue; if (!IsValidCargoType(cargo_type)) continue;
for (const auto &hs : HouseSpec::Specs()) { for (const auto &hs : HouseSpec::Specs()) {
if (!hs.enabled || !(hs.building_availability & climate_mask)) continue; if (!hs.enabled || !hs.building_availability.Any(climate_mask)) continue;
for (uint j = 0; j < lengthof(hs.accepts_cargo); j++) { for (uint j = 0; j < lengthof(hs.accepts_cargo); j++) {
if (hs.cargo_acceptance[j] > 0 && cargo_type == hs.accepts_cargo[j]) return true; if (hs.cargo_acceptance[j] > 0 && cargo_type == hs.accepts_cargo[j]) return true;

View File

@ -976,7 +976,7 @@ static bool IsHouseSpecValid(HouseSpec &hs, const HouseSpec *next1, const HouseS
} }
/* Make sure that additional parts of multitile houses are not available. */ /* Make sure that additional parts of multitile houses are not available. */
if (!hs.building_flags.Any(BUILDING_HAS_1_TILE) && (hs.building_availability & HZ_ZONALL) != 0 && (hs.building_availability & HZ_CLIMALL) != 0) { if (!hs.building_flags.Any(BUILDING_HAS_1_TILE) && hs.building_availability.Any(HZ_ZONE_ALL) && hs.building_availability.Any(HZ_CLIMATE_ALL)) {
hs.enabled = false; hs.enabled = false;
if (!filename.empty()) Debug(grf, 1, "FinaliseHouseArray: {} defines house {} without a size but marked it as available. Disabling house.", filename, hs.grf_prop.local_id); if (!filename.empty()) Debug(grf, 1, "FinaliseHouseArray: {} defines house {} without a size but marked it as available. Disabling house.", filename, hs.grf_prop.local_id);
return false; return false;
@ -997,7 +997,7 @@ static void EnsureEarlyHouse(HouseZones bitmask)
for (const auto &hs : HouseSpec::Specs()) { for (const auto &hs : HouseSpec::Specs()) {
if (!hs.enabled) continue; if (!hs.enabled) continue;
if ((hs.building_availability & bitmask) != bitmask) continue; if (!hs.building_availability.All(bitmask)) continue;
if (hs.min_year < min_year) min_year = hs.min_year; if (hs.min_year < min_year) min_year = hs.min_year;
} }
@ -1005,7 +1005,7 @@ static void EnsureEarlyHouse(HouseZones bitmask)
for (auto &hs : HouseSpec::Specs()) { for (auto &hs : HouseSpec::Specs()) {
if (!hs.enabled) continue; if (!hs.enabled) continue;
if ((hs.building_availability & bitmask) != bitmask) continue; if (!hs.building_availability.All(bitmask)) continue;
if (hs.min_year == min_year) hs.min_year = CalendarTime::MIN_YEAR; if (hs.min_year == min_year) hs.min_year = CalendarTime::MIN_YEAR;
} }
} }
@ -1077,19 +1077,11 @@ static void FinaliseHouseArray()
} }
} }
HouseZones climate_mask = (HouseZones)(1 << (to_underlying(_settings_game.game_creation.landscape) + 12)); HouseZones climate_mask = GetClimateMaskForLandscape();
EnsureEarlyHouse(HZ_ZON1 | climate_mask); for (HouseZone climate : climate_mask) {
EnsureEarlyHouse(HZ_ZON2 | climate_mask); for (HouseZone zone : HZ_ZONE_ALL) {
EnsureEarlyHouse(HZ_ZON3 | climate_mask); EnsureEarlyHouse({climate, zone});
EnsureEarlyHouse(HZ_ZON4 | climate_mask); }
EnsureEarlyHouse(HZ_ZON5 | climate_mask);
if (_settings_game.game_creation.landscape == LandscapeType::Arctic) {
EnsureEarlyHouse(HZ_ZON1 | HZ_SUBARTC_ABOVE);
EnsureEarlyHouse(HZ_ZON2 | HZ_SUBARTC_ABOVE);
EnsureEarlyHouse(HZ_ZON3 | HZ_SUBARTC_ABOVE);
EnsureEarlyHouse(HZ_ZON4 | HZ_SUBARTC_ABOVE);
EnsureEarlyHouse(HZ_ZON5 | HZ_SUBARTC_ABOVE);
} }
} }

View File

@ -170,7 +170,7 @@ static uint32_t GetAirportTileIDAtOffset(TileIndex tile, const Station *st, uint
case 0x41: return GetTerrainType(this->tile); case 0x41: return GetTerrainType(this->tile);
/* Current town zone of the tile in the nearest town */ /* Current town zone of the tile in the nearest town */
case 0x42: return GetTownRadiusGroup(ClosestTownFromTile(this->tile, UINT_MAX), this->tile); case 0x42: return to_underlying(GetTownRadiusGroup(ClosestTownFromTile(this->tile, UINT_MAX), this->tile));
/* Position relative to most northern airport tile. */ /* Position relative to most northern airport tile. */
case 0x43: return GetRelativePosition(this->tile, this->st->airport.tile); case 0x43: return GetRelativePosition(this->tile, this->st->airport.tile);

View File

@ -345,7 +345,7 @@ static uint32_t GetDistanceFromNearbyHouse(uint8_t parameter, TileIndex start_ti
case 0x41: return IsTileType(this->tile, MP_HOUSE) ? GetHouseAge(this->tile).base() : 0; case 0x41: return IsTileType(this->tile, MP_HOUSE) ? GetHouseAge(this->tile).base() : 0;
/* Town zone */ /* Town zone */
case 0x42: return GetTownRadiusGroup(this->town, this->tile); case 0x42: return to_underlying(GetTownRadiusGroup(this->town, this->tile));
/* Terrain type */ /* Terrain type */
case 0x43: return GetTerrainType(this->tile); case 0x43: return GetTerrainType(this->tile);

View File

@ -185,7 +185,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(uint8_t param_set_id, uint8
case 0x87: return GetTerrainType(this->tile); case 0x87: return GetTerrainType(this->tile);
/* Town zone */ /* Town zone */
case 0x88: return GetTownRadiusGroup(this->industry->town, this->tile); case 0x88: return to_underlying(GetTownRadiusGroup(this->industry->town, this->tile));
/* Manhattan distance of the closest town */ /* Manhattan distance of the closest town */
case 0x89: return ClampTo<uint8_t>(DistanceManhattan(this->industry->town->xy, this->tile)); case 0x89: return ClampTo<uint8_t>(DistanceManhattan(this->industry->town->xy, this->tile));
@ -295,7 +295,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(uint8_t param_set_id, uint8
case 0x65: { case 0x65: {
if (this->tile == INVALID_TILE) break; if (this->tile == INVALID_TILE) break;
TileIndex tile = GetNearbyTile(parameter, this->tile, true); TileIndex tile = GetNearbyTile(parameter, this->tile, true);
return GetTownRadiusGroup(this->industry->town, tile) << 16 | ClampTo<uint16_t>(DistanceManhattan(tile, this->industry->town->xy)); return to_underlying(GetTownRadiusGroup(this->industry->town, tile)) << 16 | ClampTo<uint16_t>(DistanceManhattan(tile, this->industry->town->xy));
} }
/* Get square of Euclidean distance of closest town */ /* Get square of Euclidean distance of closest town */
case 0x66: { case 0x66: {

View File

@ -69,7 +69,7 @@ uint32_t GetRelativePosition(TileIndex tile, TileIndex ind_tile)
case 0x41: return GetTerrainType(this->tile); case 0x41: return GetTerrainType(this->tile);
/* Current town zone of the tile in the nearest town */ /* Current town zone of the tile in the nearest town */
case 0x42: return GetTownRadiusGroup(ClosestTownFromTile(this->tile, UINT_MAX), this->tile); case 0x42: return to_underlying(GetTownRadiusGroup(ClosestTownFromTile(this->tile, UINT_MAX), this->tile));
/* Relative position */ /* Relative position */
case 0x43: return GetRelativePosition(this->tile, this->industry->location.tile); case 0x43: return GetRelativePosition(this->tile, this->industry->location.tile);

View File

@ -331,7 +331,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(uint8_t local_id, uint32_t
case 0x44: return GetTileOwner(this->tile).base(); case 0x44: return GetTileOwner(this->tile).base();
/* Get town zone and Manhattan distance of closest town */ /* Get town zone and Manhattan distance of closest town */
case 0x45: return GetTownRadiusGroup(t, this->tile) << 16 | ClampTo<uint16_t>(DistanceManhattan(this->tile, t->xy)); case 0x45: return to_underlying(GetTownRadiusGroup(t, this->tile)) << 16 | ClampTo<uint16_t>(DistanceManhattan(this->tile, t->xy));
/* Get square of Euclidean distance of closest town */ /* Get square of Euclidean distance of closest town */
case 0x46: return DistanceSquare(this->tile, t->xy); case 0x46: return DistanceSquare(this->tile, t->xy);

View File

@ -33,7 +33,7 @@
case 0x41: return 0; case 0x41: return 0;
case 0x42: return 0; case 0x42: return 0;
case 0x43: return TimerGameCalendar::date.base(); case 0x43: return TimerGameCalendar::date.base();
case 0x44: return HZB_TOWN_EDGE; case 0x44: return to_underlying(HouseZone::TownEdge);
case 0x45: { case 0x45: {
auto rt = GetRailTypeInfoIndex(this->rti); auto rt = GetRailTypeInfoIndex(this->rti);
uint8_t local = GetReverseRailTypeTranslation(rt, this->ro.grffile); uint8_t local = GetReverseRailTypeTranslation(rt, this->ro.grffile);
@ -57,7 +57,7 @@
} else if (IsLevelCrossingTile(this->tile)) { } else if (IsLevelCrossingTile(this->tile)) {
t = ClosestTownFromTile(this->tile, UINT_MAX); t = ClosestTownFromTile(this->tile, UINT_MAX);
} }
return t != nullptr ? GetTownRadiusGroup(t, this->tile) : HZB_TOWN_EDGE; return to_underlying(t != nullptr ? GetTownRadiusGroup(t, this->tile) : HouseZone::TownEdge);
} }
case 0x45: case 0x45:
return GetTrackTypes(this->tile, ro.grffile); return GetTrackTypes(this->tile, ro.grffile);

View File

@ -106,9 +106,9 @@ uint32_t RoadStopScopeResolver::GetVariable(uint8_t variable, [[maybe_unused]] u
/* Town zone and Manhattan distance of closest town */ /* Town zone and Manhattan distance of closest town */
case 0x45: { case 0x45: {
if (this->tile == INVALID_TILE) return HZB_TOWN_EDGE << 16; if (this->tile == INVALID_TILE) return to_underlying(HouseZone::TownEdge) << 16;
const Town *t = (this->st == nullptr) ? ClosestTownFromTile(this->tile, UINT_MAX) : this->st->town; const Town *t = (this->st == nullptr) ? ClosestTownFromTile(this->tile, UINT_MAX) : this->st->town;
return t != nullptr ? (GetTownRadiusGroup(t, this->tile) << 16 | ClampTo<uint16_t>(DistanceManhattan(this->tile, t->xy))) : HZB_TOWN_EDGE << 16; return t != nullptr ? (to_underlying(GetTownRadiusGroup(t, this->tile)) << 16 | ClampTo<uint16_t>(DistanceManhattan(this->tile, t->xy))) : to_underlying(HouseZone::TownEdge) << 16;
} }
/* Get square of Euclidean distance of closest town */ /* Get square of Euclidean distance of closest town */

View File

@ -67,7 +67,7 @@ uint32_t GetTrackTypes(TileIndex tile, const GRFFile *grffile)
case 0x41: return 0; case 0x41: return 0;
case 0x42: return 0; case 0x42: return 0;
case 0x43: return TimerGameCalendar::date.base(); case 0x43: return TimerGameCalendar::date.base();
case 0x44: return HZB_TOWN_EDGE; case 0x44: return to_underlying(HouseZone::TownEdge);
case 0x45: { case 0x45: {
auto rt = GetRoadTypeInfoIndex(this->rti); auto rt = GetRoadTypeInfoIndex(this->rti);
uint8_t local = GetReverseRoadTypeTranslation(rt, this->ro.grffile); uint8_t local = GetReverseRoadTypeTranslation(rt, this->ro.grffile);
@ -95,7 +95,7 @@ uint32_t GetTrackTypes(TileIndex tile, const GRFFile *grffile)
} else { } else {
t = ClosestTownFromTile(this->tile, UINT_MAX); t = ClosestTownFromTile(this->tile, UINT_MAX);
} }
return t != nullptr ? GetTownRadiusGroup(t, this->tile) : HZB_TOWN_EDGE; return to_underlying(t != nullptr ? GetTownRadiusGroup(t, this->tile) : HouseZone::TownEdge);
} }
case 0x45: case 0x45:
return GetTrackTypes(this->tile, ro.grffile); return GetTrackTypes(this->tile, ro.grffile);

View File

@ -57,16 +57,16 @@
case 0x8A: return this->t->grow_counter / Ticks::TOWN_GROWTH_TICKS; case 0x8A: return this->t->grow_counter / Ticks::TOWN_GROWTH_TICKS;
case 0x92: return this->t->flags; // In original game, 0x92 and 0x93 are really one word. Since flags is a byte, this is to adjust case 0x92: return this->t->flags; // In original game, 0x92 and 0x93 are really one word. Since flags is a byte, this is to adjust
case 0x93: return 0; case 0x93: return 0;
case 0x94: return ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[HZB_TOWN_EDGE]); case 0x94: return ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownEdge)]);
case 0x95: return GB(ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[HZB_TOWN_EDGE]), 8, 8); case 0x95: return GB(ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownEdge)]), 8, 8);
case 0x96: return ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[HZB_TOWN_OUTSKIRT]); case 0x96: return ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownOutskirt)]);
case 0x97: return GB(ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[HZB_TOWN_OUTSKIRT]), 8, 8); case 0x97: return GB(ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownOutskirt)]), 8, 8);
case 0x98: return ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[HZB_TOWN_OUTER_SUBURB]); case 0x98: return ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownOuterSuburb)]);
case 0x99: return GB(ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[HZB_TOWN_OUTER_SUBURB]), 8, 8); case 0x99: return GB(ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownOuterSuburb)]), 8, 8);
case 0x9A: return ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[HZB_TOWN_INNER_SUBURB]); case 0x9A: return ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownInnerSuburb)]);
case 0x9B: return GB(ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[HZB_TOWN_INNER_SUBURB]), 8, 8); case 0x9B: return GB(ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownInnerSuburb)]), 8, 8);
case 0x9C: return ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[HZB_TOWN_CENTRE]); case 0x9C: return ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownCentre)]);
case 0x9D: return GB(ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[HZB_TOWN_CENTRE]), 8, 8); case 0x9D: return GB(ClampTo<uint16_t>(this->t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownCentre)]), 8, 8);
case 0x9E: return this->t->ratings[0]; case 0x9E: return this->t->ratings[0];
case 0x9F: return GB(this->t->ratings[0], 8, 8); case 0x9F: return GB(this->t->ratings[0], 8, 8);
case 0xA0: return this->t->ratings[1]; case 0xA0: return this->t->ratings[1];

View File

@ -621,7 +621,7 @@ CommandCost CmdBuildRoad(DoCommandFlags flags, TileIndex tile, RoadBits pieces,
company = OWNER_TOWN; company = OWNER_TOWN;
/* If we are not within a town, we are not owned by the town */ /* If we are not within a town, we are not owned by the town */
if (town == nullptr || DistanceSquare(tile, town->xy) > town->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) { if (town == nullptr || DistanceSquare(tile, town->xy) > town->cache.squared_town_zone_radius[to_underlying(HouseZone::TownEdge)]) {
company = OWNER_NONE; company = OWNER_NONE;
} }
} }
@ -1956,7 +1956,7 @@ static const Roadside _town_road_types[][2] = {
{ ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED } { ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED }
}; };
static_assert(lengthof(_town_road_types) == HZB_END); static_assert(lengthof(_town_road_types) == NUM_HOUSE_ZONES);
static const Roadside _town_road_types_2[][2] = { static const Roadside _town_road_types_2[][2] = {
{ ROADSIDE_GRASS, ROADSIDE_GRASS }, { ROADSIDE_GRASS, ROADSIDE_GRASS },
@ -1966,7 +1966,7 @@ static const Roadside _town_road_types_2[][2] = {
{ ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED } { ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED }
}; };
static_assert(lengthof(_town_road_types_2) == HZB_END); static_assert(lengthof(_town_road_types_2) == NUM_HOUSE_ZONES);
static void TileLoop_Road(TileIndex tile) static void TileLoop_Road(TileIndex tile)
@ -1997,14 +1997,14 @@ static void TileLoop_Road(TileIndex tile)
const Town *t = ClosestTownFromTile(tile, UINT_MAX); const Town *t = ClosestTownFromTile(tile, UINT_MAX);
if (!HasRoadWorks(tile)) { if (!HasRoadWorks(tile)) {
HouseZonesBits grp = HZB_TOWN_EDGE; HouseZone grp = HouseZone::TownEdge;
if (t != nullptr) { if (t != nullptr) {
grp = GetTownRadiusGroup(t, tile); grp = GetTownRadiusGroup(t, tile);
/* Show an animation to indicate road work */ /* Show an animation to indicate road work */
if (t->road_build_months != 0 && if (t->road_build_months != 0 &&
(DistanceManhattan(t->xy, tile) < 8 || grp != HZB_TOWN_EDGE) && (DistanceManhattan(t->xy, tile) < 8 || grp != HouseZone::TownEdge) &&
IsNormalRoad(tile) && !HasAtMostOneBit(GetAllRoadBits(tile))) { IsNormalRoad(tile) && !HasAtMostOneBit(GetAllRoadBits(tile))) {
if (std::get<0>(GetFoundationSlope(tile)) == SLOPE_FLAT && EnsureNoVehicleOnGround(tile).Succeeded() && Chance16(1, 40)) { if (std::get<0>(GetFoundationSlope(tile)) == SLOPE_FLAT && EnsureNoVehicleOnGround(tile).Succeeded() && Chance16(1, 40)) {
StartRoadWorks(tile); StartRoadWorks(tile);
@ -2023,7 +2023,7 @@ static void TileLoop_Road(TileIndex tile)
{ {
/* Adjust road ground type depending on 'grp' (grp is the distance to the center) */ /* Adjust road ground type depending on 'grp' (grp is the distance to the center) */
const Roadside *new_rs = (_settings_game.game_creation.landscape == LandscapeType::Toyland) ? _town_road_types_2[grp] : _town_road_types[grp]; const Roadside *new_rs = (_settings_game.game_creation.landscape == LandscapeType::Toyland) ? _town_road_types_2[to_underlying(grp)] : _town_road_types[to_underlying(grp)];
Roadside cur_rs = GetRoadside(tile); Roadside cur_rs = GetRoadside(tile);
/* We have our desired type, do nothing */ /* We have our desired type, do nothing */

View File

@ -206,7 +206,7 @@
if (!IsValidTown(town_id)) return false; if (!IsValidTown(town_id)) return false;
const Town *t = ::Town::Get(town_id); const Town *t = ::Town::Get(town_id);
return ((uint32_t)GetDistanceSquareToTile(town_id, tile) <= t->cache.squared_town_zone_radius[HZB_TOWN_EDGE]); return ((uint32_t)GetDistanceSquareToTile(town_id, tile) <= t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownEdge)]);
} }
/* static */ bool ScriptTown::HasStatue(TownID town_id) /* static */ bool ScriptTown::HasStatue(TownID town_id)

View File

@ -3644,14 +3644,14 @@ static void TileLoop_Station(TileIndex tile)
default: break; default: break;
} }
HouseZonesBits new_zone = HZB_TOWN_EDGE; HouseZone new_zone = HouseZone::TownEdge;
const Town *t = ClosestTownFromTile(tile, UINT_MAX); const Town *t = ClosestTownFromTile(tile, UINT_MAX);
if (t != nullptr) { if (t != nullptr) {
new_zone = GetTownRadiusGroup(t, tile); new_zone = GetTownRadiusGroup(t, tile);
} }
/* Adjust road ground type depending on 'new_zone' */ /* Adjust road ground type depending on 'new_zone' */
Roadside new_rs = new_zone > HZB_TOWN_EDGE ? ROADSIDE_PAVED : ROADSIDE_GRASS; Roadside new_rs = new_zone != HouseZone::TownEdge ? ROADSIDE_PAVED : ROADSIDE_GRASS;
Roadside cur_rs = GetRoadWaypointRoadside(tile); Roadside cur_rs = GetRoadWaypointRoadside(tile);
if (new_rs != cur_rs) { if (new_rs != cur_rs) {

View File

@ -1834,443 +1834,443 @@ extern const HouseSpec _original_house_specs[] = {
*/ */
MS(1963, CalendarTime::MAX_YEAR, 187, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 140, 70, 8, 3, 4, MS(1963, CalendarTime::MAX_YEAR, 187, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 140, 70, 8, 3, 4,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON5, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownCentre}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 00 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 00
MS(1957, CalendarTime::MAX_YEAR, 85, 140, STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_1, 130, 55, 8, 3, 4, MS(1957, CalendarTime::MAX_YEAR, 85, 140, STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_1, 130, 55, 8, 3, 4,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON5 | HZ_ZON4, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownCentre, HouseZone::TownInnerSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 01 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 01
MS(1968, CalendarTime::MAX_YEAR, 40, 100, STR_TOWN_BUILDING_NAME_SMALL_BLOCK_OF_FLATS_1, 90, 20, 8, 3, 1, MS(1968, CalendarTime::MAX_YEAR, 40, 100, STR_TOWN_BUILDING_NAME_SMALL_BLOCK_OF_FLATS_1, 90, 20, 8, 3, 1,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 02 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 02
MS( 0, CalendarTime::MAX_YEAR, 5, 90, STR_TOWN_BUILDING_NAME_CHURCH_1, 230, 2, 2, 0, 0, MS( 0, CalendarTime::MAX_YEAR, 5, 90, STR_TOWN_BUILDING_NAME_CHURCH_1, 230, 2, 2, 0, 0,
BuildingFlags({BuildingFlag::IsChurch, BuildingFlag::Size1x1}), BuildingFlags({BuildingFlag::IsChurch, BuildingFlag::Size1x1}),
HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 03 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 03
MS(1975, CalendarTime::MAX_YEAR, 220, 160, STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1, 160, 85, 10, 4, 6, MS(1975, CalendarTime::MAX_YEAR, 220, 160, STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1, 160, 85, 10, 4, 6,
BuildingFlags({BuildingFlag::IsAnimated, BuildingFlag::Size1x1}), BuildingFlags({BuildingFlag::IsAnimated, BuildingFlag::Size1x1}),
HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5, HouseZones({HouseZone::ClimateTemperate, HouseZone::ClimateSubarcticBelowSnow, HouseZone::ClimateSubtropic, HouseZone::TownCentre}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 04 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 04
MS(1975, CalendarTime::MAX_YEAR, 220, 160, STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1, 160, 85, 10, 4, 6, MS(1975, CalendarTime::MAX_YEAR, 220, 160, STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1, 160, 85, 10, 4, 6,
BuildingFlags({BuildingFlag::IsAnimated, BuildingFlag::Size1x1}), BuildingFlags({BuildingFlag::IsAnimated, BuildingFlag::Size1x1}),
HZ_SUBARTC_ABOVE | HZ_ZON5, HouseZones({HouseZone::ClimateSubarcticAboveSnow, HouseZone::TownCentre}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 05 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 05
MS( 0, CalendarTime::MAX_YEAR, 30, 80, STR_TOWN_BUILDING_NAME_TOWN_HOUSES_1, 80, 12, 4, 1, 0, MS( 0, CalendarTime::MAX_YEAR, 30, 80, STR_TOWN_BUILDING_NAME_TOWN_HOUSES_1, 80, 12, 4, 1, 0,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 06 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 06
MS(1959, CalendarTime::MAX_YEAR, 140, 180, STR_TOWN_BUILDING_NAME_HOTEL_1, 150, 22, 6, 1, 2, MS(1959, CalendarTime::MAX_YEAR, 140, 180, STR_TOWN_BUILDING_NAME_HOTEL_1, 150, 22, 6, 1, 2,
BuildingFlag::Size1x2, BuildingFlag::Size1x2,
HZ_TEMP | HZ_ZON5 | HZ_ZON3, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownCentre, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 07 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 07
MS(1959, CalendarTime::MAX_YEAR, 0, 180, STR_TOWN_BUILDING_NAME_HOTEL_1, 150, 22, 6, 1, 2, MS(1959, CalendarTime::MAX_YEAR, 0, 180, STR_TOWN_BUILDING_NAME_HOTEL_1, 150, 22, 6, 1, 2,
{}, {},
HZ_NOZNS, {},
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 08 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 08
MS(1945, CalendarTime::MAX_YEAR, 0, 65, STR_TOWN_BUILDING_NAME_STATUE_1, 40, 0, 2, 0, 0, MS(1945, CalendarTime::MAX_YEAR, 0, 65, STR_TOWN_BUILDING_NAME_STATUE_1, 40, 0, 2, 0, 0,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4, HouseZones({HouseZone::ClimateTemperate, HouseZone::ClimateSubarcticBelowSnow, HouseZone::ClimateSubtropic, HouseZone::TownCentre, HouseZone::TownInnerSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 09 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 09
MS(1945, CalendarTime::MAX_YEAR, 0, 65, STR_TOWN_BUILDING_NAME_FOUNTAIN_1, 40, 0, 2, 0, 0, MS(1945, CalendarTime::MAX_YEAR, 0, 65, STR_TOWN_BUILDING_NAME_FOUNTAIN_1, 40, 0, 2, 0, 0,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5, HouseZones({HouseZone::ClimateTemperate, HouseZone::ClimateSubarcticBelowSnow, HouseZone::ClimateSubtropic, HouseZone::TownCentre}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0A CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0A
MS( 0, CalendarTime::MAX_YEAR, 0, 60, STR_TOWN_BUILDING_NAME_PARK_1, 75, 0, 2, 0, 0, MS( 0, CalendarTime::MAX_YEAR, 0, 60, STR_TOWN_BUILDING_NAME_PARK_1, 75, 0, 2, 0, 0,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON3, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0B CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0B
MS(1935, CalendarTime::MAX_YEAR, 0, 60, STR_TOWN_BUILDING_NAME_PARK_1, 75, 0, 2, 0, 0, MS(1935, CalendarTime::MAX_YEAR, 0, 60, STR_TOWN_BUILDING_NAME_PARK_1, 75, 0, 2, 0, 0,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON4, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownInnerSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0C CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0C
MS(1951, CalendarTime::MAX_YEAR, 150, 130, STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_2, 110, 65, 8, 2, 4, MS(1951, CalendarTime::MAX_YEAR, 150, 130, STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_2, 110, 65, 8, 2, 4,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON5 | HZ_ZON4, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownCentre, HouseZone::TownInnerSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0D CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0D
MS(1930, 1960, 95, 110, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 100, 48, 6, 2, 3, MS(1930, 1960, 95, 110, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 100, 48, 6, 2, 3,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0E CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0E
MS(1930, 1960, 95, 105, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 100, 48, 6, 2, 3, MS(1930, 1960, 95, 105, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 100, 48, 6, 2, 3,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0F CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0F
MS(1930, 1960, 95, 107, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 100, 48, 6, 2, 3, MS(1930, 1960, 95, 107, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 100, 48, 6, 2, 3,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 10 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 10
MS(1977, CalendarTime::MAX_YEAR, 130, 200, STR_TOWN_BUILDING_NAME_MODERN_OFFICE_BUILDING_1, 150, 50, 10, 3, 6, MS(1977, CalendarTime::MAX_YEAR, 130, 200, STR_TOWN_BUILDING_NAME_MODERN_OFFICE_BUILDING_1, 150, 50, 10, 3, 6,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5, HouseZones({HouseZone::ClimateTemperate, HouseZone::ClimateSubarcticBelowSnow, HouseZone::ClimateSubtropic, HouseZone::TownCentre}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 11 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 11
MS(1983, CalendarTime::MAX_YEAR, 6, 145, STR_TOWN_BUILDING_NAME_WAREHOUSE_1, 110, 10, 6, 3, 8, MS(1983, CalendarTime::MAX_YEAR, 6, 145, STR_TOWN_BUILDING_NAME_WAREHOUSE_1, 110, 10, 6, 3, 8,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON5, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownCentre}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 12 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 12
MS(1985, CalendarTime::MAX_YEAR, 110, 155, STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_3, 110, 55, 6, 2, 6, MS(1985, CalendarTime::MAX_YEAR, 110, 155, STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_3, 110, 55, 6, 2, 6,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON5, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownCentre}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 13 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 13
MS( 0, CalendarTime::MAX_YEAR, 65, 250, STR_TOWN_BUILDING_NAME_STADIUM_1, 300, 5, 4, 0, 0, MS( 0, CalendarTime::MAX_YEAR, 65, 250, STR_TOWN_BUILDING_NAME_STADIUM_1, 300, 5, 4, 0, 0,
BuildingFlags({BuildingFlag::IsStadium, BuildingFlag::Size2x2}), BuildingFlags({BuildingFlag::IsStadium, BuildingFlag::Size2x2}),
HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 14 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 14
MS( 0, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_1, 300, 5, 4, 0, 0, MS( 0, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_1, 300, 5, 4, 0, 0,
{}, {},
HZ_NOZNS, {},
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 15 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 15
MS( 0, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_1, 300, 5, 4, 0, 0, MS( 0, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_1, 300, 5, 4, 0, 0,
{}, {},
HZ_NOZNS, {},
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 16 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 16
MS( 0, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_1, 300, 5, 4, 0, 0, MS( 0, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_1, 300, 5, 4, 0, 0,
{}, {},
HZ_NOZNS, {},
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 17 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 17
MS( 0, 1951, 15, 70, STR_TOWN_BUILDING_NAME_OLD_HOUSES_1, 75, 6, 3, 1, 0, MS( 0, 1951, 15, 70, STR_TOWN_BUILDING_NAME_OLD_HOUSES_1, 75, 6, 3, 1, 0,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 18 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 18
MS( 0, 1952, 12, 75, STR_TOWN_BUILDING_NAME_COTTAGES_1, 75, 7, 3, 1, 0, MS( 0, 1952, 12, 75, STR_TOWN_BUILDING_NAME_COTTAGES_1, 75, 7, 3, 1, 0,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON1, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 19 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 19
MS(1931, CalendarTime::MAX_YEAR, 13, 71, STR_TOWN_BUILDING_NAME_HOUSES_1, 75, 8, 3, 1, 0, MS(1931, CalendarTime::MAX_YEAR, 13, 71, STR_TOWN_BUILDING_NAME_HOUSES_1, 75, 8, 3, 1, 0,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1A CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1A
MS(1935, CalendarTime::MAX_YEAR, 100, 135, STR_TOWN_BUILDING_NAME_FLATS_1, 100, 35, 7, 2, 2, MS(1935, CalendarTime::MAX_YEAR, 100, 135, STR_TOWN_BUILDING_NAME_FLATS_1, 100, 35, 7, 2, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1B CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1B
MS(1963, CalendarTime::MAX_YEAR, 170, 145, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_2, 170, 50, 8, 3, 3, MS(1963, CalendarTime::MAX_YEAR, 170, 145, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_2, 170, 50, 8, 3, 3,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1C CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1C
MS( 0, 1955, 100, 132, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_2, 135, 40, 6, 2, 3, MS( 0, 1955, 100, 132, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_2, 135, 40, 6, 2, 3,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1D CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1D
MS(1973, CalendarTime::MAX_YEAR, 180, 155, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_3, 180, 64, 8, 3, 3, MS(1973, CalendarTime::MAX_YEAR, 180, 155, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_3, 180, 64, 8, 3, 3,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON3, HouseZones({HouseZone::ClimateTemperate, HouseZone::ClimateSubtropic, HouseZone::TownCentre, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1E CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1E
MS( 0, CalendarTime::MAX_YEAR, 35, 220, STR_TOWN_BUILDING_NAME_THEATER_1, 230, 23, 8, 2, 2, MS( 0, CalendarTime::MAX_YEAR, 35, 220, STR_TOWN_BUILDING_NAME_THEATER_1, 230, 23, 8, 2, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON5 | HZ_ZON4, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownCentre, HouseZone::TownInnerSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1F CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1F
MS(1958, CalendarTime::MAX_YEAR, 65, 250, STR_TOWN_BUILDING_NAME_STADIUM_2, 300, 5, 4, 0, 0, MS(1958, CalendarTime::MAX_YEAR, 65, 250, STR_TOWN_BUILDING_NAME_STADIUM_2, 300, 5, 4, 0, 0,
BuildingFlags({BuildingFlag::IsStadium, BuildingFlag::Size2x2}), BuildingFlags({BuildingFlag::IsStadium, BuildingFlag::Size2x2}),
HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateTemperate, HouseZone::ClimateSubarcticBelowSnow, HouseZone::ClimateSubtropic, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 20 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 20
MS(1958, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_2, 300, 5, 4, 0, 0, MS(1958, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_2, 300, 5, 4, 0, 0,
{}, {},
HZ_NOZNS, {},
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 21 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 21
MS(1958, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_2, 300, 5, 4, 0, 0, MS(1958, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_2, 300, 5, 4, 0, 0,
{}, {},
HZ_NOZNS, {},
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 22 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 22
MS(1958, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_2, 300, 5, 4, 0, 0, MS(1958, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_2, 300, 5, 4, 0, 0,
{}, {},
HZ_NOZNS, {},
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 23 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 23
MS(2000, CalendarTime::MAX_YEAR, 140, 170, STR_TOWN_BUILDING_NAME_OFFICES_1, 250, 65, 8, 3, 2, MS(2000, CalendarTime::MAX_YEAR, 140, 170, STR_TOWN_BUILDING_NAME_OFFICES_1, 250, 65, 8, 3, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4, HouseZones({HouseZone::ClimateTemperate, HouseZone::ClimateSubarcticBelowSnow, HouseZone::ClimateSubtropic, HouseZone::TownCentre, HouseZone::TownInnerSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 24 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 24
MS( 0, 1960, 15, 70, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 1, MS( 0, 1960, 15, 70, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 1,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_BELOW | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateSubarcticBelowSnow, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 25 CT_PASSENGERS, CT_MAIL, CT_FOOD), // 25
MS( 0, 1960, 15, 70, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 1, MS( 0, 1960, 15, 70, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 1,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_ABOVE | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateSubarcticAboveSnow, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 26 CT_PASSENGERS, CT_MAIL, CT_FOOD), // 26
MS(1945, CalendarTime::MAX_YEAR, 35, 210, STR_TOWN_BUILDING_NAME_CINEMA_1, 230, 23, 8, 2, 2, MS(1945, CalendarTime::MAX_YEAR, 35, 210, STR_TOWN_BUILDING_NAME_CINEMA_1, 230, 23, 8, 2, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 27 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 27
MS(1983, CalendarTime::MAX_YEAR, 180, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1, 300, 5, 8, 2, 3, MS(1983, CalendarTime::MAX_YEAR, 180, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1, 300, 5, 8, 2, 3,
BuildingFlag::Size2x2, BuildingFlag::Size2x2,
HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 |HZ_ZON2, HouseZones({HouseZone::ClimateTemperate, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb,HouseZone::TownOutskirt}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 28 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 28
MS(1983, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1, 300, 5, 8, 2, 3, MS(1983, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1, 300, 5, 8, 2, 3,
{}, {},
HZ_NOZNS, {},
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 29 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 29
MS(1983, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1, 300, 5, 8, 2, 3, MS(1983, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1, 300, 5, 8, 2, 3,
{}, {},
HZ_NOZNS, {},
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 2A CT_PASSENGERS, CT_MAIL, CT_GOODS), // 2A
MS(1983, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1, 300, 5, 8, 2, 3, MS(1983, CalendarTime::MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1, 300, 5, 8, 2, 3,
{}, {},
HZ_NOZNS, {},
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 2B CT_PASSENGERS, CT_MAIL, CT_GOODS), // 2B
MS( 0, CalendarTime::MAX_YEAR, 80, 100, STR_TOWN_BUILDING_NAME_FLATS_1, 90, 20, 5, 2, 2, MS( 0, CalendarTime::MAX_YEAR, 80, 100, STR_TOWN_BUILDING_NAME_FLATS_1, 90, 20, 5, 2, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_BELOW | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateSubarcticBelowSnow, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 2C CT_PASSENGERS, CT_MAIL, CT_FOOD), // 2C
MS( 0, CalendarTime::MAX_YEAR, 80, 100, STR_TOWN_BUILDING_NAME_FLATS_1, 90, 20, 5, 2, 2, MS( 0, CalendarTime::MAX_YEAR, 80, 100, STR_TOWN_BUILDING_NAME_FLATS_1, 90, 20, 5, 2, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateSubarcticAboveSnow, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 2D CT_PASSENGERS, CT_MAIL, CT_FOOD), // 2D
MS( 0, CalendarTime::MAX_YEAR, 16, 70, STR_TOWN_BUILDING_NAME_HOUSES_2, 70, 6, 3, 1, 2, MS( 0, CalendarTime::MAX_YEAR, 16, 70, STR_TOWN_BUILDING_NAME_HOUSES_2, 70, 6, 3, 1, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_BELOW | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateSubarcticBelowSnow, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 2E CT_PASSENGERS, CT_MAIL, CT_FOOD), // 2E
MS( 0, CalendarTime::MAX_YEAR, 16, 70, STR_TOWN_BUILDING_NAME_HOUSES_2, 70, 6, 3, 1, 2, MS( 0, CalendarTime::MAX_YEAR, 16, 70, STR_TOWN_BUILDING_NAME_HOUSES_2, 70, 6, 3, 1, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_ABOVE | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateSubarcticAboveSnow, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 2F CT_PASSENGERS, CT_MAIL, CT_FOOD), // 2F
MS( 0, 1963, 14, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 70, 6, 3, 1, 2, MS( 0, 1963, 14, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 70, 6, 3, 1, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_BELOW | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateSubarcticBelowSnow, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 30 CT_PASSENGERS, CT_MAIL, CT_FOOD), // 30
MS( 0, 1963, 14, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 70, 6, 3, 1, 2, MS( 0, 1963, 14, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 70, 6, 3, 1, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_ABOVE | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateSubarcticAboveSnow, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 31 CT_PASSENGERS, CT_MAIL, CT_FOOD), // 31
MS(1966, CalendarTime::MAX_YEAR, 135, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 120, 60, 8, 3, 4, MS(1966, CalendarTime::MAX_YEAR, 135, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 120, 60, 8, 3, 4,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4, HouseZones({HouseZone::ClimateSubarcticBelowSnow, HouseZone::ClimateSubtropic, HouseZone::TownCentre, HouseZone::TownInnerSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 32 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 32
MS(1966, CalendarTime::MAX_YEAR, 135, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 120, 60, 8, 3, 4, MS(1966, CalendarTime::MAX_YEAR, 135, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 120, 60, 8, 3, 4,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4, HouseZones({HouseZone::ClimateSubarcticAboveSnow, HouseZone::TownCentre, HouseZone::TownInnerSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 33 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 33
MS(1970, CalendarTime::MAX_YEAR, 170, 170, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 130, 70, 9, 3, 4, MS(1970, CalendarTime::MAX_YEAR, 170, 170, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 130, 70, 9, 3, 4,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_BELOW | HZ_ZON5 | HZ_ZON4, HouseZones({HouseZone::ClimateSubarcticBelowSnow, HouseZone::TownCentre, HouseZone::TownInnerSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 34 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 34
MS(1970, CalendarTime::MAX_YEAR, 170, 170, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 130, 70, 9, 3, 4, MS(1970, CalendarTime::MAX_YEAR, 170, 170, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 130, 70, 9, 3, 4,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4, HouseZones({HouseZone::ClimateSubarcticAboveSnow, HouseZone::TownCentre, HouseZone::TownInnerSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 35 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 35
MS(1974, CalendarTime::MAX_YEAR, 210, 200, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 140, 80, 10, 3, 5, MS(1974, CalendarTime::MAX_YEAR, 210, 200, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 140, 80, 10, 3, 5,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4, HouseZones({HouseZone::ClimateSubarcticBelowSnow, HouseZone::ClimateSubtropic, HouseZone::TownCentre, HouseZone::TownInnerSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 36 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 36
MS(1974, CalendarTime::MAX_YEAR, 210, 200, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 140, 80, 10, 3, 5, MS(1974, CalendarTime::MAX_YEAR, 210, 200, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 140, 80, 10, 3, 5,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4, HouseZones({HouseZone::ClimateSubarcticAboveSnow, HouseZone::TownCentre, HouseZone::TownInnerSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 37 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 37
MS( 0, CalendarTime::MAX_YEAR, 10, 60, STR_TOWN_BUILDING_NAME_HOUSES_2, 60, 5, 2, 1, 1, MS( 0, CalendarTime::MAX_YEAR, 10, 60, STR_TOWN_BUILDING_NAME_HOUSES_2, 60, 5, 2, 1, 1,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_BELOW | HZ_ZON1, HouseZones({HouseZone::ClimateSubarcticBelowSnow, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 38 CT_PASSENGERS, CT_MAIL, CT_FOOD), // 38
MS( 0, CalendarTime::MAX_YEAR, 10, 60, STR_TOWN_BUILDING_NAME_HOUSES_2, 60, 5, 2, 1, 1, MS( 0, CalendarTime::MAX_YEAR, 10, 60, STR_TOWN_BUILDING_NAME_HOUSES_2, 60, 5, 2, 1, 1,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_ABOVE | HZ_ZON1, HouseZones({HouseZone::ClimateSubarcticAboveSnow, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 39 CT_PASSENGERS, CT_MAIL, CT_FOOD), // 39
MS( 0, CalendarTime::MAX_YEAR, 25, 100, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 80, 20, 3, 1, 1, MS( 0, CalendarTime::MAX_YEAR, 25, 100, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 80, 20, 3, 1, 1,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_BELOW | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2, HouseZones({HouseZone::ClimateSubarcticBelowSnow, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 3A CT_PASSENGERS, CT_MAIL, CT_FOOD), // 3A
MS( 0, CalendarTime::MAX_YEAR, 25, 100, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 80, 20, 3, 1, 1, MS( 0, CalendarTime::MAX_YEAR, 25, 100, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 80, 20, 3, 1, 1,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2, HouseZones({HouseZone::ClimateSubarcticAboveSnow, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 3B CT_PASSENGERS, CT_MAIL, CT_FOOD), // 3B
MS( 0, CalendarTime::MAX_YEAR, 6, 85, STR_TOWN_BUILDING_NAME_CHURCH_1, 230, 2, 2, 0, 0, MS( 0, CalendarTime::MAX_YEAR, 6, 85, STR_TOWN_BUILDING_NAME_CHURCH_1, 230, 2, 2, 0, 0,
BuildingFlags({BuildingFlag::IsChurch, BuildingFlag::Size1x1}), BuildingFlags({BuildingFlag::IsChurch, BuildingFlag::Size1x1}),
HZ_SUBARTC_BELOW | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateSubarcticBelowSnow, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 3C CT_PASSENGERS, CT_MAIL, CT_GOODS), // 3C
MS( 0, CalendarTime::MAX_YEAR, 6, 85, STR_TOWN_BUILDING_NAME_CHURCH_1, 230, 2, 2, 0, 0, MS( 0, CalendarTime::MAX_YEAR, 6, 85, STR_TOWN_BUILDING_NAME_CHURCH_1, 230, 2, 2, 0, 0,
BuildingFlags({BuildingFlag::IsChurch, BuildingFlag::Size1x1}), BuildingFlags({BuildingFlag::IsChurch, BuildingFlag::Size1x1}),
HZ_SUBARTC_ABOVE | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateSubarcticAboveSnow, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 3D CT_PASSENGERS, CT_MAIL, CT_GOODS), // 3D
MS( 0, CalendarTime::MAX_YEAR, 17, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 7, 3, 1, 1, MS( 0, CalendarTime::MAX_YEAR, 17, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 7, 3, 1, 1,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_BELOW | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateSubarcticBelowSnow, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 3E CT_PASSENGERS, CT_MAIL, CT_FOOD), // 3E
MS( 0, CalendarTime::MAX_YEAR, 17, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 7, 3, 1, 1, MS( 0, CalendarTime::MAX_YEAR, 17, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 7, 3, 1, 1,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_ABOVE | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateSubarcticAboveSnow, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 3F CT_PASSENGERS, CT_MAIL, CT_FOOD), // 3F
MS( 0, 1960, 90, 140, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 110, 45, 6, 2, 3, MS( 0, 1960, 90, 140, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 110, 45, 6, 2, 3,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_BELOW| HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateSubarcticBelowSnow, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 40 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 40
MS( 0, 1960, 90, 140, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 110, 45, 6, 2, 3, MS( 0, 1960, 90, 140, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 110, 45, 6, 2, 3,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_ABOVE| HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateSubarcticAboveSnow, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 41 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 41
MS(1972, CalendarTime::MAX_YEAR, 140, 160, STR_TOWN_BUILDING_NAME_HOTEL_1, 160, 25, 6, 1, 3, MS(1972, CalendarTime::MAX_YEAR, 140, 160, STR_TOWN_BUILDING_NAME_HOTEL_1, 160, 25, 6, 1, 3,
BuildingFlag::Size1x2, BuildingFlag::Size1x2,
HZ_SUBARTC_BELOW| HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateSubarcticBelowSnow, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 42 CT_PASSENGERS, CT_MAIL, CT_FOOD), // 42
MS(1972, CalendarTime::MAX_YEAR, 0, 160, STR_TOWN_BUILDING_NAME_HOTEL_1, 160, 25, 6, 1, 2, MS(1972, CalendarTime::MAX_YEAR, 0, 160, STR_TOWN_BUILDING_NAME_HOTEL_1, 160, 25, 6, 1, 2,
{}, {},
HZ_NOZNS, {},
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 43 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 43
MS(1972, CalendarTime::MAX_YEAR, 140, 160, STR_TOWN_BUILDING_NAME_HOTEL_1, 160, 25, 6, 1, 3, MS(1972, CalendarTime::MAX_YEAR, 140, 160, STR_TOWN_BUILDING_NAME_HOTEL_1, 160, 25, 6, 1, 3,
BuildingFlag::Size1x2, BuildingFlag::Size1x2,
HZ_SUBARTC_ABOVE| HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateSubarcticAboveSnow, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 44 CT_PASSENGERS, CT_MAIL, CT_FOOD), // 44
MS(1972, CalendarTime::MAX_YEAR, 0, 160, STR_TOWN_BUILDING_NAME_HOTEL_1, 160, 25, 6, 1, 2, MS(1972, CalendarTime::MAX_YEAR, 0, 160, STR_TOWN_BUILDING_NAME_HOTEL_1, 160, 25, 6, 1, 2,
{}, {},
HZ_NOZNS, {},
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 45 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 45
MS(1963, CalendarTime::MAX_YEAR, 105, 130, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 105, 50, 7, 2, 3, MS(1963, CalendarTime::MAX_YEAR, 105, 130, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 105, 50, 7, 2, 3,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateSubarcticBelowSnow, HouseZone::ClimateSubtropic, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 46 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 46
MS(1963, CalendarTime::MAX_YEAR, 105, 130, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 105, 50, 7, 2, 3, MS(1963, CalendarTime::MAX_YEAR, 105, 130, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 105, 50, 7, 2, 3,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_ABOVE| HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateSubarcticAboveSnow, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 47 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 47
MS(1978, CalendarTime::MAX_YEAR, 190, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 135, 75, 9, 3, 4, MS(1978, CalendarTime::MAX_YEAR, 190, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 135, 75, 9, 3, 4,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_BELOW | HZ_ZON5 | HZ_ZON4, HouseZones({HouseZone::ClimateSubarcticBelowSnow, HouseZone::TownCentre, HouseZone::TownInnerSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 48 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 48
MS(1978, CalendarTime::MAX_YEAR, 190, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 135, 75, 9, 3, 4, MS(1978, CalendarTime::MAX_YEAR, 190, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 135, 75, 9, 3, 4,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4, HouseZones({HouseZone::ClimateSubarcticAboveSnow, HouseZone::TownCentre, HouseZone::TownInnerSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 49 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 49
MS(1967, CalendarTime::MAX_YEAR, 250, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 200, 60, 7, 2, 2, MS(1967, CalendarTime::MAX_YEAR, 250, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 200, 60, 7, 2, 2,
BuildingFlag::Size2x1, BuildingFlag::Size2x1,
HZ_SUBARTC_BELOW| HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateSubarcticBelowSnow, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 4A CT_PASSENGERS, CT_MAIL, CT_GOODS), // 4A
MS(1967, CalendarTime::MAX_YEAR, 0, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 200, 60, 7, 2, 2, MS(1967, CalendarTime::MAX_YEAR, 0, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 200, 60, 7, 2, 2,
{}, {},
HZ_NOZNS, {},
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 4B CT_PASSENGERS, CT_MAIL, CT_GOODS), // 4B
MS(1967, CalendarTime::MAX_YEAR, 250, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 200, 60, 7, 2, 2, MS(1967, CalendarTime::MAX_YEAR, 250, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 200, 60, 7, 2, 2,
BuildingFlag::Size2x1, BuildingFlag::Size2x1,
HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateSubarcticAboveSnow, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 4C CT_PASSENGERS, CT_MAIL, CT_GOODS), // 4C
MS(1967, CalendarTime::MAX_YEAR, 0, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 200, 60, 7, 2, 2, MS(1967, CalendarTime::MAX_YEAR, 0, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 200, 60, 7, 2, 2,
{}, {},
HZ_NOZNS, {},
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 4D CT_PASSENGERS, CT_MAIL, CT_GOODS), // 4D
MS( 0, CalendarTime::MAX_YEAR, 16, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 6, 3, 1, 2, MS( 0, CalendarTime::MAX_YEAR, 16, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 6, 3, 1, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2, HouseZones({HouseZone::ClimateSubtropic, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 4E CT_PASSENGERS, CT_MAIL, CT_FOOD), // 4E
MS( 0, CalendarTime::MAX_YEAR, 16, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 6, 3, 1, 2, MS( 0, CalendarTime::MAX_YEAR, 16, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 6, 3, 1, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2, HouseZones({HouseZone::ClimateSubtropic, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 4F CT_PASSENGERS, CT_MAIL, CT_FOOD), // 4F
MS( 0, CalendarTime::MAX_YEAR, 16, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 5, 3, 1, 2, MS( 0, CalendarTime::MAX_YEAR, 16, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 5, 3, 1, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2, HouseZones({HouseZone::ClimateSubtropic, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 50 CT_PASSENGERS, CT_MAIL, CT_FOOD), // 50
MS( 0, CalendarTime::MAX_YEAR, 7, 30, STR_TOWN_BUILDING_NAME_HOUSES_2, 30, 4, 3, 1, 1, MS( 0, CalendarTime::MAX_YEAR, 7, 30, STR_TOWN_BUILDING_NAME_HOUSES_2, 30, 4, 3, 1, 1,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBTROPIC | HZ_ZON1, HouseZones({HouseZone::ClimateSubtropic, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 51 CT_PASSENGERS, CT_MAIL, CT_FOOD), // 51
MS( 0, CalendarTime::MAX_YEAR, 45, 130, STR_TOWN_BUILDING_NAME_FLATS_1, 95, 15, 6, 2, 1, MS( 0, CalendarTime::MAX_YEAR, 45, 130, STR_TOWN_BUILDING_NAME_FLATS_1, 95, 15, 6, 2, 1,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateSubtropic, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 52 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 52
MS( 0, CalendarTime::MAX_YEAR, 8, 90, STR_TOWN_BUILDING_NAME_CHURCH_1, 200, 3, 2, 0, 0, MS( 0, CalendarTime::MAX_YEAR, 8, 90, STR_TOWN_BUILDING_NAME_CHURCH_1, 200, 3, 2, 0, 0,
BuildingFlags({BuildingFlag::IsChurch, BuildingFlag::Size1x1}), BuildingFlags({BuildingFlag::IsChurch, BuildingFlag::Size1x1}),
HZ_SUBTROPIC | HZ_ZON4 | HZ_ZON3 | HZ_ZON2, HouseZones({HouseZone::ClimateSubtropic, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 53 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 53
MS( 0, CalendarTime::MAX_YEAR, 18, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 7, 3, 1, 2, MS( 0, CalendarTime::MAX_YEAR, 18, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 7, 3, 1, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2, HouseZones({HouseZone::ClimateSubtropic, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt}),
CT_PASSENGERS, CT_MAIL, CT_FOOD), // 54 CT_PASSENGERS, CT_MAIL, CT_FOOD), // 54
MS(1973, CalendarTime::MAX_YEAR, 90, 110, STR_TOWN_BUILDING_NAME_FLATS_1, 95, 24, 6, 2, 1, MS(1973, CalendarTime::MAX_YEAR, 90, 110, STR_TOWN_BUILDING_NAME_FLATS_1, 95, 24, 6, 2, 1,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateSubtropic, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 55 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 55
MS(1962, CalendarTime::MAX_YEAR, 120, 120, STR_TOWN_BUILDING_NAME_FLATS_1, 95, 25, 6, 2, 1, MS(1962, CalendarTime::MAX_YEAR, 120, 120, STR_TOWN_BUILDING_NAME_FLATS_1, 95, 25, 6, 2, 1,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateSubtropic, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 56 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 56
MS(1984, CalendarTime::MAX_YEAR, 250, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 140, 80, 8, 3, 4, MS(1984, CalendarTime::MAX_YEAR, 250, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 140, 80, 8, 3, 4,
BuildingFlag::Size2x1, BuildingFlag::Size2x1,
HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4, HouseZones({HouseZone::ClimateSubtropic, HouseZone::TownCentre, HouseZone::TownInnerSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 57 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 57
MS(1984, CalendarTime::MAX_YEAR, 0, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 140, 80, 8, 3, 4, MS(1984, CalendarTime::MAX_YEAR, 0, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 140, 80, 8, 3, 4,
{}, {},
HZ_SUBTROPIC, HouseZones({HouseZone::ClimateSubtropic}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 58 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 58
MS( 0, CalendarTime::MAX_YEAR, 80, 110, STR_TOWN_BUILDING_NAME_FLATS_1, 95, 23, 6, 2, 1, MS( 0, CalendarTime::MAX_YEAR, 80, 110, STR_TOWN_BUILDING_NAME_FLATS_1, 95, 23, 6, 2, 1,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateSubtropic, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 59 CT_PASSENGERS, CT_MAIL, CT_GOODS), // 59
MS(1993, CalendarTime::MAX_YEAR, 180, 180, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 150, 90, 8, 3, 4, MS(1993, CalendarTime::MAX_YEAR, 180, 180, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 150, 90, 8, 3, 4,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateSubtropic, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_GOODS), // 5A CT_PASSENGERS, CT_MAIL, CT_GOODS), // 5A
MS( 0, CalendarTime::MAX_YEAR, 8, 90, STR_TOWN_BUILDING_NAME_CHURCH_1, 200, 3, 2, 0, 0, MS( 0, CalendarTime::MAX_YEAR, 8, 90, STR_TOWN_BUILDING_NAME_CHURCH_1, 200, 3, 2, 0, 0,
BuildingFlags({BuildingFlag::IsChurch, BuildingFlag::Size1x1}), BuildingFlags({BuildingFlag::IsChurch, BuildingFlag::Size1x1}),
HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateToyland, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5B CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5B
MS( 0, CalendarTime::MAX_YEAR, 18, 90, STR_TOWN_BUILDING_NAME_HOUSES_2, 90, 5, 6, 2, 2, MS( 0, CalendarTime::MAX_YEAR, 18, 90, STR_TOWN_BUILDING_NAME_HOUSES_2, 90, 5, 6, 2, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateToyland, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5C CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5C
MS( 0, CalendarTime::MAX_YEAR, 7, 70, STR_TOWN_BUILDING_NAME_HOUSES_2, 50, 3, 3, 1, 1, MS( 0, CalendarTime::MAX_YEAR, 7, 70, STR_TOWN_BUILDING_NAME_HOUSES_2, 50, 3, 3, 1, 1,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TOYLND | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateToyland, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5D CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5D
MS( 0, CalendarTime::MAX_YEAR, 15, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 2, MS( 0, CalendarTime::MAX_YEAR, 15, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TOYLND | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateToyland, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5E CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5E
MS( 0, CalendarTime::MAX_YEAR, 17, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 2, MS( 0, CalendarTime::MAX_YEAR, 17, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TOYLND | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateToyland, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5F CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5F
MS( 0, CalendarTime::MAX_YEAR, 19, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 2, MS( 0, CalendarTime::MAX_YEAR, 19, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TOYLND | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateToyland, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_CANDY), // 60 CT_PASSENGERS, CT_MAIL, CT_CANDY), // 60
MS( 0, CalendarTime::MAX_YEAR, 21, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 2, MS( 0, CalendarTime::MAX_YEAR, 21, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TOYLND | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateToyland, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_CANDY), // 61 CT_PASSENGERS, CT_MAIL, CT_CANDY), // 61
MS( 0, CalendarTime::MAX_YEAR, 75, 160, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 130, 20, 8, 4, 2, MS( 0, CalendarTime::MAX_YEAR, 75, 160, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 130, 20, 8, 4, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateToyland, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_CANDY), // 62 CT_PASSENGERS, CT_MAIL, CT_CANDY), // 62
MS( 0, CalendarTime::MAX_YEAR, 35, 90, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 9, 4, 1, 2, MS( 0, CalendarTime::MAX_YEAR, 35, 90, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 9, 4, 1, 2,
BuildingFlag::Size1x2, BuildingFlag::Size1x2,
HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateToyland, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_CANDY), // 63 CT_PASSENGERS, CT_MAIL, CT_CANDY), // 63
MS( 0, CalendarTime::MAX_YEAR, 0, 90, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 0, 4, 1, 2, MS( 0, CalendarTime::MAX_YEAR, 0, 90, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 0, 4, 1, 2,
{}, {},
HZ_NOZNS, {},
CT_PASSENGERS, CT_MAIL, CT_CANDY), // 64 CT_PASSENGERS, CT_MAIL, CT_CANDY), // 64
MS( 0, CalendarTime::MAX_YEAR, 85, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 130, 18, 8, 4, 2, MS( 0, CalendarTime::MAX_YEAR, 85, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 130, 18, 8, 4, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateToyland, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_CANDY), // 65 CT_PASSENGERS, CT_MAIL, CT_CANDY), // 65
MS( 0, CalendarTime::MAX_YEAR, 11, 60, STR_TOWN_BUILDING_NAME_IGLOO_1, 45, 3, 3, 1, 1, MS( 0, CalendarTime::MAX_YEAR, 11, 60, STR_TOWN_BUILDING_NAME_IGLOO_1, 45, 3, 3, 1, 1,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TOYLND | HZ_ZON1, HouseZones({HouseZone::ClimateToyland, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_CANDY), // 66 CT_PASSENGERS, CT_MAIL, CT_CANDY), // 66
MS( 0, CalendarTime::MAX_YEAR, 10, 60, STR_TOWN_BUILDING_NAME_TEPEES_1, 45, 3, 3, 1, 1, MS( 0, CalendarTime::MAX_YEAR, 10, 60, STR_TOWN_BUILDING_NAME_TEPEES_1, 45, 3, 3, 1, 1,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TOYLND | HZ_ZON1, HouseZones({HouseZone::ClimateToyland, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_CANDY), // 67 CT_PASSENGERS, CT_MAIL, CT_CANDY), // 67
MS( 0, CalendarTime::MAX_YEAR, 67, 140, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 130, 22, 8, 4, 4, MS( 0, CalendarTime::MAX_YEAR, 67, 140, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 130, 22, 8, 4, 4,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateToyland, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_FIZZY_DRINKS), // 68 CT_PASSENGERS, CT_MAIL, CT_FIZZY_DRINKS), // 68
MS( 0, CalendarTime::MAX_YEAR, 86, 145, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 130, 23, 8, 4, 4, MS( 0, CalendarTime::MAX_YEAR, 86, 145, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 130, 23, 8, 4, 4,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateToyland, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_FIZZY_DRINKS), // 69 CT_PASSENGERS, CT_MAIL, CT_FIZZY_DRINKS), // 69
MS( 0, CalendarTime::MAX_YEAR, 95, 165, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 130, 28, 8, 4, 2, MS( 0, CalendarTime::MAX_YEAR, 95, 165, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 130, 28, 8, 4, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateToyland, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_CANDY), // 6A CT_PASSENGERS, CT_MAIL, CT_CANDY), // 6A
MS( 0, CalendarTime::MAX_YEAR, 30, 90, STR_TOWN_BUILDING_NAME_STATUE_1, 70, 10, 4, 1, 2, MS( 0, CalendarTime::MAX_YEAR, 30, 90, STR_TOWN_BUILDING_NAME_STATUE_1, 70, 10, 4, 1, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, HouseZones({HouseZone::ClimateToyland, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb}),
CT_PASSENGERS, CT_MAIL, CT_CANDY), // 6B CT_PASSENGERS, CT_MAIL, CT_CANDY), // 6B
MS( 0, CalendarTime::MAX_YEAR, 25, 75, STR_TOWN_BUILDING_NAME_TEAPOT_HOUSE_1, 65, 8, 3, 1, 2, MS( 0, CalendarTime::MAX_YEAR, 25, 75, STR_TOWN_BUILDING_NAME_TEAPOT_HOUSE_1, 65, 8, 3, 1, 2,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateToyland, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_CANDY), // 6C CT_PASSENGERS, CT_MAIL, CT_CANDY), // 6C
MS( 0, CalendarTime::MAX_YEAR, 18, 85, STR_TOWN_BUILDING_NAME_PIGGY_BANK_1, 95, 7, 3, 2, 4, MS( 0, CalendarTime::MAX_YEAR, 18, 85, STR_TOWN_BUILDING_NAME_PIGGY_BANK_1, 95, 7, 3, 2, 4,
BuildingFlag::Size1x1, BuildingFlag::Size1x1,
HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, HouseZones({HouseZone::ClimateToyland, HouseZone::TownCentre, HouseZone::TownInnerSuburb, HouseZone::TownOuterSuburb, HouseZone::TownOutskirt, HouseZone::TownEdge}),
CT_PASSENGERS, CT_MAIL, CT_FIZZY_DRINKS), // 6D CT_PASSENGERS, CT_MAIL, CT_FIZZY_DRINKS), // 6D
}; };
#undef MS #undef MS

View File

@ -42,7 +42,7 @@ struct TownCache {
uint32_t population = 0; ///< Current population of people uint32_t population = 0; ///< Current population of people
TrackedViewportSign sign{}; ///< Location of name sign, UpdateVirtCoord updates this TrackedViewportSign sign{}; ///< Location of name sign, UpdateVirtCoord updates this
PartsOfSubsidy part_of_subsidy{}; ///< Is this town a source/destination of a subsidy? PartsOfSubsidy part_of_subsidy{}; ///< Is this town a source/destination of a subsidy?
std::array<uint32_t, HZB_END> squared_town_zone_radius{}; ///< UpdateTownRadius updates this given the house count std::array<uint32_t, NUM_HOUSE_ZONES> squared_town_zone_radius{}; ///< UpdateTownRadius updates this given the house count
BuildingCounts<uint16_t> building_counts{}; ///< The number of each type of building in the town BuildingCounts<uint16_t> building_counts{}; ///< The number of each type of building in the town
auto operator<=>(const TownCache &) const = default; auto operator<=>(const TownCache &) const = default;
@ -228,7 +228,7 @@ void UpdateTownRadius(Town *t);
CommandCost CheckIfAuthorityAllowsNewStation(TileIndex tile, DoCommandFlags flags); CommandCost CheckIfAuthorityAllowsNewStation(TileIndex tile, DoCommandFlags flags);
Town *ClosestTownFromTile(TileIndex tile, uint threshold); Town *ClosestTownFromTile(TileIndex tile, uint threshold);
void ChangeTownRating(Town *t, int add, int max, DoCommandFlags flags); void ChangeTownRating(Town *t, int add, int max, DoCommandFlags flags);
HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile); HouseZone GetTownRadiusGroup(const Town *t, TileIndex tile);
void SetTownRatingTestMode(bool mode); void SetTownRatingTestMode(bool mode);
TownActions GetMaskOfTownActions(CompanyID cid, const Town *t); TownActions GetMaskOfTownActions(CompanyID cid, const Town *t);
bool GenerateTowns(TownLayout layout); bool GenerateTowns(TownLayout layout);

View File

@ -1943,7 +1943,7 @@ static bool GrowTown(Town *t)
*/ */
void UpdateTownRadius(Town *t) void UpdateTownRadius(Town *t)
{ {
static const std::array<std::array<uint32_t, HZB_END>, 23> _town_squared_town_zone_radius_data = {{ static const std::array<std::array<uint32_t, NUM_HOUSE_ZONES>, 23> _town_squared_town_zone_radius_data = {{
{ 4, 0, 0, 0, 0}, // 0 { 4, 0, 0, 0, 0}, // 0
{ 16, 0, 0, 0, 0}, { 16, 0, 0, 0, 0},
{ 25, 0, 0, 0, 0}, { 25, 0, 0, 0, 0},
@ -1976,11 +1976,11 @@ void UpdateTownRadius(Town *t)
/* Actually we are proportional to sqrt() but that's right because we are covering an area. /* Actually we are proportional to sqrt() but that's right because we are covering an area.
* The offsets are to make sure the radii do not decrease in size when going from the table * The offsets are to make sure the radii do not decrease in size when going from the table
* to the calculated value.*/ * to the calculated value.*/
t->cache.squared_town_zone_radius[HZB_TOWN_EDGE] = mass * 15 - 40; t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownEdge)] = mass * 15 - 40;
t->cache.squared_town_zone_radius[HZB_TOWN_OUTSKIRT] = mass * 9 - 15; t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownOutskirt)] = mass * 9 - 15;
t->cache.squared_town_zone_radius[HZB_TOWN_OUTER_SUBURB] = 0; t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownOuterSuburb)] = 0;
t->cache.squared_town_zone_radius[HZB_TOWN_INNER_SUBURB] = mass * 5 - 5; t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownInnerSuburb)] = mass * 5 - 5;
t->cache.squared_town_zone_radius[HZB_TOWN_CENTRE] = mass * 3 + 5; t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownCentre)] = mass * 3 + 5;
} }
} }
@ -2304,6 +2304,21 @@ static TileIndex FindNearestGoodCoastalTownSpot(TileIndex tile, TownLayout layou
return INVALID_TILE; return INVALID_TILE;
} }
/**
* Get the HouseZones climate mask for the current landscape type.
* @return HouseZones climate mask.
*/
HouseZones GetClimateMaskForLandscape()
{
switch (_settings_game.game_creation.landscape) {
case LandscapeType::Temperate: return HouseZone::ClimateTemperate;
case LandscapeType::Arctic: return {HouseZone::ClimateSubarcticAboveSnow, HouseZone::ClimateSubarcticBelowSnow};
case LandscapeType::Tropic: return HouseZone::ClimateSubtropic;
case LandscapeType::Toyland: return HouseZone::ClimateToyland;
default: NOT_REACHED();
}
}
/** /**
* Create a random town somewhere in the world. * Create a random town somewhere in the world.
* @param attempts How many times should we try? * @param attempts How many times should we try?
@ -2426,15 +2441,15 @@ bool GenerateTowns(TownLayout layout)
* @param tile TileIndex where town zone needs to be found. * @param tile TileIndex where town zone needs to be found.
* @return the bit position of the given zone, as defined in HouseZones. * @return the bit position of the given zone, as defined in HouseZones.
*/ */
HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile) HouseZone GetTownRadiusGroup(const Town *t, TileIndex tile)
{ {
uint dist = DistanceSquare(tile, t->xy); uint dist = DistanceSquare(tile, t->xy);
if (t->fund_buildings_months && dist <= 25) return HZB_TOWN_CENTRE; if (t->fund_buildings_months != 0 && dist <= 25) return HouseZone::TownCentre;
HouseZonesBits smallest = HZB_TOWN_EDGE; HouseZone smallest = HouseZone::TownEdge;
for (HouseZonesBits i = HZB_BEGIN; i < HZB_END; i++) { for (HouseZone i : HZ_ZONE_ALL) {
if (dist < t->cache.squared_town_zone_radius[i]) smallest = i; if (dist < t->cache.squared_town_zone_radius[to_underlying(i)]) smallest = i;
} }
return smallest; return smallest;
@ -2733,13 +2748,14 @@ static bool TryBuildTownHouse(Town *t, TileIndex tile)
/* Get the town zone type of the current tile, as well as the climate. /* Get the town zone type of the current tile, as well as the climate.
* This will allow to easily compare with the specs of the new house to build */ * This will allow to easily compare with the specs of the new house to build */
HouseZonesBits rad = GetTownRadiusGroup(t, tile); HouseZones zones = GetTownRadiusGroup(t, tile);
/* Above snow? */ switch (_settings_game.game_creation.landscape) {
int land = to_underlying(_settings_game.game_creation.landscape); case LandscapeType::Temperate: zones.Set(HouseZone::ClimateTemperate); break;
if (_settings_game.game_creation.landscape == LandscapeType::Arctic && maxz > HighestSnowLine()) land = -1; case LandscapeType::Arctic: zones.Set(maxz > HighestSnowLine() ? HouseZone::ClimateSubarcticAboveSnow : HouseZone::ClimateSubarcticBelowSnow); break;
case LandscapeType::Tropic: zones.Set(HouseZone::ClimateSubtropic); break;
uint bitmask = (1 << rad) + (1 << (land + 12)); case LandscapeType::Toyland: zones.Set(HouseZone::ClimateToyland); break;
}
/* bits 0-4 are used /* bits 0-4 are used
* bits 11-15 are used * bits 11-15 are used
@ -2752,7 +2768,7 @@ static bool TryBuildTownHouse(Town *t, TileIndex tile)
/* Generate a list of all possible houses that can be built. */ /* Generate a list of all possible houses that can be built. */
for (const auto &hs : HouseSpec::Specs()) { for (const auto &hs : HouseSpec::Specs()) {
/* Verify that the candidate house spec matches the current tile status */ /* Verify that the candidate house spec matches the current tile status */
if ((~hs.building_availability & bitmask) != 0 || !hs.enabled || hs.grf_prop.override_id != INVALID_HOUSE_ID) continue; if (!hs.building_availability.All(zones) || !hs.enabled || hs.grf_prop.override_id != INVALID_HOUSE_ID) continue;
/* Don't let these counters overflow. Global counters are 32bit, there will never be that many houses. */ /* Don't let these counters overflow. Global counters are 32bit, there will never be that many houses. */
if (hs.class_id != HOUSE_NO_CLASS) { if (hs.class_id != HOUSE_NO_CLASS) {
@ -3651,9 +3667,9 @@ static void ForAllStationsNearTown(Town *t, Func func)
* The true radius is not stored or calculated anywhere, only the squared radius. */ * The true radius is not stored or calculated anywhere, only the squared radius. */
/* The efficiency of this search might be improved for large towns and many stations on the map, /* The efficiency of this search might be improved for large towns and many stations on the map,
* by using an integer square root approximation giving a value not less than the true square root. */ * by using an integer square root approximation giving a value not less than the true square root. */
uint search_radius = t->cache.squared_town_zone_radius[HZB_TOWN_EDGE] / 2; uint search_radius = t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownEdge)] / 2;
ForAllStationsRadius(t->xy, search_radius, [&](const Station * st) { ForAllStationsRadius(t->xy, search_radius, [&](const Station * st) {
if (DistanceSquare(st->xy, t->xy) <= t->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) { if (DistanceSquare(st->xy, t->xy) <= t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownEdge)]) {
func(st); func(st);
} }
}); });

View File

@ -1421,13 +1421,7 @@ public:
*/ */
void SetClimateMask() void SetClimateMask()
{ {
switch (_settings_game.game_creation.landscape) { this->climate_mask = GetClimateMaskForLandscape();
case LandscapeType::Temperate: this->climate_mask = HZ_TEMP; break;
case LandscapeType::Arctic: this->climate_mask = HZ_SUBARTC_ABOVE | HZ_SUBARTC_BELOW; break;
case LandscapeType::Tropic: this->climate_mask = HZ_SUBTROPIC; break;
case LandscapeType::Toyland: this->climate_mask = HZ_TOYLND; break;
default: NOT_REACHED();
}
/* In some cases, not all 'classes' (house zones) have distinct houses, so we need to disable those. /* In some cases, not all 'classes' (house zones) have distinct houses, so we need to disable those.
* As we need to check all types, and this cannot change with the picker window open, pre-calculate it. * As we need to check all types, and this cannot change with the picker window open, pre-calculate it.
@ -1455,7 +1449,7 @@ public:
/* Houses do not have classes like NewGRFClass. We'll make up fake classes based on town zone /* Houses do not have classes like NewGRFClass. We'll make up fake classes based on town zone
* availability instead. */ * availability instead. */
static inline const std::array<StringID, HZB_END> zone_names = { static inline const std::array<StringID, NUM_HOUSE_ZONES> zone_names = {
STR_HOUSE_PICKER_CLASS_ZONE1, STR_HOUSE_PICKER_CLASS_ZONE1,
STR_HOUSE_PICKER_CLASS_ZONE2, STR_HOUSE_PICKER_CLASS_ZONE2,
STR_HOUSE_PICKER_CLASS_ZONE3, STR_HOUSE_PICKER_CLASS_ZONE3,
@ -1500,16 +1494,19 @@ public:
int GetSelectedType() const override { return sel_type; } int GetSelectedType() const override { return sel_type; }
void SetSelectedType(int id) const override { sel_type = id; } void SetSelectedType(int id) const override { sel_type = id; }
static HouseZone GetHouseZoneFromClassId(int cls_id) { return static_cast<HouseZone>(to_underlying(HouseZone::TownEdge) + cls_id); }
static int GetClassIdFromHouseZone(HouseZones zones) { return FindFirstBit((zones & HZ_ZONE_ALL).base()) - to_underlying(HouseZone::TownEdge); }
StringID GetTypeName(int cls_id, int id) const override StringID GetTypeName(int cls_id, int id) const override
{ {
const HouseSpec *spec = HouseSpec::Get(id); const HouseSpec *spec = HouseSpec::Get(id);
if (spec == nullptr) return INVALID_STRING_ID; if (spec == nullptr) return INVALID_STRING_ID;
if (!spec->enabled) return INVALID_STRING_ID; if (!spec->enabled) return INVALID_STRING_ID;
if ((spec->building_availability & climate_mask) == 0) return INVALID_STRING_ID; if (!spec->building_availability.Any(climate_mask)) return INVALID_STRING_ID;
if (!HasBit(spec->building_availability, cls_id)) return INVALID_STRING_ID; if (!spec->building_availability.Test(GetHouseZoneFromClassId(cls_id))) return INVALID_STRING_ID;
for (int i = 0; i < cls_id; i++) { for (int i = 0; i < cls_id; i++) {
/* Don't include if it's already included in an earlier zone. */ /* Don't include if it's already included in an earlier zone. */
if (HasBit(spec->building_availability, i)) return INVALID_STRING_ID; if (spec->building_availability.Test(GetHouseZoneFromClassId(i))) return INVALID_STRING_ID;
} }
return GetHouseName(spec); return GetHouseName(spec);
@ -1520,11 +1517,11 @@ public:
const auto *spec = HouseSpec::Get(id); const auto *spec = HouseSpec::Get(id);
if (spec == nullptr) return {}; if (spec == nullptr) return {};
if (!spec->enabled) return {}; if (!spec->enabled) return {};
if ((spec->building_availability & climate_mask) == 0) return {}; if (!spec->building_availability.Any(climate_mask)) return {};
if (!HasBit(spec->building_availability, cls_id)) return {}; if (!spec->building_availability.Test(GetHouseZoneFromClassId(cls_id))) return {};
for (int i = 0; i < cls_id; i++) { for (int i = 0; i < cls_id; i++) {
/* Don't include if it's already included in an earlier zone. */ /* Don't include if it's already included in an earlier zone. */
if (HasBit(spec->building_availability, i)) return {}; if (spec->building_availability.Test(GetHouseZoneFromClassId(i))) return {};
} }
return spec->badges; return spec->badges;
@ -1548,7 +1545,7 @@ public:
if (*it == 0) continue; if (*it == 0) continue;
HouseID house = static_cast<HouseID>(std::distance(id_count.begin(), it)); HouseID house = static_cast<HouseID>(std::distance(id_count.begin(), it));
const HouseSpec *hs = HouseSpec::Get(house); const HouseSpec *hs = HouseSpec::Get(house);
int class_index = FindFirstBit(hs->building_availability & HZ_ZONALL); int class_index = GetClassIdFromHouseZone(hs->building_availability);
items.insert({0, house, class_index, house}); items.insert({0, house, class_index, house});
} }
} }
@ -1569,7 +1566,7 @@ public:
/* Not preset, hide from UI. */ /* Not preset, hide from UI. */
dst.insert({item.grfid, item.local_id, -1, -1}); dst.insert({item.grfid, item.local_id, -1, -1});
} else { } else {
int class_index = FindFirstBit(it->building_availability & HZ_ZONALL); int class_index = GetClassIdFromHouseZone(it->building_availability);
dst.insert( {item.grfid, item.local_id, class_index, it->Index()}); dst.insert( {item.grfid, item.local_id, class_index, it->Index()});
} }
} }

View File

@ -281,7 +281,7 @@ CommandCost CmdBuildBridge(DoCommandFlags flags, TileIndex tile_end, TileIndex t
company = OWNER_TOWN; company = OWNER_TOWN;
/* If we are not within a town, we are not owned by the town */ /* If we are not within a town, we are not owned by the town */
if (town == nullptr || DistanceSquare(tile_start, town->xy) > town->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) { if (town == nullptr || DistanceSquare(tile_start, town->xy) > town->cache.squared_town_zone_radius[to_underlying(HouseZone::TownEdge)]) {
company = OWNER_NONE; company = OWNER_NONE;
} }
} }
@ -635,7 +635,7 @@ CommandCost CmdBuildTunnel(DoCommandFlags flags, TileIndex start_tile, Transport
company = OWNER_TOWN; company = OWNER_TOWN;
/* If we are not within a town, we are not owned by the town */ /* If we are not within a town, we are not owned by the town */
if (town == nullptr || DistanceSquare(start_tile, town->xy) > town->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) { if (town == nullptr || DistanceSquare(start_tile, town->xy) > town->cache.squared_town_zone_radius[to_underlying(HouseZone::TownEdge)]) {
company = OWNER_NONE; company = OWNER_NONE;
} }
} }