Update to 1.10.0-beta1

This commit is contained in:
dP
2019-10-31 22:24:28 +03:00
parent b84a475e14
commit 599ccf0c2b
1470 changed files with 354219 additions and 16795 deletions

View File

@@ -14,6 +14,7 @@
#include "company_base.h"
#include "roadveh.h"
#include "viewport_func.h"
#include "viewport_kdtree.h"
#include "date_func.h"
#include "command_func.h"
#include "news_func.h"
@@ -21,8 +22,10 @@
#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"
@@ -35,6 +38,20 @@
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);
@@ -54,7 +71,7 @@ Station::Station(TileIndex tile) :
SpecializedStation<Station, false>(tile),
bus_station(INVALID_TILE, 0, 0),
truck_station(INVALID_TILE, 0, 0),
dock_tile(INVALID_TILE),
ship_station(INVALID_TILE, 0, 0),
indtype(IT_INVALID),
time_since_load(255),
time_since_unload(255),
@@ -91,7 +108,7 @@ Station::~Station()
for (CargoID c = 0; c < NUM_CARGO; ++c) {
LinkGraph *lg = LinkGraph::GetIfValid(this->goods[c].link_graph);
if (lg == NULL) continue;
if (lg == nullptr) continue;
for (NodeID node = 0; node < lg->Size(); ++node) {
Station *st = Station::Get((*lg)[node].Station());
@@ -119,6 +136,9 @@ Station::~Station()
}
}
/* Remove station from industries and towns that reference it. */
this->RemoveFromAllNearbyLists();
/* Clear the persistent storage. */
delete this->airport.psa;
@@ -142,6 +162,9 @@ Station::~Station()
}
CargoPacket::InvalidateAllFrom(this->index);
_station_kdtree.Remove(this->index);
_viewport_sign_kdtree.Remove(ViewportSignKdtreeItem::MakeStation(this->index));
}
@@ -164,9 +187,9 @@ RoadStop *Station::GetPrimaryRoadStop(const RoadVehicle *v) const
{
RoadStop *rs = this->GetPrimaryRoadStop(v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK);
for (; rs != NULL; rs = rs->next) {
for (; rs != nullptr; rs = rs->next) {
/* The vehicle cannot go to this roadstop (different roadtype) */
if ((GetRoadTypes(rs->xy) & v->compatible_roadtypes) == ROADTYPES_NONE) continue;
if (!HasTileAnyRoadType(rs->xy, v->compatible_roadtypes)) continue;
/* The vehicle is articulated and can therefore not go to a standard road stop. */
if (IsStandardRoadStopTile(rs->xy) && v->HasArticulatedPart()) continue;
@@ -184,7 +207,7 @@ RoadStop *Station::GetPrimaryRoadStop(const RoadVehicle *v) const
void Station::AddFacility(StationFacility new_facility_bit, TileIndex facil_xy)
{
if (this->facilities == FACIL_NONE) {
this->xy = facil_xy;
this->MoveSign(facil_xy);
this->random_bits = Random();
}
this->facilities |= new_facility_bit;
@@ -261,6 +284,39 @@ void Station::MarkTilesDirty(bool cargo_change) const
return length;
}
/**
* Get the catchment size of an individual station tile.
* @param tile Station tile to get catchment size of.
* @param st Associated station of station tile.
* @pre IsTileType(tile, MP_STATION)
* @return The catchment size of the station tile.
*/
static uint GetTileCatchmentRadius(TileIndex tile, const Station *st)
{
assert(IsTileType(tile, MP_STATION));
if (_settings_game.station.modified_catchment) {
switch (GetStationType(tile)) {
case STATION_RAIL: return CA_TRAIN;
case STATION_OILRIG: return CA_UNMODIFIED;
case STATION_AIRPORT: return st->airport.GetSpec()->catchment;
case STATION_TRUCK: return CA_TRUCK;
case STATION_BUS: return CA_BUS;
case STATION_DOCK: return CA_DOCK;
default: NOT_REACHED();
case STATION_BUOY:
case STATION_WAYPOINT: return CA_NONE;
}
} else {
switch (GetStationType(tile)) {
default: return CA_UNMODIFIED;
case STATION_BUOY:
case STATION_WAYPOINT: return CA_NONE;
}
}
}
/**
* Determines the catchment radius of the station
* @return The radius
@@ -270,13 +326,13 @@ uint Station::GetCatchmentRadius() const
uint ret = CA_NONE;
if (_settings_game.station.modified_catchment) {
if (this->bus_stops != NULL) ret = max<uint>(ret, CA_BUS);
if (this->truck_stops != NULL) ret = max<uint>(ret, CA_TRUCK);
if (this->bus_stops != nullptr) ret = max<uint>(ret, CA_BUS);
if (this->truck_stops != nullptr) ret = max<uint>(ret, CA_TRUCK);
if (this->train_station.tile != INVALID_TILE) ret = max<uint>(ret, CA_TRAIN);
if (this->dock_tile != INVALID_TILE) ret = max<uint>(ret, CA_DOCK);
if (this->ship_station.tile != INVALID_TILE) ret = max<uint>(ret, CA_DOCK);
if (this->airport.tile != INVALID_TILE) ret = max<uint>(ret, this->airport.GetSpec()->catchment);
} else {
if (this->bus_stops != NULL || this->truck_stops != NULL || this->train_station.tile != INVALID_TILE || this->dock_tile != INVALID_TILE || this->airport.tile != INVALID_TILE) {
if (this->bus_stops != nullptr || this->truck_stops != nullptr || this->train_station.tile != INVALID_TILE || this->ship_station.tile != INVALID_TILE || this->airport.tile != INVALID_TILE) {
ret = CA_UNMODIFIED;
}
}
@@ -305,79 +361,129 @@ Rect Station::GetCatchmentRect() const
return ret;
}
/** Rect and pointer to IndustryVector */
struct RectAndIndustryVector {
Rect rect; ///< The rectangle to search the industries in.
IndustryVector *industries_near; ///< The nearby industries.
};
/**
* Callback function for Station::RecomputeIndustriesNear()
* Tests whether tile is an industry and possibly adds
* the industry to station's industries_near list.
* @param ind_tile tile to check
* @param user_data pointer to RectAndIndustryVector
* @return always false, we want to search all tiles
* Add nearby industry to station's industries_near list if it accepts cargo.
* @param ind Industry
* @param st Station
*/
static bool FindIndustryToDeliver(TileIndex ind_tile, void *user_data)
static void AddIndustryToDeliver(Industry *ind, Station *st)
{
/* Only process industry tiles */
if (!IsTileType(ind_tile, MP_INDUSTRY)) return false;
RectAndIndustryVector *riv = (RectAndIndustryVector *)user_data;
Industry *ind = Industry::GetByTile(ind_tile);
/* Don't check further if this industry is already in the list */
if (riv->industries_near->Contains(ind)) return false;
/* Only process tiles in the station acceptance rectangle */
int x = TileX(ind_tile);
int y = TileY(ind_tile);
if (x < riv->rect.left || x > riv->rect.right || y < riv->rect.top || y > riv->rect.bottom) return false;
if (st->industries_near.find(ind) != st->industries_near.end()) return;
/* Include only industries that can accept cargo */
uint cargo_index;
for (cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) {
if (ind->accepts_cargo[cargo_index] != CT_INVALID) break;
}
if (cargo_index >= lengthof(ind->accepts_cargo)) return false;
if (cargo_index >= lengthof(ind->accepts_cargo)) return;
*riv->industries_near->Append() = ind;
st->industries_near.insert(ind);
}
/**
* Remove this station from the nearby stations lists of all towns and industries.
*/
void Station::RemoveFromAllNearbyLists()
{
Town *t;
FOR_ALL_TOWNS(t) { t->stations_near.erase(this); }
Industry *i;
FOR_ALL_INDUSTRIES(i) { i->stations_near.erase(this); }
}
/**
* Test if the given town ID is covered by our catchment area.
* This is used when removing a house tile to determine if it was the last house tile
* within our catchment.
* @param t TownID to test.
* @return true if at least one house tile of TownID is covered.
*/
bool Station::CatchmentCoversTown(TownID t) const
{
BitmapTileIterator it(this->catchment_tiles);
for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) {
if (IsTileType(tile, MP_HOUSE) && GetTownIndex(tile) == t) return true;
}
return false;
}
/**
* Recomputes Station::industries_near, list of industries possibly
* accepting cargo in station's catchment radius
* Recompute tiles covered in our catchment area.
* This will additionally recompute nearby towns and industries.
*/
void Station::RecomputeIndustriesNear()
void Station::RecomputeCatchment()
{
this->industries_near.Clear();
if (this->rect.IsEmpty()) return;
this->industries_near.clear();
this->RemoveFromAllNearbyLists();
RectAndIndustryVector riv = {
this->GetCatchmentRect(),
&this->industries_near
};
if (this->rect.IsEmpty()) {
this->catchment_tiles.Reset();
return;
}
/* Compute maximum extent of acceptance rectangle wrt. station sign */
TileIndex start_tile = this->xy;
uint max_radius = max(
max(DistanceManhattan(start_tile, TileXY(riv.rect.left, riv.rect.top)), DistanceManhattan(start_tile, TileXY(riv.rect.left, riv.rect.bottom))),
max(DistanceManhattan(start_tile, TileXY(riv.rect.right, riv.rect.top)), DistanceManhattan(start_tile, TileXY(riv.rect.right, riv.rect.bottom)))
);
if (!_settings_game.station.serve_neutral_industries && this->industry != nullptr) {
/* Station is associated with an industry, so we only need to deliver to that industry. */
this->catchment_tiles.Initialize(this->industry->location);
TILE_AREA_LOOP(tile, this->industry->location) {
if (IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == this->industry->index) {
this->catchment_tiles.SetTile(tile);
}
}
/* The industry's stations_near may have been computed before its neutral station was built so clear and re-add here. */
for (Station *st : this->industry->stations_near) {
st->industries_near.erase(this->industry);
}
this->industry->stations_near.clear();
this->industry->stations_near.insert(this);
this->industries_near.insert(this->industry);
return;
}
CircularTileSearch(&start_tile, 2 * max_radius + 1, &FindIndustryToDeliver, &riv);
this->catchment_tiles.Initialize(GetCatchmentRect());
/* Loop finding all station tiles */
TileArea ta(TileXY(this->rect.left, this->rect.top), TileXY(this->rect.right, this->rect.bottom));
TILE_AREA_LOOP(tile, ta) {
if (!IsTileType(tile, MP_STATION) || GetStationIndex(tile) != this->index) continue;
uint r = GetTileCatchmentRadius(tile, this);
if (r == CA_NONE) continue;
/* This tile sub-loop doesn't need to test any tiles, they are simply added to the catchment set. */
TileArea ta2 = TileArea(tile, 1, 1).Expand(r);
TILE_AREA_LOOP(tile2, ta2) this->catchment_tiles.SetTile(tile2);
}
/* Search catchment tiles for towns and industries */
BitmapTileIterator it(this->catchment_tiles);
for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) {
if (IsTileType(tile, MP_HOUSE)) {
Town *t = Town::GetByTile(tile);
t->stations_near.insert(this);
}
if (IsTileType(tile, MP_INDUSTRY)) {
Industry *i = Industry::GetByTile(tile);
/* Ignore industry if it has a neutral station. It already can't be this station. */
if (!_settings_game.station.serve_neutral_industries && i->neutral_station != nullptr) continue;
i->stations_near.insert(this);
/* Add if we can deliver to this industry as well */
AddIndustryToDeliver(i, this);
}
}
}
/**
* Recomputes Station::industries_near for all stations
* Recomputes catchment of all stations.
* This will additionally recompute nearby stations for all towns and industries.
*/
/* static */ void Station::RecomputeIndustriesNearForAll()
/* static */ void Station::RecomputeCatchmentForAll()
{
Station *st;
FOR_ALL_STATIONS(st) st->RecomputeIndustriesNear();
FOR_ALL_STATIONS(st) { st->RecomputeCatchment(); }
}
/************************************************************************/
@@ -565,3 +671,8 @@ Money AirportMaintenanceCost(Owner owner)
/* 3 bits fraction for the maintenance cost factor. */
return total_cost >> 3;
}
bool StationCompare::operator() (const Station *lhs, const Station *rhs) const
{
return lhs->index < rhs->index;
}