Changeset - r23436:cfad304b5b27
[Not reviewed]
master
0 13 1
Niels Martin Hansen - 5 years ago 2019-02-18 20:14:52
nielsm@indvikleren.dk
Codechange: Make a k-d tree index of stations
14 files changed with 127 insertions and 33 deletions:
0 comments (0 inline, 0 general)
projects/openttd_vs140.vcxproj
Show inline comments
 
@@ -637,24 +637,25 @@
 
    <ClInclude Include="..\src\signs_type.h" />
 
    <ClInclude Include="..\src\slope_func.h" />
 
    <ClInclude Include="..\src\slope_type.h" />
 
    <ClInclude Include="..\src\smallmap_gui.h" />
 
    <ClInclude Include="..\src\sortlist_type.h" />
 
    <ClInclude Include="..\src\sound_func.h" />
 
    <ClInclude Include="..\src\sound_type.h" />
 
    <ClInclude Include="..\src\sprite.h" />
 
    <ClInclude Include="..\src\spritecache.h" />
 
    <ClInclude Include="..\src\station_base.h" />
 
    <ClInclude Include="..\src\station_func.h" />
 
    <ClInclude Include="..\src\station_gui.h" />
 
    <ClInclude Include="..\src\station_kdtree.h" />
 
    <ClInclude Include="..\src\station_type.h" />
 
    <ClInclude Include="..\src\statusbar_gui.h" />
 
    <ClInclude Include="..\src\stdafx.h" />
 
    <ClInclude Include="..\src\story_base.h" />
 
    <ClInclude Include="..\src\story_type.h" />
 
    <ClInclude Include="..\src\strgen\strgen.h" />
 
    <ClInclude Include="..\src\string_base.h" />
 
    <ClInclude Include="..\src\string_func.h" />
 
    <ClInclude Include="..\src\string_type.h" />
 
    <ClInclude Include="..\src\os\windows\string_uniscribe.h" />
 
    <ClInclude Include="..\src\stringfilter_type.h" />
 
    <ClInclude Include="..\src\strings_func.h" />
projects/openttd_vs140.vcxproj.filters
Show inline comments
 
@@ -1017,24 +1017,27 @@
 
    <ClInclude Include="..\src\spritecache.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\station_base.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\station_func.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\station_gui.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\station_kdtree.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\station_type.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\statusbar_gui.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\stdafx.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\story_base.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
projects/openttd_vs141.vcxproj
Show inline comments
 
@@ -637,24 +637,25 @@
 
    <ClInclude Include="..\src\signs_type.h" />
 
    <ClInclude Include="..\src\slope_func.h" />
 
    <ClInclude Include="..\src\slope_type.h" />
 
    <ClInclude Include="..\src\smallmap_gui.h" />
 
    <ClInclude Include="..\src\sortlist_type.h" />
 
    <ClInclude Include="..\src\sound_func.h" />
 
    <ClInclude Include="..\src\sound_type.h" />
 
    <ClInclude Include="..\src\sprite.h" />
 
    <ClInclude Include="..\src\spritecache.h" />
 
    <ClInclude Include="..\src\station_base.h" />
 
    <ClInclude Include="..\src\station_func.h" />
 
    <ClInclude Include="..\src\station_gui.h" />
 
    <ClInclude Include="..\src\station_kdtree.h" />
 
    <ClInclude Include="..\src\station_type.h" />
 
    <ClInclude Include="..\src\statusbar_gui.h" />
 
    <ClInclude Include="..\src\stdafx.h" />
 
    <ClInclude Include="..\src\story_base.h" />
 
    <ClInclude Include="..\src\story_type.h" />
 
    <ClInclude Include="..\src\strgen\strgen.h" />
 
    <ClInclude Include="..\src\string_base.h" />
 
    <ClInclude Include="..\src\string_func.h" />
 
    <ClInclude Include="..\src\string_type.h" />
 
    <ClInclude Include="..\src\os\windows\string_uniscribe.h" />
 
    <ClInclude Include="..\src\stringfilter_type.h" />
 
    <ClInclude Include="..\src\strings_func.h" />
projects/openttd_vs141.vcxproj.filters
Show inline comments
 
