File diff r24300:dc74d00736ca → r24301:7ff717a1243f
src/town_cmd.cpp
Show inline comments
 
@@ -34,49 +34,48 @@
 
#include "string_func.h"
 
#include "newgrf_cargo.h"
 
#include "cheat_type.h"
 
#include "animated_tile_func.h"
 
#include "date_func.h"
 
#include "subsidy_func.h"
 
#include "core/pool_func.hpp"
 
#include "town.h"
 
#include "town_kdtree.h"
 
#include "townname_func.h"
 
#include "core/random_func.hpp"
 
#include "core/backup_type.hpp"
 
#include "depot_base.h"
 
#include "object_map.h"
 
#include "object_base.h"
 
#include "ai/ai.hpp"
 
#include "game/game.hpp"
 

	
 
#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)
 

	
 

	
 
TownKdtree _town_kdtree(&Kdtree_TownXYFunc);
 

	
 
void RebuildTownKdtree()
 
{
 
	std::vector<TownID> townids;
 
	for (const Town *town : Town::Iterate()) {
 
		townids.push_back(town->index);
 
	}
 
	_town_kdtree.Build(townids.begin(), townids.end());
 
}
 

	
 

	
 
/**
 
 * Check if a town 'owns' a bridge.
 
 * Bridges to not directly have an owner, so we check the tiles adjacent to the bridge ends.
 
 * If either adjacent tile belongs to the town then it will be assumed that the town built
 
 * the bridge.
 
 * @param tile Bridge tile to test
 
@@ -761,127 +760,48 @@ static void GetTileDesc_Town(TileIndex t
 
	if (!house_completed) {
 
		SetDParamX(td->dparam, 0, td->str);
 
		td->str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION;
 
	}
 

	
 
	if (hs->grf_prop.grffile != nullptr) {
 
		const GRFConfig *gc = GetGRFConfig(hs->grf_prop.grffile->grfid);
 
		td->grf = gc->GetName();
 
	}
 

	
 
	td->owner[0] = OWNER_TOWN;
 
}
 

	
 
static TrackStatus GetTileTrackStatus_Town(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
 
{
 
	/* not used */
 
	return 0;
 
}
 

	
 
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 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.
 
 */
 
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);
 
	TILE_AREA_LOOP(tile, area) {
 
		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.
 
 * @param t The town to update.
 
 */
 
void UpdateTownCargoes(Town *t)
 
{
 
	t->cargo_produced = 0;
 

	
 
	const TileArea &area = t->cargo_accepted.GetArea();
 
	if (area.tile == INVALID_TILE) return;
 

	
 
	/* Update acceptance for each grid square. */
 
	TILE_AREA_LOOP(tile, area) {
 
		if (TileX(tile) % AcceptanceMatrix::GRID == 0 && TileY(tile) % AcceptanceMatrix::GRID == 0) {
 
			UpdateTownCargoes(t, tile, false);
 
		}
 
	}
 

	
 
	/* Update the total acceptance. */
 
	UpdateTownCargoTotal(t);
 
}
 

	
 
/** 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;
 
		if (i < 0) {
 
			if (GrowTown(t)) {
 
				i = t->growth_rate;
 
			} else {
 
				/* If growth failed wait a bit before retrying */
 
				i = min(t->growth_rate, TOWN_GROWTH_TICKS - 1);
 
			}
 
		}
 
		t->grow_counter = i;
 
	}
 
}
 

	
 
void OnTick_Town()
 
