diff options
Diffstat (limited to 'src/town_cmd.cpp')
-rw-r--r-- | src/town_cmd.cpp | 78 |
1 files changed, 63 insertions, 15 deletions
diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index abfa18106..6b351b2cd 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -13,6 +13,7 @@ #include "road_internal.h" /* Cleaning up road bits */ #include "road_cmd.h" #include "landscape.h" +#include "layer_func.h" #include "viewport_func.h" #include "cmd_helper.h" #include "command_func.h" @@ -137,17 +138,36 @@ void Town::InitializeLayout(TownLayout layout) } /** - * Return a random valid town. - * @return random town, NULL if there are no towns + * Return a random town that statisfies some criteria specified + * with a callback function. + * + * @param enum_proc Callback function. Return true for a matching town and false to continue iterating. + * @param skip Skip over this town id when searching. + * @param data Optional data passed to the callback function. + * @return A town satisfying the search criteria or NULL if no such town exists. */ -/* static */ Town *Town::GetRandom() +/* static */ Town *Town::GetRandom(EnumTownProc enum_proc, TownID skip, void *data) { - if (Town::GetNumItems() == 0) return NULL; - int num = RandomRange((uint16)Town::GetNumItems()); - size_t index = MAX_UVALUE(size_t); + assert(skip == INVALID_TOWN || Town::IsValidID(skip)); - while (num >= 0) { - num--; + uint16 max_num = 0; + if (enum_proc != NULL) { + /* A callback was given, count all matching towns. */ + Town *t; + FOR_ALL_TOWNS(t) { + if (t->index != skip && enum_proc(t, data)) max_num++; + } + } else { + max_num = (uint16)Town::GetNumItems(); + /* Subtract one if a town to skip was given. max_num is at least + * one here as otherwise skip could not be valid. */ + if (skip != INVALID_TOWN) max_num--; + } + if (max_num == 0) return NULL; + + uint num = RandomRange(max_num) + 1; + size_t index = MAX_UVALUE(size_t); + do { index++; /* Make sure we have a valid town */ @@ -155,7 +175,9 @@ void Town::InitializeLayout(TownLayout layout) index++; assert(index < Town::GetPoolSize()); } - } + + if (index != skip && (enum_proc == NULL || enum_proc(Town::Get(index), data))) num--; + } while (num > 0); return Town::Get(index); } @@ -483,7 +505,7 @@ static void TileLoop_Town(TileIndex tile) uint amt = GB(callback, 0, 8); if (amt == 0) continue; - uint moved = MoveGoodsToStation(cargo, amt, ST_TOWN, t->index, stations.GetStations()); + uint moved = MoveGoodsToStation(cargo, amt, ST_TOWN, t->index, stations.GetStations(), tile); const CargoSpec *cs = CargoSpec::Get(cargo); t->supplied[cs->Index()].new_max += amt; @@ -495,7 +517,7 @@ static void TileLoop_Town(TileIndex tile) if (EconomyIsInRecession()) amt = (amt + 1) >> 1; t->supplied[CT_PASSENGERS].new_max += amt; - t->supplied[CT_PASSENGERS].new_act += MoveGoodsToStation(CT_PASSENGERS, amt, ST_TOWN, t->index, stations.GetStations()); + t->supplied[CT_PASSENGERS].new_act += MoveGoodsToStation(CT_PASSENGERS, amt, ST_TOWN, t->index, stations.GetStations(), tile); } if (GB(r, 8, 8) < hs->mail_generation) { @@ -503,7 +525,7 @@ static void TileLoop_Town(TileIndex tile) if (EconomyIsInRecession()) amt = (amt + 1) >> 1; t->supplied[CT_MAIL].new_max += amt; - t->supplied[CT_MAIL].new_act += MoveGoodsToStation(CT_MAIL, amt, ST_TOWN, t->index, stations.GetStations()); + t->supplied[CT_MAIL].new_act += MoveGoodsToStation(CT_MAIL, amt, ST_TOWN, t->index, stations.GetStations(), tile); } } @@ -680,17 +702,33 @@ static void ChangeTileOwner_Town(TileIndex tile, Owner old_owner, Owner new_owne void UpdateTownCargoTotal(Town *t) { t->cargo_accepted_total = 0; + MemSetT(t->cargo_accepted_weights, 0, lengthof(t->cargo_accepted_weights)); + /* Calculate the maximum weight based on the grid square furthest + * from the town centre. The maximum weight is two times the L-inf + * norm plus 1 so that max weight - furthest square weight == 1. */ const TileArea &area = t->cargo_accepted.GetArea(); + uint max_dist = max(DistanceMax(t->xy_aligned, area.tile), DistanceMax(t->xy_aligned, TILE_ADDXY(area.tile, area.w - 1, area.h - 1))) / AcceptanceMatrix::GRID; + t->cargo_accepted_max_weight = max_dist * 2 + 1; + + /* Collect acceptance from all grid squares. */ TILE_AREA_LOOP(tile, area) { if (TileX(tile) % AcceptanceMatrix::GRID == 0 && TileY(tile) % AcceptanceMatrix::GRID == 0) { - t->cargo_accepted_total |= t->cargo_accepted[tile]; + uint32 acc = t->cargo_accepted[tile]; + t->cargo_accepted_total |= acc; + + CargoID cid; + FOR_EACH_SET_CARGO_ID(cid, acc) { + /* For each accepted cargo, the grid square weight is the maximum weight + * minus two times the L-inf norm between this square and the centre square. */ + t->cargo_accepted_weights[cid] += t->cargo_accepted_max_weight - (DistanceMax(t->xy_aligned, tile) / AcceptanceMatrix::GRID) * 2; + } } } } /** - * Update accepted town cargoes around a specific tile. + * Update accepted and produced town cargoes around a specific tile. * @param t The town to update. * @param start Update the values around this tile. * @param update_total Set to true if the total cargo acceptance should be updated. @@ -700,7 +738,7 @@ static void UpdateTownCargoes(Town *t, TileIndex start, bool update_total = true CargoArray accepted, produced; uint32 dummy; - /* Gather acceptance for all houses in an area around the start tile. + /* Gather acceptance and production for all houses in an area around the start tile. * The area is composed of the square the tile is in, extended one square in all * directions as the coverage area of a single station is bigger than just one square. */ TileArea area = AcceptanceMatrix::GetAreaForTile(start, 1); @@ -1537,6 +1575,11 @@ static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts, TownSize t->larger_town = city; + /* Cache the aligned tile index of the centre tile. */ + uint town_x = (TileX(t->xy) / AcceptanceMatrix::GRID) * AcceptanceMatrix::GRID; + uint town_y = (TileY(t->xy) / AcceptanceMatrix::GRID) * AcceptanceMatrix::GRID; + t->xy_aligned= TileXY(town_x, town_y); + int x = (int)size * 16 + 3; if (size == TSZ_RANDOM) x = (Random() & 0xF) + 8; /* Don't create huge cities when founding town in-game */ @@ -1987,6 +2030,9 @@ static inline bool CanBuildHouseHere(TileIndex tile, TownID town, bool noslope) Slope slope = GetTileSlope(tile); if ((noslope && slope != SLOPE_FLAT) || IsSteepSlope(slope)) return false; + /* Недопустимо строительство объекта под землей */ + if (IsUnderground(tile)) return false; + /* building under a bridge? */ if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false; @@ -2422,6 +2468,8 @@ CommandCost CmdRenameTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 t->UpdateVirtCoord(); InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 1); + InvalidateWindowClassesData(WC_TOWN_VIEW); + InvalidateWindowClassesData(WC_INDUSTRY_VIEW); UpdateAllStationVirtCoords(); } return CommandCost(); |