@@ -1017,24 +1017,27 @@
 
    <ClInclude Include="..\src\spritecache.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\station_base.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\station_func.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\station_gui.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\station_kdtree.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\station_type.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\statusbar_gui.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\stdafx.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\story_base.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
projects/openttd_vs142.vcxproj
Show inline comments
 
@@ -637,24 +637,25 @@
 
    <ClInclude Include="..\src\signs_type.h" />
 
    <ClInclude Include="..\src\slope_func.h" />
 
    <ClInclude Include="..\src\slope_type.h" />
 
    <ClInclude Include="..\src\smallmap_gui.h" />
 
    <ClInclude Include="..\src\sortlist_type.h" />
 
    <ClInclude Include="..\src\sound_func.h" />
 
    <ClInclude Include="..\src\sound_type.h" />
 
    <ClInclude Include="..\src\sprite.h" />
 
    <ClInclude Include="..\src\spritecache.h" />
 
    <ClInclude Include="..\src\station_base.h" />
 
    <ClInclude Include="..\src\station_func.h" />
 
    <ClInclude Include="..\src\station_gui.h" />
 
    <ClInclude Include="..\src\station_kdtree.h" />
 
    <ClInclude Include="..\src\station_type.h" />
 
    <ClInclude Include="..\src\statusbar_gui.h" />
 
    <ClInclude Include="..\src\stdafx.h" />
 
    <ClInclude Include="..\src\story_base.h" />
 
    <ClInclude Include="..\src\story_type.h" />
 
    <ClInclude Include="..\src\strgen\strgen.h" />
 
    <ClInclude Include="..\src\string_base.h" />
 
    <ClInclude Include="..\src\string_func.h" />
 
    <ClInclude Include="..\src\string_type.h" />
 
    <ClInclude Include="..\src\os\windows\string_uniscribe.h" />
 
    <ClInclude Include="..\src\stringfilter_type.h" />
 
    <ClInclude Include="..\src\strings_func.h" />
projects/openttd_vs142.vcxproj.filters
Show inline comments
 
@@ -1017,24 +1017,27 @@
 
    <ClInclude Include="..\src\spritecache.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\station_base.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\station_func.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\station_gui.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\station_kdtree.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\station_type.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\statusbar_gui.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\stdafx.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\story_base.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
source.list
Show inline comments
 
@@ -324,24 +324,25 @@ signs_func.h
 
signs_type.h
 
slope_func.h
 
slope_type.h
 
smallmap_gui.h
 
sortlist_type.h
 
sound_func.h
 
sound_type.h
 
sprite.h
 
spritecache.h
 
station_base.h
 
station_func.h
 
station_gui.h
 
station_kdtree.h
 
station_type.h
 
statusbar_gui.h
 
stdafx.h
 
story_base.h
 
story_type.h
 
strgen/strgen.h
 
string_base.h
 
string_func.h
 
string_type.h
 
os/windows/string_uniscribe.h
 
stringfilter_type.h
 
strings_func.h
src/misc.cpp
Show inline comments
 
@@ -19,24 +19,25 @@
 
#include "economy_func.h"
 
#include "date_func.h"
 
#include "texteff.hpp"
 
#include "gfx_func.h"
 
#include "gamelog.h"
 
#include "animated_tile_func.h"
 
#include "tilehighlight_func.h"
 
#include "network/network_func.h"
 
#include "window_func.h"
 
#include "core/pool_type.hpp"
 
#include "game/game.hpp"
 
#include "linkgraph/linkgraphschedule.h"
 
#include "station_kdtree.h"
 
#include "town_kdtree.h"
 

	
 
#include "safeguards.h"
 

	
 

	
 
extern TileIndex _cur_tileloop_tile;
 
extern void MakeNewgameSettingsLive();
 

	
 
void InitializeSound();
 
void InitializeMusic();
 
void InitializeVehicles();
 
void InitializeRailGui();
 
@@ -67,24 +68,25 @@ void InitializeGame(uint size_x, uint si
 
	_cur_tileloop_tile = 1;
 
	_thd.redsq = INVALID_TILE;
 
	if (reset_settings) MakeNewgameSettingsLive();
 

	
 
	if (reset_date) {
 
		SetDate(ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1), 0);
 
		InitializeOldNames();
 
	}
 

	
 
	LinkGraphSchedule::Clear();
 
	PoolBase::Clean(PT_NORMAL);
 

	
 
	RebuildStationKdtree();
 
	RebuildTownKdtree();
 

	
 
	ResetPersistentNewGRFData();
 

	
 
	InitializeSound();
 
	InitializeMusic();
 

	
 
	InitializeVehicles();
 

	
 
	InitNewsItemStructs();
 
	InitializeLandscape();
 
	InitializeRailGui();