{
 
	if (_game_mode == GM_EDITOR) return;
 

	
 
	for (Town *t : Town::Iterate()) {
 
		TownTickHandler(t);
 
@@ -2567,49 +2487,48 @@ static bool BuildTownHouse(Town *t, Tile
 
		t->cache.num_houses++;
 

	
 
		/* Special houses that there can be only one of. */
 
		t->flags |= oneof;
 

	
 
		byte construction_counter = 0;
 
		byte construction_stage = 0;
 

	
 
		if (_generating_world || _game_mode == GM_EDITOR) {
 
			uint32 r = Random();
 

	
 
			construction_stage = TOWN_HOUSE_COMPLETED;
 
			if (Chance16(1, 7)) construction_stage = GB(r, 0, 2);
 

	
 
			if (construction_stage == TOWN_HOUSE_COMPLETED) {
 
				ChangePopulation(t, hs->population);
 
			} else {
 
				construction_counter = GB(r, 2, 2);
 
			}
 
		}
 

	
 
		MakeTownHouse(tile, t, construction_counter, construction_stage, house, random_bits);
 
		UpdateTownRadius(t);
 
		UpdateTownGrowthRate(t);
 
		UpdateTownCargoes(t, tile);
 

	
 
		return true;
 
	}
 

	
 
	return false;
 
}
 

	
 
/**
 
 * Update data structures when a house is removed
 
 * @param tile  Tile of the house
 
 * @param t     Town owning the house
 
 * @param house House type
 
 */
 
static void DoClearTownHouseHelper(TileIndex tile, Town *t, HouseID house)
 
{
 
	assert(IsTileType(tile, MP_HOUSE));
 
	DecreaseBuildingCount(t, house);
 
	DoClearSquare(tile);
 
	DeleteAnimatedTile(tile);
 

	
 
	DeleteNewGRFInspectWindow(GSF_HOUSES, tile);
 
}
 

	
 
/**
 
@@ -2652,51 +2571,48 @@ void ClearTownHouse(Town *t, TileIndex t
 

	
 
	/* Remove population from the town if the house is finished. */
 
	if (IsHouseCompleted(tile)) {
 
		ChangePopulation(t, -hs->population);
 
	}
 

	
 
	t->cache.num_houses--;
 

	
 
	/* Clear flags for houses that only may exist once/town. */
 
	if (hs->building_flags & BUILDING_IS_CHURCH) {
 
		ClrBit(t->flags, TOWN_HAS_CHURCH);
 
	} else if (hs->building_flags & BUILDING_IS_STADIUM) {
 
		ClrBit(t->flags, TOWN_HAS_STADIUM);
 
	}
 

	
 
	/* Do the actual clearing of tiles */
 
	DoClearTownHouseHelper(tile, t, house);
 
	if (hs->building_flags & BUILDING_2_TILES_Y)   DoClearTownHouseHelper(tile + TileDiffXY(0, 1), t, ++house);
 
	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);
 

	
 
	UpdateTownRadius(t);
 

	
 
	/* Update cargo acceptance. */
 
	UpdateTownCargoes(t, tile);
 
}
 

	
 
/**
 
 * Rename a town (server-only).
 
 * @param tile unused
 
 * @param flags type of operation
 
 * @param p1 town ID to rename
 
 * @param p2 unused
 
 * @param text the new name or an empty string when resetting to the default
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdRenameTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	Town *t = Town::GetIfValid(p1);
 
	if (t == nullptr) return CMD_ERROR;
 

	
 
	bool reset = StrEmpty(text);
 

	
 
	if (!reset) {
 
		if (Utf8StringLength(text) >= MAX_LENGTH_TOWN_NAME_CHARS) return CMD_ERROR;
 
		if (!IsUniqueTownName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
@@ -3677,52 +3593,50 @@ CommandCost CheckforTownRating(DoCommand
 
	 */
 
	int needed = needed_rating[_settings_game.difficulty.town_council_tolerance][type];
 

	
 
	if (GetRating(t) < needed) {
 
		SetDParam(0, t->index);
 
		return_cmd_error(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS);
 
	}
 

	
 
	return CommandCost();
 
}
 

	
 
void TownsMonthlyLoop()
 
{
 
	for (Town *t : Town::Iterate()) {
 
		if (t->road_build_months != 0) t->road_build_months--;
 

	
 
		if (t->exclusive_counter != 0) {
 
			if (--t->exclusive_counter == 0) t->exclusivity = INVALID_COMPANY;
 
		}
 

	
 
		UpdateTownAmounts(t);
 
		UpdateTownGrowth(t);
 
		UpdateTownRating(t);
 
		UpdateTownUnwanted(t);
 
		UpdateTownCargoes(t);
 
	}
 

	
 
	UpdateTownCargoBitmap();
 
}
 

	
 
void TownsYearlyLoop()
 
{
 
	/* Increment house ages */
 
	for (TileIndex t = 0; t < MapSize(); t++) {
 
		if (!IsTileType(t, MP_HOUSE)) continue;
 
		IncrementHouseAge(t);
 
	}
 
}
 

	
 
static CommandCost TerraformTile_Town(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
 
{
 
	if (AutoslopeEnabled()) {
 
		HouseID house = GetHouseType(tile);
 
		GetHouseNorthPart(house); // modifies house to the ID of the north tile
 
		const HouseSpec *hs = HouseSpec::Get(house);
 

	
 
		/* Here we differ from TTDP by checking TILE_NOT_SLOPED */
 
		if (((hs->building_flags & TILE_NOT_SLOPED) == 0) && !IsSteepSlope(tileh_new) &&
 
				(GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
 
			bool allow_terraform = true;
 

	
 
			/* Call the autosloping callback per tile, not for the whole building at once. */