Merge branch 'master' into jgrpp

Remove the viewport sign cache as this is now superseded by the kd tree
implementation

# Conflicts:
#	src/crashlog.cpp
#	src/lang/english.txt
#	src/misc.cpp
#	src/pathfinder/follow_track.hpp
#	src/pbs.cpp
#	src/rail_cmd.cpp
#	src/saveload/vehicle_sl.cpp
#	src/settings.cpp
#	src/settings_gui.cpp
#	src/ship_cmd.cpp
#	src/station.cpp
#	src/station_base.h
#	src/station_cmd.cpp
#	src/table/settings.ini
#	src/thread/thread_morphos.cpp
#	src/town_cmd.cpp
#	src/train_cmd.cpp
#	src/viewport.cpp
#	src/waypoint.cpp
This commit is contained in:
Jonathan G Rennison
2019-03-12 18:00:36 +00:00
177 changed files with 3131 additions and 2247 deletions

View File

@@ -14,6 +14,7 @@
#include "bridge_map.h"
#include "cmd_helper.h"
#include "viewport_func.h"
#include "viewport_kdtree.h"
#include "command_func.h"
#include "town.h"
#include "news_func.h"
@@ -37,6 +38,7 @@
#include "animated_tile_func.h"
#include "elrail_func.h"
#include "station_base.h"
#include "station_kdtree.h"
#include "roadstop_base.h"
#include "dock_base.h"
#include "newgrf_railtype.h"
@@ -361,19 +363,21 @@ static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming n
static Station *GetClosestDeletedStation(TileIndex tile)
{
uint threshold = 8;
Station *best_station = NULL;
Station *st;
FOR_ALL_STATIONS(st) {
Station *best_station = NULL;
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;
}
@@ -425,7 +429,6 @@ void Station::UpdateVirtCoord()
this->sign.UpdatePosition(pt.x, pt.y, STR_VIEWPORT_STATION);
SetWindowDirty(WC_STATION_VIEW, this->index);
ViewportClearStationSignCache();
}
/** Update the virtual coords needed to draw the station sign for all stations. */
@@ -509,6 +512,8 @@ CargoArray GetProductionAroundTiles(TileIndex tile, int w, int h, int rad)
const Industry *i;
FOR_ALL_INDUSTRIES(i) {
if (!ta.Intersects(i->location)) continue;
/* Skip industry with neutral station */
if (i->neutral_station != NULL && !_settings_game.station.serve_neutral_industries) continue;
for (uint j = 0; j < lengthof(i->produced_cargo); j++) {
CargoID cargo = i->produced_cargo[j];
@@ -526,6 +531,7 @@ CargoArray GetProductionAroundTiles(TileIndex tile, int w, int h, int rad)
* @param h Y extent of area
* @param rad Search radius in addition to given area
* @param always_accepted bitmask of cargo accepted by houses and headquarters; can be NULL
* @param ind Industry associated with neutral station (e.g. oil rig) or NULL
*/
CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, CargoTypes *always_accepted)
{
@@ -550,6 +556,10 @@ CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, Cargo
for (int yc = y1; yc != y2; yc++) {
for (int xc = x1; xc != x2; xc++) {
TileIndex tile = TileXY(xc, yc);
/* Ignore industry if it has a neutral station. */
if (!_settings_game.station.serve_neutral_industries && IsTileType(tile, MP_INDUSTRY) && Industry::GetByTile(tile)->neutral_station != NULL) continue;
AddAcceptedCargo(tile, acceptance, always_accepted);
}
}
@@ -557,6 +567,24 @@ CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, Cargo
return acceptance;
}
/**
* Get the acceptance of cargoes around the station in.
* @param st Station to get acceptance of.
* @param always_accepted bitmask of cargo accepted by houses and headquarters; can be NULL
*/
static CargoArray GetAcceptanceAroundStation(const Station *st, CargoTypes *always_accepted)
{
CargoArray acceptance;
if (always_accepted != NULL) *always_accepted = 0;
BitmapTileIterator it(st->catchment_tiles);
for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) {
AddAcceptedCargo(tile, acceptance, always_accepted);
}
return acceptance;
}
/**
* Update the acceptance for a station.
* @param st Station to update
@@ -570,13 +598,7 @@ void UpdateStationAcceptance(Station *st, bool show_msg)
/* And retrieve the acceptance. */
CargoArray acceptance;
if (!st->rect.IsEmpty()) {
acceptance = GetAcceptanceAroundTiles(
TileXY(st->rect.left, st->rect.top),
st->rect.right - st->rect.left + 1,
st->rect.bottom - st->rect.top + 1,
st->GetCatchmentRadius(),
&st->always_accepted
);
acceptance = GetAcceptanceAroundStation(st, &st->always_accepted);
}
/* Adjust in case our station only accepts fewer kinds of goods */
@@ -651,8 +673,15 @@ static void UpdateStationSignCoord(BaseStation *st)
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) {
_viewport_sign_kdtree.Remove(ViewportSignKdtreeItem::MakeStation(st->index));
_station_kdtree.Remove(st->index);
st->xy = new_xy;
_station_kdtree.Insert(st->index);
_viewport_sign_kdtree.Insert(ViewportSignKdtreeItem::MakeStation(st->index));
st->UpdateVirtCoord();
}
if (!Station::IsExpected(st)) return;
Station *full_station = Station::From(st);
@@ -690,6 +719,8 @@ static CommandCost BuildStationPart(Station **st, DoCommandFlag flags, bool reus
if (flags & DC_EXEC) {
*st = new Station(area.tile);
_station_kdtree.Insert((*st)->index);
_viewport_sign_kdtree.Insert(ViewportSignKdtreeItem::MakeStation((*st)->index));
(*st)->town = ClosestTownFromTile(area.tile, UINT_MAX);
(*st)->string_id = GenerateStationName(*st, area.tile, name_class);
@@ -729,7 +760,7 @@ static void DeleteStationIfEmpty(BaseStation *st)
void Station::AfterStationTileSetChange(bool adding, StationType type)
{
this->UpdateVirtCoord();
this->RecomputeIndustriesNear();
this->RecomputeCatchment();
DirtyCompanyInfrastructureWindows(this->owner);
if (adding) InvalidateWindowData(WC_STATION_LIST, this->owner, 0);
@@ -1730,7 +1761,7 @@ CommandCost CmdRemoveFromRailStation(TileIndex start, DoCommandFlag flags, uint3
if (st->train_station.tile == INVALID_TILE) SetWindowWidgetDirty(WC_STATION_VIEW, st->index, WID_SV_TRAINS);
st->MarkTilesDirty(false);
st->RecomputeIndustriesNear();
st->RecomputeCatchment();
}
/* Now apply the rail cost to the number that we deleted */
@@ -1816,7 +1847,7 @@ static CommandCost RemoveRailStation(TileIndex tile, DoCommandFlag flags)
CommandCost cost = RemoveRailStation(st, flags, _price[PR_CLEAR_STATION_RAIL]);
if (flags & DC_EXEC) st->RecomputeIndustriesNear();
if (flags & DC_EXEC) st->RecomputeCatchment();
return cost;
}
@@ -3250,7 +3281,14 @@ static void GetTileDesc_Station(TileIndex tile, TileDesc *td)
break;
case STATION_TRUCK: str = STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA; break;
case STATION_BUS: str = STR_LAI_STATION_DESCRIPTION_BUS_STATION; break;
case STATION_OILRIG: str = STR_INDUSTRY_NAME_OIL_RIG; break;
case STATION_OILRIG: {
const Industry *i = Station::GetByTile(tile)->industry;
const IndustrySpec *is = GetIndustrySpec(i->type);
td->owner[0] = i->owner;
str = is->name;
if (is->grf_prop.grffile != NULL) td->grf = GetGRFConfig(is->grf_prop.grffile->grfid)->GetName();
break;
}
case STATION_DOCK: str = STR_LAI_STATION_DESCRIPTION_SHIP_DOCK; break;
case STATION_BUOY: str = STR_LAI_STATION_DESCRIPTION_BUOY; break;
case STATION_WAYPOINT: str = STR_LAI_STATION_DESCRIPTION_WAYPOINT; break;
@@ -3437,9 +3475,8 @@ void TriggerWatchedCargoCallbacks(Station *st)
if (cargoes == 0) return;
/* Loop over all houses in the catchment. */
Rect r = st->GetCatchmentRect();
TileArea ta(TileXY(r.left, r.top), TileXY(r.right, r.bottom));
TILE_AREA_LOOP(tile, ta) {
BitmapTileIterator it(st->catchment_tiles);
for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) {
if (IsTileType(tile, MP_HOUSE)) {
WatchedCargoCallback(tile, cargoes);
}
@@ -3893,11 +3930,8 @@ void StationMonthlyLoop()
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];
@@ -3906,7 +3940,7 @@ void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint rad
}
}
}
}
});
}
static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceType source_type, SourceID source_id)
@@ -4000,53 +4034,64 @@ CommandCost CmdRenameStation(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
return CommandCost();
}
static void AddNearbyStationsByCatchment(TileIndex tile, StationList *stations, StationList &nearby)
{
for (Station *st : nearby) {
if (st->TileIsInCatchment(tile)) stations->insert(st);
}
}
/**
* Find all stations around a rectangular producer (industry, house, headquarter, ...)
*
* @param location The location/area of the producer
* @param stations The list to store the stations in
* @param use_nearby Use nearby station list of industry/town associated with location.tile
*/
void FindStationsAroundTiles(const TileArea &location, StationList *stations)
void FindStationsAroundTiles(const TileArea &location, StationList *stations, bool use_nearby)
{
/* area to search = producer plus station catchment radius */
uint max_rad = (_settings_game.station.modified_catchment ? MAX_CATCHMENT : CA_UNMODIFIED);
max_rad += _settings_game.station.catchment_increase;
if (use_nearby) {
/* Industries and towns maintain a list of nearby stations */
if (IsTileType(location.tile, MP_INDUSTRY)) {
/* Industry nearby stations are already filtered by catchment. */
stations = &Industry::GetByTile(location.tile)->stations_near;
return;
} else if (IsTileType(location.tile, MP_HOUSE)) {
/* Town nearby stations need to be filtered per tile. */
assert(location.w == 1 && location.h == 1);
AddNearbyStationsByCatchment(location.tile, stations, Town::GetByTile(location.tile)->stations_near);
return;
}
}
/* Not using, or don't have a nearby stations list, so we need to scan. */
uint x = TileX(location.tile);
uint y = TileY(location.tile);
uint min_x = (x > max_rad) ? x - max_rad : 0;
uint max_x = x + location.w + max_rad;
uint min_y = (y > max_rad) ? y - max_rad : 0;
uint max_y = y + location.h + max_rad;
std::set<StationID> seen_stations;
if (min_x == 0 && _settings_game.construction.freeform_edges) min_x = 1;
if (min_y == 0 && _settings_game.construction.freeform_edges) min_y = 1;
if (max_x >= MapSizeX()) max_x = MapSizeX() - 1;
if (max_y >= MapSizeY()) max_y = MapSizeY() - 1;
/* Scan an area around the building covering the maximum possible station
* to find the possible nearby stations. */
uint max_c = _settings_game.station.modified_catchment ? MAX_CATCHMENT : CA_UNMODIFIED;
max_c += _settings_game.station.catchment_increase;
TileArea ta(TileXY(max<int>(0, x - max_c), max<int>(0, y - max_c)), TileXY(min<int>(MapMaxX(), x + location.w + max_c), min<int>(MapMaxY(), y + location.h + max_c)));
TILE_AREA_LOOP(tile, ta) {
if (IsTileType(tile, MP_STATION)) seen_stations.insert(GetStationIndex(tile));
}
for (uint cy = min_y; cy < max_y; cy++) {
for (uint cx = min_x; cx < max_x; cx++) {
TileIndex cur_tile = TileXY(cx, cy);
if (!IsTileType(cur_tile, MP_STATION)) continue;
for (StationID stationid : seen_stations) {
Station *st = Station::GetIfValid(stationid);
if (st == NULL) continue; /* Waypoint */
Station *st = Station::GetByTile(cur_tile);
/* st can be NULL in case of waypoints */
if (st == NULL) continue;
/* Check if station is attached to an industry */
if (!_settings_game.station.serve_neutral_industries && st->industry != NULL) continue;
if (_settings_game.station.modified_catchment) {
int rad = st->GetCatchmentRadius();
int rad_x = cx - x;
int rad_y = cy - y;
if (rad_x < -rad || rad_x >= rad + location.w) continue;
if (rad_y < -rad || rad_y >= rad + location.h) continue;
/* Test if the tile is within the station's catchment */
TILE_AREA_LOOP(tile, location) {
if (st->TileIsInCatchment(tile)) {
stations->insert(st);
break;
}
/* Insert the station in the set. This will fail if it has
* already been added.
*/
stations->Include(st);
}
}
}
@@ -4074,9 +4119,7 @@ uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, Sourc
uint best_rating1 = 0; // rating of st1
uint best_rating2 = 0; // rating of st2
for (Station * const *st_iter = all_stations->Begin(); st_iter != all_stations->End(); ++st_iter) {
Station *st = *st_iter;
for (Station *st : *all_stations) {
/* Is the station reserved exclusively for somebody else? */
if (st->owner != OWNER_NONE && st->town->exclusive_counter > 0 && st->town->exclusivity != st->owner) continue;
@@ -4138,11 +4181,15 @@ void BuildOilRig(TileIndex tile)
}
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_tile(IsTileType(tile, MP_INDUSTRY), tile);
/* Mark industry as associated both ways */
st->industry = Industry::GetByTile(tile);
st->industry->neutral_station = st;
DeleteAnimatedTile(tile);
MakeOilrig(tile, st->index, GetWaterClass(tile));
@@ -4165,8 +4212,9 @@ void BuildOilRig(TileIndex tile)
st->rect.BeforeAddTile(tile, StationRect::ADD_FORCE);
st->UpdateVirtCoord();
_viewport_sign_kdtree.Insert(ViewportSignKdtreeItem::MakeStation(st->index));
st->RecomputeCatchment();
UpdateStationAcceptance(st, false);
st->RecomputeIndustriesNear();
ZoningMarkDirtyStationCoverageArea(st);
}
@@ -4189,7 +4237,7 @@ void DeleteOilRig(TileIndex tile)
st->rect.AfterRemoveTile(st, tile);
st->UpdateVirtCoord();
st->RecomputeIndustriesNear();
st->RecomputeCatchment();
if (!st->IsInUse()) delete st;
}