src/saveload/afterload.cpp
Show inline comments
 
@@ -528,24 +528,25 @@ bool AfterLoadGame()
 
	TileIndex map_size = MapSize();
 

	
 
	extern TileIndex _cur_tileloop_tile; // From landscape.cpp.
 
	/* The LFSR used in RunTileLoop iteration cannot have a zeroed state, make it non-zeroed. */
 
	if (_cur_tileloop_tile == 0) _cur_tileloop_tile = 1;
 

	
 
	if (IsSavegameVersionBefore(SLV_98)) GamelogOldver();
 

	
 
	GamelogTestRevision();
 
	GamelogTestMode();
 

	
 
	RebuildTownKdtree();
 
	RebuildStationKdtree();
 

	
 
	if (IsSavegameVersionBefore(SLV_98)) GamelogGRFAddList(_grfconfig);
 

	
 
	if (IsSavegameVersionBefore(SLV_119)) {
 
		_pause_mode = (_pause_mode == 2) ? PM_PAUSED_NORMAL : PM_UNPAUSED;
 
	} else if (_network_dedicated && (_pause_mode & PM_PAUSED_ERROR) != 0) {
 
		DEBUG(net, 0, "The loading savegame was paused due to an error state.");
 
		DEBUG(net, 0, "  The savegame cannot be used for multiplayer!");
 
		/* Restore the signals */
 
		ResetSignalHandlers();
 
		return false;
 
	} else if (!_networking || _network_server) {
src/station.cpp
Show inline comments
 
@@ -12,39 +12,54 @@
 
#include "stdafx.h"
 
#include "company_func.h"
 
#include "company_base.h"
 
#include "roadveh.h"
 
#include "viewport_func.h"
 
#include "date_func.h"
 
#include "command_func.h"
 
#include "news_func.h"
 
#include "aircraft.h"
 
#include "vehiclelist.h"
 
#include "core/pool_func.hpp"
 
#include "station_base.h"
 
#include "station_kdtree.h"
 
#include "roadstop_base.h"
 
#include "industry.h"
 
#include "town.h"
 
#include "core/random_func.hpp"
 
#include "linkgraph/linkgraph.h"
 
#include "linkgraph/linkgraphschedule.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "safeguards.h"
 

	
 
/** The pool of stations. */
 
StationPool _station_pool("Station");
 
INSTANTIATE_POOL_METHODS(Station)
 

	
 

	
 
StationKdtree _station_kdtree(Kdtree_StationXYFunc);
 

	
 
void RebuildStationKdtree()
 
{
 
	std::vector<StationID> stids;
 
	BaseStation *st;
 
	FOR_ALL_STATIONS(st) {
 
		stids.push_back(st->index);
 
	}
 
	_station_kdtree.Build(stids.begin(), stids.end());
 
}
 

	
 

	
 
BaseStation::~BaseStation()
 
{
 
	free(this->name);
 
	free(this->speclist);
 

	
 
	if (CleaningPool()) return;
 

	
 
	DeleteWindowById(WC_TRAINS_LIST,   VehicleListIdentifier(VL_STATION_LIST, VEH_TRAIN,    this->owner, this->index).Pack());
 
	DeleteWindowById(WC_ROADVEH_LIST,  VehicleListIdentifier(VL_STATION_LIST, VEH_ROAD,     this->owner, this->index).Pack());
 
	DeleteWindowById(WC_SHIPS_LIST,    VehicleListIdentifier(VL_STATION_LIST, VEH_SHIP,     this->owner, this->index).Pack());
 
	DeleteWindowById(WC_AIRCRAFT_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_AIRCRAFT, this->owner, this->index).Pack());
 

	
 
@@ -137,24 +152,26 @@ Station::~Station()
 

	
 
	/* Now delete all orders that go to the station */
 
	RemoveOrderFromAllVehicles(OT_GOTO_STATION, this->index);
 

	
 
	/* Remove all news items */
 
	DeleteStationNews(this->index);
 

	
 
	for (CargoID c = 0; c < NUM_CARGO; c++) {
 
		this->goods[c].cargo.Truncate();
 
	}
 

	
 
	CargoPacket::InvalidateAllFrom(this->index);
 

	
 
	_station_kdtree.Remove(this->index);
 
}
 

	
 

	
 
