@@ -2827,24 +2827,12 @@ bool AfterLoadGame()
/* When any NewGRF has been changed the availability of some vehicles might
* have been changed too. e->company_avail must be set to 0 in that case
* which is done by StartupEngines(). */
if (gcf_res != GLC_ALL_GOOD) StartupEngines();
if (IsSavegameVersionBefore(SLV_166)) {
/* Update cargo acceptance map of towns. */
for (TileIndex t = 0; t < map_size; t++) {
if (!IsTileType(t, MP_HOUSE)) continue;
Town::Get(GetTownIndex(t))->cargo_accepted.Add(t);
}
for (Town *town : Town::Iterate()) {
UpdateTownCargoes(town);
/* The road owner of standard road stops was not properly accounted for. */
if (IsSavegameVersionBefore(SLV_172)) {
if (!IsStandardRoadStopTile(t)) continue;
Owner o = GetTileOwner(t);
SetRoadOwner(t, RTT_ROAD, o);
@@ -10,18 +10,22 @@
#include "../stdafx.h"
#include "../newgrf_house.h"
#include "../town.h"
#include "../landscape.h"
#include "../subsidy_func.h"
#include "../strings_func.h"
#include "../tilematrix_type.hpp"
#include "saveload.h"
#include "newgrf_sl.h"
#include "../safeguards.h"
/* TODO: Remove acceptance matrix from the savegame completely. */
typedef TileMatrix<CargoTypes, 4> AcceptanceMatrix;
/**
* Rebuild all the cached variables of towns.
*/
void RebuildTownCaches()
{
InitializeBuildingCounts();
@@ -45,15 +49,13 @@ void RebuildTownCaches()
if (GetHouseNorthPart(house_id) == 0) town->cache.num_houses++;
/* Update the population and num_house dependent values */
UpdateTownRadius(town);
UpdateTownCargoBitmap();
* Check and update town and house values.
*
* Checked are the HouseIDs. Updated are the
@@ -187,14 +189,14 @@ static const SaveLoad _town_desc[] = {
SLE_CONDVAR(Town, larger_town, SLE_BOOL, SLV_56, SL_MAX_VERSION),
SLE_CONDVAR(Town, layout, SLE_UINT8, SLV_113, SL_MAX_VERSION),
SLE_CONDLST(Town, psa_list, REF_STORAGE, SLV_161, SL_MAX_VERSION),
SLE_CONDVAR(Town, cargo_produced, SLE_FILE_U32 | SLE_VAR_U64, SLV_166, SLV_EXTEND_CARGOTYPES),
SLE_CONDVAR(Town, cargo_produced, SLE_UINT64, SLV_EXTEND_CARGOTYPES, SL_MAX_VERSION),
SLE_CONDNULL(4, SLV_166, SLV_EXTEND_CARGOTYPES), ///< cargo_produced, no longer in use
SLE_CONDNULL(8, SLV_EXTEND_CARGOTYPES, SL_MAX_VERSION), ///< cargo_produced, no longer in use
/* reserve extra space in savegame here. (currently 30 bytes) */
SLE_CONDNULL(30, SLV_2, SL_MAX_VERSION),
SLE_END()
};
@@ -250,17 +252,15 @@ static void RealSave_Town(Town *t)
for (int i = TE_BEGIN; i < NUM_TE; i++) {
SlObject(&t->received[i], _town_received_desc);
if (IsSavegameVersionBefore(SLV_166)) return;
SlObject(&t->cargo_accepted, GetTileMatrixDesc());
if (t->cargo_accepted.area.w != 0) {
uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID;
SlArray(t->cargo_accepted.data, arr_len, SLE_UINT32);
/* Write an empty matrix to avoid bumping savegame version. */
AcceptanceMatrix dummy;
SlObject(&dummy, GetTileMatrixDesc());
static void Save_TOWN()
for (Town *t : Town::Iterate()) {
SlSetArrayIndex(t->index);
@@ -287,20 +287,18 @@ static void Load_TOWN()
if (t->townnamegrfid == 0 && !IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1) && GetStringTab(t->townnametype) != TEXT_TAB_OLD_CUSTOM) {
SlErrorCorrupt("Invalid town name generator");
if (IsSavegameVersionBefore(SLV_166)) continue;
t->cargo_accepted.data = MallocT<CargoTypes>(arr_len);
/* Rebuild total cargo acceptance. */
UpdateTownCargoTotal(t);
/* Discard acceptance matrix to avoid bumping savegame version. */
if (dummy.area.w != 0) {
uint arr_len = dummy.area.w / AcceptanceMatrix::GRID * dummy.area.h / AcceptanceMatrix::GRID;
for (arr_len *= 4; arr_len != 0; arr_len--) SlReadByte();
/** Fix pointers when loading town data. */
static void Ptrs_TOWN()
@@ -431,13 +431,13 @@ bool FindSubsidyCargoDestination(CargoID
case ST_TOWN: {
/* Select a random town. */
const Town *dst_town = Town::GetRandom();
CargoArray town_cargo_accepted = GetAcceptanceAroundTiles(dst_town->xy, 1, 1, SUBSIDY_TOWN_CARGO_RADIUS);
/* Check if the town can accept this cargo. */
if (town_cargo_accepted[cid] >= 8) return false;
if (town_cargo_accepted[cid] < 8) return false;
dst = dst_town->index;
break;
case ST_INDUSTRY: {
@@ -12,23 +12,20 @@
#include "viewport_type.h"
#include "town_map.h"
#include "subsidy_type.h"
#include "newgrf_storage.h"
#include "cargotype.h"
#include "tilematrix_type.hpp"
#include <list>
template <typename T>
struct BuildingCounts {
T id_count[NUM_HOUSES];
T class_count[HOUSE_CLASS_MAX];
static const uint CUSTOM_TOWN_NUMBER_DIFFICULTY = 4; ///< value for custom town number in difficulty settings
static const uint CUSTOM_TOWN_MAX_NUMBER = 5000; ///< this is the maximum number of towns a user can specify in customisation
static const TownID INVALID_TOWN = 0xFFFF;
static const uint TOWN_GROWTH_WINTER = 0xFFFFFFFE; ///< The town only needs this cargo in the winter (any amount)
@@ -80,16 +77,12 @@ struct Town : TownPool::PoolItem<&_town_
uint32 goal[NUM_TE]; ///< Amount of cargo required for the town to grow.
std::string text; ///< General text with additional information.
inline byte GetPercentTransported(CargoID cid) const { return this->supplied[cid].old_act * 256 / (this->supplied[cid].old_max + 1); }
/* Cargo production and acceptance stats. */
CargoTypes cargo_produced; ///< Bitmap of all cargoes produced by houses in this town.
AcceptanceMatrix cargo_accepted; ///< Bitmap of cargoes accepted by houses for each 4*4 map square of the town.
CargoTypes cargo_accepted_total; ///< NOSAVE: Bitmap of all cargoes accepted by houses in this town.
StationList stations_near; ///< NOSAVE: List of nearby stations.
uint16 time_until_rebuild; ///< time until we rebuild a house
uint16 grow_counter; ///< counter to count when to grow, value is smaller than or equal to growth_rate
uint16 growth_rate; ///< town growth rate
@@ -200,15 +193,12 @@ Town *CalcClosestTownFromTile(TileIndex
void ResetHouses();
void ClearTownHouse(Town *t, TileIndex tile);
void UpdateTownMaxPass(Town *t);
void UpdateTownRadius(Town *t);
void UpdateTownCargoes(Town *t);
void UpdateTownCargoTotal(Town *t);
void UpdateTownCargoBitmap();
CommandCost CheckIfAuthorityAllowsNewStation(TileIndex tile, DoCommandFlag flags);
Town *ClosestTownFromTile(TileIndex tile, uint threshold);
void ChangeTownRating(Town *t, int add, int max, DoCommandFlag flags);
HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile);
void SetTownRatingTestMode(bool mode);
uint GetMaskOfTownActions(int *nump, CompanyID cid, const Town *t);
@@ -310,11 +300,9 @@ void MakeDefaultName(T *obj)
static inline uint16 TownTicksToGameTicks(uint16 ticks) {
return (min(ticks, MAX_TOWN_GROWTH_TICKS) + 1) * TOWN_GROWTH_TICKS - 1;
extern CargoTypes _town_cargoes_accepted;
RoadType GetTownRoadType(const Town *t);
#endif /* TOWN_H */
@@ -52,13 +52,12 @@
#include "table/strings.h"
#include "table/town_land.h"
#include "safeguards.h"
TownID _new_town_id;
CargoTypes _town_cargoes_accepted; ///< Bitmap of all cargoes accepted by houses.
/* Initialize the town-pool */
TownPool _town_pool("Town");
INSTANTIATE_POOL_METHODS(Town)
@@ -779,91 +778,12 @@ static TrackStatus GetTileTrackStatus_To
static void ChangeTileOwner_Town(TileIndex tile, Owner old_owner, Owner new_owner)
/* not used */
/** Update the total cargo acceptance of the whole town.
* @param t The town to update.
void UpdateTownCargoTotal(Town *t)
t->cargo_accepted_total = 0;
const TileArea &area = t->cargo_accepted.GetArea();
TILE_AREA_LOOP(tile, area) {
if (TileX(tile) % AcceptanceMatrix::GRID == 0 && TileY(tile) % AcceptanceMatrix::GRID == 0) {
t->cargo_accepted_total |= t->cargo_accepted[tile];
* Update accepted town cargoes around a specific tile.
* @param start Update the values around this tile.
* @param update_total Set to true if the total cargo acceptance should be updated.
static void UpdateTownCargoes(Town *t, TileIndex start, bool update_total = true)
CargoArray accepted, produced;
CargoTypes dummy = 0;
/* Gather acceptance 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);
if (!IsTileType(tile, MP_HOUSE) || GetTownIndex(tile) != t->index) continue;
AddAcceptedCargo_Town(tile, accepted, &dummy);
AddProducedCargo_Town(tile, produced);
/* Create bitmap of produced and accepted cargoes. */
CargoTypes acc = 0;
for (uint cid = 0; cid < NUM_CARGO; cid++) {
if (accepted[cid] >= 8) SetBit(acc, cid);
if (produced[cid] > 0) SetBit(t->cargo_produced, cid);
t->cargo_accepted[start] = acc;
if (update_total) UpdateTownCargoTotal(t);
/** Update cargo acceptance for the complete town.
void UpdateTownCargoes(Town *t)
t->cargo_produced = 0;
if (area.tile == INVALID_TILE) return;
/* Update acceptance for each grid square. */
UpdateTownCargoes(t, tile, false);
/* Update the total acceptance. */
/** Updates the bitmap of all cargoes accepted by houses. */
void UpdateTownCargoBitmap()
_town_cargoes_accepted = 0;
for (const Town *town : Town::Iterate()) {
_town_cargoes_accepted |= town->cargo_accepted_total;
static bool GrowTown(Town *t);
static void TownTickHandler(Town *t)
if (HasBit(t->flags, TOWN_IS_GROWING)) {
int i = (int)t->grow_counter - 1;
@@ -2585,13 +2505,12 @@ static bool BuildTownHouse(Town *t, Tile
MakeTownHouse(tile, t, construction_counter, construction_stage, house, random_bits);
UpdateTownRadius(t);
UpdateTownGrowthRate(t);
UpdateTownCargoes(t, tile);
return true;
return false;
@@ -2670,15 +2589,12 @@ void ClearTownHouse(Town *t, TileIndex t
if (hs->building_flags & BUILDING_2_TILES_X) DoClearTownHouseHelper(tile + TileDiffXY(1, 0), t, ++house);
if (hs->building_flags & BUILDING_HAS_4_TILES) DoClearTownHouseHelper(tile + TileDiffXY(1, 1), t, ++house);
RemoveNearbyStations(t, tile, hs->building_flags);
/* Update cargo acceptance. */
* Rename a town (server-only).
* @param tile unused
* @param flags type of operation
@@ -3695,16 +3611,14 @@ void TownsMonthlyLoop()
UpdateTownAmounts(t);
UpdateTownGrowth(t);
UpdateTownRating(t);
UpdateTownUnwanted(t);
UpdateTownCargoes(t);
void TownsYearlyLoop()
/* Increment house ages */
for (TileIndex t = 0; t < MapSize(); t++) {
Status change: