summaryrefslogtreecommitdiff
path: root/src/town_cmd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/town_cmd.cpp')
-rw-r--r--src/town_cmd.cpp78
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();