/**
 
 * Invalidating of the JoinStation window has to be done
 
 * after removing item from the pool.
 
 * @param index index of deleted item
 
 */
 
void BaseStation::PostDestructor(size_t index)
 
{
 
	InvalidateWindowData(WC_SELECT_STATION, 0, 0);
 
}
src/station_base.h
Show inline comments
 
@@ -547,13 +547,15 @@ public:
 
		while (this->tile != INVALID_TILE && !st->TileBelongsToAirport(this->tile)) {
 
			(*this).OrthogonalTileIterator::operator++();
 
		}
 
		return *this;
 
	}
 

	
 
	virtual TileIterator *Clone() const
 
	{
 
		return new AirportTileIterator(*this);
 
	}
 
};
 

	
 
void RebuildStationKdtree();
 

	
 
#endif /* STATION_BASE_H */
src/station_cmd.cpp
Show inline comments
 
@@ -28,24 +28,25 @@
 
#include "pathfinder/yapf/yapf_cache.h"
 
#include "road_internal.h" /* For drawing catenary/checking road removal */
 
#include "autoslope.h"
 
#include "water.h"
 
#include "strings_func.h"
 
#include "clear_func.h"
 
#include "date_func.h"
 
#include "vehicle_func.h"
 
#include "string_func.h"
 
#include "animated_tile_func.h"
 
#include "elrail_func.h"
 
#include "station_base.h"
 
#include "station_kdtree.h"
 
#include "roadstop_base.h"
 
#include "newgrf_railtype.h"
 
#include "waypoint_base.h"
 
#include "waypoint_func.h"
 
#include "pbs.h"
 
#include "debug.h"
 
#include "core/random_func.hpp"
 
#include "company_base.h"
 
#include "table/airporttile_ids.h"
 
#include "newgrf_airporttiles.h"
 
#include "order_backup.h"
 
#include "newgrf_house.h"
 
@@ -350,37 +351,39 @@ static StringID GenerateStationName(Stat
 
	return (tmp == 0) ? STR_SV_STNAME_FALLBACK : (STR_SV_STNAME + FindFirstBit(tmp));
 
}
 
#undef M
 

	
 
/**
 
 * Find the closest deleted station of the current company
 
 * @param tile the tile to search from.
 
 * @return the closest station or NULL if too far.
 
 */
 
static Station *GetClosestDeletedStation(TileIndex tile)
 
{
 
	uint threshold = 8;
 

	
 
	Station *best_station = NULL;
 
	Station *st;
 

	
 
	FOR_ALL_STATIONS(st) {
 
	ForAllStationsRadius(tile, threshold, [&](Station *st) {
 
		if (!st->IsInUse() && st->owner == _current_company) {
 
			uint cur_dist = DistanceManhattan(tile, st->xy);
 

	
 
			if (cur_dist < threshold) {
 
				threshold = cur_dist;
 
				best_station = st;
 
			} else if (cur_dist == threshold && best_station != NULL) {
 
				/* In case of a tie, lowest station ID wins */
 
				if (st->index < best_station->index) best_station = st;
 
			}
 
		}
 
	}
 
	});
 

	
 
	return best_station;
 
}
 

	
 

	
 
void Station::GetTileArea(TileArea *ta, StationType type) const
 
{
 
	switch (type) {
 
		case STATION_RAIL:
 
			*ta = this->train_station;
 
			return;
 

	
 
@@ -658,26 +661,31 @@ void UpdateStationAcceptance(Station *st
 

	
 
	/* redraw the station view since acceptance changed */
 
	SetWindowWidgetDirty(WC_STATION_VIEW, st->index, WID_SV_ACCEPT_RATING_LIST);
 
}
 

	
 
static void UpdateStationSignCoord(BaseStation *st)
 
{
 
	const StationRect *r = &st->rect;
 

	
 
	if (r->IsEmpty()) return; // no tiles belong to this station
 

	
 
	/* clamp sign coord to be inside the station rect */
 
	st->xy = TileXY(ClampU(TileX(st->xy), r->left, r->right), ClampU(TileY(st->xy), r->top, r->bottom));
 
	st->UpdateVirtCoord();
 
	TileIndex new_xy = TileXY(ClampU(TileX(st->xy), r->left, r->right), ClampU(TileY(st->xy), r->top, r->bottom));
 
	if (new_xy != st->xy) {
 
		_station_kdtree.Remove(st->index);
 
		st->xy = new_xy;
 
		_station_kdtree.Insert(st->index);
 
		st->UpdateVirtCoord();
 
	}
 

	
 
	if (!Station::IsExpected(st)) return;
 
	Station *full_station = Station::From(st);
 
	for (CargoID c = 0; c < NUM_CARGO; ++c) {
 
		LinkGraphID lg = full_station->goods[c].link_graph;
 
		if (!LinkGraph::IsValidID(lg)) continue;
 
		(*LinkGraph::Get(lg))[full_station->goods[c].node].UpdateLocation(st->xy);
 
	}
 
}
 

	
 
/**
 
 * Common part of building various station parts and possibly attaching them to an existing one.
 
@@ -697,24 +705,25 @@ static CommandCost BuildStationPart(Stat
 
		if ((*st)->owner != _current_company) {
 
			return_cmd_error(CMD_ERROR);
 
		}
 

	
 
		CommandCost ret = (*st)->rect.BeforeAddRect(area.tile, area.w, area.h, StationRect::ADD_TEST);
 
		if (ret.Failed()) return ret;
 
	} else {
 
		/* allocate and initialize new station */
 
		if (!Station::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING);
 

	
 
		if (flags & DC_EXEC) {
 
			*st = new Station(area.tile);
 
			_station_kdtree.Insert((*st)->index);
 

	
 
			(*st)->town = ClosestTownFromTile(area.tile, UINT_MAX);
 
			(*st)->string_id = GenerateStationName(*st, area.tile, name_class);
 

	
 
			if (Company::IsValidID(_current_company)) {
 
				SetBit((*st)->town->have_ratings, _current_company);
 
			}
 
		}
 
	}
 
	return CommandCost();
 
}
 

	
 
@@ -3685,38 +3694,35 @@ void StationMonthlyLoop()
 
	FOR_ALL_STATIONS(st) {
 
		for (CargoID i = 0; i < NUM_CARGO; i++) {
 
			GoodsEntry *ge = &st->goods[i];
 
			SB(ge->status, GoodsEntry::GES_LAST_MONTH, 1, GB(ge->status, GoodsEntry::GES_CURRENT_MONTH, 1));
 
			ClrBit(ge->status, GoodsEntry::GES_CURRENT_MONTH);
 
		}
 
	}
 
}
 

	
 

	
 
void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius)
 
{
 
	Station *st;
 

	
 
	FOR_ALL_STATIONS(st) {
 
		if (st->owner == owner &&
 
				DistanceManhattan(tile, st->xy) <= radius) {
 
	ForAllStationsRadius(tile, radius, [&](Station *st) {
 
		if (st->owner == owner) {
 
			for (CargoID i = 0; i < NUM_CARGO; i++) {
 
				GoodsEntry *ge = &st->goods[i];
 

	
 
				if (ge->status != 0) {
 
					ge->rating = Clamp(ge->rating + amount, 0, 255);
 
				}
 
			}
 
		}
 
	}
 
	});
 
}
 

	
 
static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceType source_type, SourceID source_id)
 
{
 
	/* We can't allocate a CargoPacket? Then don't do anything
 
	 * at all; i.e. just discard the incoming cargo. */
 
	if (!CargoPacket::CanAllocateItem()) return 0;
 

	
 
	GoodsEntry &ge = st->goods[type];
 
	amount += ge.amount_fract;
 
	ge.amount_fract = GB(amount, 0, 8);
 

	
 
@@ -3938,24 +3944,25 @@ uint MoveGoodsToStation(CargoID type, ui
 
	 * of execution would be undefined and that could cause desyncs with callbacks. */
 
	return moved + UpdateStationWaiting(st2, type, worst_cargo, source_type, source_id);
 
}
 

	
 
void BuildOilRig(TileIndex tile)
 
{
 
	if (!Station::CanAllocateItem()) {
 
		DEBUG(misc, 0, "Can't allocate station for oilrig at 0x%X, reverting to oilrig only", tile);
 
		return;
 
	}
 

	
 
	Station *st = new Station(tile);
 
	_station_kdtree.Insert(st->index);
 
	st->town = ClosestTownFromTile(tile, UINT_MAX);
 

	
 
	st->string_id = GenerateStationName(st, tile, STATIONNAMING_OILRIG);
 

	
 
	assert(IsTileType(tile, MP_INDUSTRY));
 
	/* Mark industry as associated both ways */
 
	st->industry = Industry::GetByTile(tile);
 
	st->industry->neutral_station = st;
 
	DeleteAnimatedTile(tile);
 
	MakeOilrig(tile, st->index, GetWaterClass(tile));
 

	
 
	st->owner = OWNER_NONE;
src/station_kdtree.h
Show inline comments
 
new file 100644
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file station_kdtree.h Declarations for accessing the k-d tree of stations */
 

	
 
#ifndef STATION_KDTREE_H
 
#define STATION_KDTREE_H
 

	
 
#include "core/kdtree.hpp"
 
#include "core/math_func.hpp"
 
#include "station_base.h"
 
#include "map_func.h"
 

	
 
inline uint16 Kdtree_StationXYFunc(StationID stid, int dim) { return (dim == 0) ? TileX(BaseStation::Get(stid)->xy) : TileY(BaseStation::Get(stid)->xy); }
 
typedef Kdtree<StationID, decltype(&Kdtree_StationXYFunc), uint16, int> StationKdtree;
 
extern StationKdtree _station_kdtree;
 

	
 
/**
 
 * Call a function on all stations whose sign is within a radius of a center tile.
 
 * @param center  Central tile to search around.
 
 * @param radius  Distance in both X and Y to search within.
 
 * @param func    The function to call, must take a single parameter which is Station*.
 
 */
 
template <typename Func>
 
void ForAllStationsRadius(TileIndex center, uint radius, Func func)
 
{
 
	uint16 x1, y1, x2, y2;
 
	x1 = (uint16)max<int>(0, TileX(center) - radius);
 
	x2 = (uint16)min<int>(TileX(center) + radius + 1, MapSizeX());
 
	y1 = (uint16)max<int>(0, TileY(center) - radius);
 
	y2 = (uint16)min<int>(TileY(center) + radius + 1, MapSizeY());
 

	
 
	_station_kdtree.FindContained(x1, y1, x2, y2, [&](StationID id) {
 
		func(Station::Get(id));
 
	});
 
}
 

	
 
#endif
src/town_cmd.cpp
Show inline comments
 
@@ -9,24 +9,25 @@
 

	
 
/** @file town_cmd.cpp Handling of town tiles. */
 

	
 
#include "stdafx.h"
 
#include "road_internal.h" /* Cleaning up road bits */
 
#include "road_cmd.h"
 
#include "landscape.h"
 
#include "viewport_func.h"
 
#include "cmd_helper.h"
 
#include "command_func.h"
 
#include "industry.h"
 
#include "station_base.h"
 
#include "station_kdtree.h"
 
#include "company_base.h"
 
#include "news_func.h"
 
#include "error.h"
 
#include "object.h"
 
#include "genworld.h"
 
#include "newgrf_debug.h"
 
#include "newgrf_house.h"
 
#include "newgrf_text.h"
 
#include "autoslope.h"
 
#include "tunnelbridge_map.h"
 
#include "strings_func.h"
 
#include "window_func.h"
 
@@ -3188,50 +3189,62 @@ CommandCost CmdDoTownAction(TileIndex ti
 
	CommandCost cost(EXPENSES_OTHER, _price[PR_TOWN_ACTION] * _town_action_costs[p2] >> 8);
 

	
 
	CommandCost ret = _town_action_proc[p2](t, flags);
 
	if (ret.Failed()) return ret;
 

	
 
	if (flags & DC_EXEC) {
 
		SetWindowDirty(WC_TOWN_AUTHORITY, p1);
 
	}
 

	
 
	return cost;
 
}
 

	
 
template <typename Func>
 
static void ForAllStationsNearTown(Town *t, Func func)
 
{
 
	/* Ideally the search radius should be close to the actual town zone 0 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,
 
	 * 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[0] / 2;
 
	ForAllStationsRadius(t->xy, search_radius, [&](const Station * st) {
 
		if (DistanceSquare(st->xy, t->xy) <= t->cache.squared_town_zone_radius[0]) {
 
			func(st);
 
		}
 
	});
 
}
 

	
 
static void UpdateTownRating(Town *t)
 
{
 
	/* Increase company ratings if they're low */
 
	const Company *c;
 
	FOR_ALL_COMPANIES(c) {
 
		if (t->ratings[c->index] < RATING_GROWTH_MAXIMUM) {
 
			t->ratings[c->index] = min((int)RATING_GROWTH_MAXIMUM, t->ratings[c->index] + RATING_GROWTH_UP_STEP);
 
		}
 
	}
 

	
 
	const Station *st;
 
	FOR_ALL_STATIONS(st) {
 
		if (DistanceSquare(st->xy, t->xy) <= t->cache.squared_town_zone_radius[0]) {
 
			if (st->time_since_load <= 20 || st->time_since_unload <= 20) {
 
				if (Company::IsValidID(st->owner)) {
 
					int new_rating = t->ratings[st->owner] + RATING_STATION_UP_STEP;
 
					t->ratings[st->owner] = min(new_rating, INT16_MAX); // do not let it overflow
 
				}
 
			} else {
 
				if (Company::IsValidID(st->owner)) {
 
					int new_rating = t->ratings[st->owner] + RATING_STATION_DOWN_STEP;
 
					t->ratings[st->owner] = max(new_rating, INT16_MIN);
 
				}
 
	ForAllStationsNearTown(t, [&](const Station *st) {
 
		if (st->time_since_load <= 20 || st->time_since_unload <= 20) {
 
			if (Company::IsValidID(st->owner)) {
 
				int new_rating = t->ratings[st->owner] + RATING_STATION_UP_STEP;
 
				t->ratings[st->owner] = min(new_rating, INT16_MAX); // do not let it overflow
 
			}
 
		} else {
 
			if (Company::IsValidID(st->owner)) {
 
				int new_rating = t->ratings[st->owner] + RATING_STATION_DOWN_STEP;
 
				t->ratings[st->owner] = max(new_rating, INT16_MIN);
 
			}
 
		}
 
	}
 
	});
 

	
 
	/* clamp all ratings to valid values */
 
	for (uint i = 0; i < MAX_COMPANIES; i++) {
 
		t->ratings[i] = Clamp(t->ratings[i], RATING_MINIMUM, RATING_MAXIMUM);
 
	}
 

	
 
	SetWindowDirty(WC_TOWN_AUTHORITY, t->index);
 
}
 

	
 

	
 
/**
 
 * Updates town grow counter after growth rate change.
 
@@ -3248,32 +3261,29 @@ static void UpdateTownGrowCounter(Town *
 
	}
 
	t->grow_counter = RoundDivSU((uint32)t->grow_counter * (t->growth_rate + 1), prev_growth_rate + 1);
 
}
 

	
 
/**
 
 * Calculates amount of active stations in the range of town (HZB_TOWN_EDGE).
 
 * @param t The town to calculate stations for
 
 * @returns Amount of active stations
 
 */
 
static int CountActiveStations(Town *t)
 
{
 
	int n = 0;
 
	const Station *st;
 
	FOR_ALL_STATIONS(st) {
 
		if (DistanceSquare(st->xy, t->xy) <= t->cache.squared_town_zone_radius[0]) {
 
			if (st->time_since_load <= 20 || st->time_since_unload <= 20) {
 
				n++;
 
			}
 
	ForAllStationsNearTown(t, [&](const Station * st) {
 
		if (st->time_since_load <= 20 || st->time_since_unload <= 20) {
 
			n++;
 
		}
 
	}
 
	});
 
	return n;
 
}
 

	
 
/**
 
 * Calculates town growth rate in normal conditions (custom growth rate not set).
 
 * If town growth speed is set to None(0) returns the same rate as if it was Normal(2).
 
 * @param t The town to calculate growth rate for
 
 * @returns Calculated growth rate
 
 */
 
static uint GetNormalGrowthRate(Town *t)
 
{
 
	static const uint16 _grow_count_values[2][6] = {
0 comments (0 inline, 0 general)