Merge branch 'master' into jgrpp-nrt
Merge trunk multiple docks implementation # Conflicts: # docs/landscape_grid.html # src/order_cmd.cpp # src/pathfinder/npf/npf.cpp # src/pathfinder/yapf/yapf_ship.cpp # src/rail_cmd.cpp # src/saveload/afterload.cpp # src/saveload/oldloader_sl.cpp # src/saveload/station_sl.cpp # src/script/api/script_order.cpp # src/ship_cmd.cpp # src/station.cpp # src/station_base.h # src/station_cmd.cpp # src/tunnelbridge_cmd.cpp
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
#include "../../ship.h"
|
||||
#include "../../roadstop_base.h"
|
||||
#include "../../infrastructure_func.h"
|
||||
#include "../../vehicle_func.h"
|
||||
#include "../pathfinder_func.h"
|
||||
#include "../pathfinder_type.h"
|
||||
#include "../follow_track.hpp"
|
||||
@@ -166,7 +167,7 @@ static int32 NPFCalcStationOrTileHeuristic(AyStar *as, AyStarNode *current, Open
|
||||
uint dist;
|
||||
AyStarUserData *user = (AyStarUserData *)as->user_data;
|
||||
|
||||
/* for stations, we are going to aim for the closest station tile */
|
||||
/* aim for the closest station tile */
|
||||
if (fstd->station_index != INVALID_STATION) {
|
||||
to = CalcClosestStationTile(fstd->station_index, from, fstd->station_type);
|
||||
}
|
||||
@@ -304,6 +305,15 @@ static void NPFMarkTile(TileIndex tile)
|
||||
}
|
||||
}
|
||||
|
||||
static Vehicle *CountShipProc(Vehicle *v, void *data)
|
||||
{
|
||||
uint *count = (uint *)data;
|
||||
/* Ignore other vehicles (aircraft) and ships inside depot. */
|
||||
if (v->type == VEH_SHIP && (v->vehstatus & VS_HIDDEN) == 0) (*count)++;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static int32 NPFWaterPathCost(AyStar *as, AyStarNode *current, OpenListNode *parent)
|
||||
{
|
||||
/* TileIndex tile = current->tile; */
|
||||
@@ -320,6 +330,13 @@ static int32 NPFWaterPathCost(AyStar *as, AyStarNode *current, OpenListNode *par
|
||||
cost += _settings_game.pf.npf.npf_water_curve_penalty;
|
||||
}
|
||||
|
||||
if (IsDockingTile(current->tile)) {
|
||||
/* Check docking tile for occupancy */
|
||||
uint count = 1;
|
||||
HasVehicleOnPos(current->tile, &count, &CountShipProc);
|
||||
cost += count * 3 * _trackdir_length[trackdir];
|
||||
}
|
||||
|
||||
/* @todo More penalties? */
|
||||
|
||||
return cost;
|
||||
@@ -562,16 +579,22 @@ static int32 NPFFindStationOrTile(const AyStar *as, const OpenListNode *current)
|
||||
const AyStarNode *node = ¤t->path.node;
|
||||
TileIndex tile = node->tile;
|
||||
|
||||
if (fstd->station_index == INVALID_STATION) {
|
||||
return (tile == fstd->dest_coords) ? AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
|
||||
if (fstd->station_index == INVALID_STATION && tile == fstd->dest_coords) return AYSTAR_FOUND_END_NODE;
|
||||
|
||||
if (fstd->v->type == VEH_SHIP) {
|
||||
/* Ships do not actually reach the destination station, so we check for a docking tile instead. */
|
||||
if (IsDockingTile(tile) && IsShipDestinationTile(tile, fstd->station_index)) return AYSTAR_FOUND_END_NODE;
|
||||
return AYSTAR_DONE;
|
||||
}
|
||||
|
||||
switch (fstd->v->type) {
|
||||
default: NOT_REACHED();
|
||||
case VEH_TRAIN: return (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index) ? AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
|
||||
case VEH_ROAD: return (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index && GetStationType(tile) == fstd->station_type && (fstd->not_articulated || IsDriveThroughStopTile(tile))) ? AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
|
||||
case VEH_SHIP: return Station::Get(fstd->station_index)->IsDockingTile(tile) ? AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
|
||||
if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index) {
|
||||
if (fstd->v->type == VEH_TRAIN) return AYSTAR_FOUND_END_NODE;
|
||||
|
||||
assert(fstd->v->type == VEH_ROAD);
|
||||
/* Only if it is a valid station *and* we can stop there */
|
||||
if (GetStationType(tile) == fstd->station_type && (fstd->not_articulated || IsDriveThroughStopTile(tile))) return AYSTAR_FOUND_END_NODE;
|
||||
}
|
||||
return AYSTAR_DONE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1116,12 +1139,22 @@ void InitializeNPF()
|
||||
|
||||
static void NPFFillWithOrderData(NPFFindStationOrTileData *fstd, const Vehicle *v, bool reserve_path = false)
|
||||
{
|
||||
/* Fill station_index for station orders, else only dest_coords. */
|
||||
if (v->current_order.IsType(OT_GOTO_STATION) || (v->type != VEH_SHIP && v->current_order.IsType(OT_GOTO_WAYPOINT))) {
|
||||
/* Ships don't really reach their stations, but the tile in front. So don't
|
||||
* save the station id for ships. For roadvehs we don't store it either,
|
||||
* because multistop depends on vehicles actually reaching the exact
|
||||
* dest_tile, not just any stop of that station.
|
||||
* So only for train orders to stations we fill fstd->station_index, for all
|
||||
* others only dest_coords */
|
||||
if (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_WAYPOINT)) {
|
||||
fstd->station_index = v->current_order.GetDestination();
|
||||
fstd->station_type = (v->type == VEH_SHIP) ? STATION_DOCK :
|
||||
(v->type == VEH_TRAIN) ? (v->current_order.IsType(OT_GOTO_STATION) ? STATION_RAIL : STATION_WAYPOINT) :
|
||||
(RoadVehicle::From(v)->IsBus() ? STATION_BUS : STATION_TRUCK);
|
||||
if (v->type == VEH_TRAIN) {
|
||||
fstd->station_type = v->current_order.IsType(OT_GOTO_STATION) ? STATION_RAIL : STATION_WAYPOINT;
|
||||
} else if (v->type == VEH_ROAD) {
|
||||
fstd->station_type = RoadVehicle::From(v)->IsBus() ? STATION_BUS : STATION_TRUCK;
|
||||
} else if (v->type == VEH_SHIP) {
|
||||
fstd->station_type = v->current_order.IsType(OT_GOTO_STATION) ? STATION_DOCK : STATION_BUOY;
|
||||
}
|
||||
|
||||
fstd->not_articulated = v->type == VEH_ROAD && !RoadVehicle::From(v)->HasArticulatedPart();
|
||||
/* Let's take the closest tile of the station as our target for vehicles */
|
||||
fstd->dest_coords = CalcClosestStationTile(fstd->station_index, v->tile, fstd->station_type);
|
||||
|
||||
@@ -14,7 +14,19 @@
|
||||
|
||||
/** Yapf Node for ships */
|
||||
template <class Tkey_>
|
||||
struct CYapfShipNodeT : CYapfNodeT<Tkey_, CYapfShipNodeT<Tkey_> > { };
|
||||
struct CYapfShipNodeT : CYapfNodeT<Tkey_, CYapfShipNodeT<Tkey_> > {
|
||||
typedef CYapfNodeT<Tkey_, CYapfShipNodeT<Tkey_> > base;
|
||||
|
||||
TileIndex m_segment_last_tile;
|
||||
Trackdir m_segment_last_td;
|
||||
|
||||
void Set(CYapfShipNodeT *parent, TileIndex tile, Trackdir td, bool is_choice)
|
||||
{
|
||||
base::Set(parent, tile, td, is_choice);
|
||||
m_segment_last_tile = tile;
|
||||
m_segment_last_td = td;
|
||||
}
|
||||
};
|
||||
|
||||
/* now define two major node types (that differ by key type) */
|
||||
typedef CYapfShipNodeT<CYapfNodeKeyExitDir> CYapfShipNodeExitDir;
|
||||
|
||||
@@ -11,12 +11,96 @@
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "../../ship.h"
|
||||
#include "../../industry.h"
|
||||
#include "../../vehicle_func.h"
|
||||
|
||||
#include "yapf.hpp"
|
||||
#include "yapf_node_ship.hpp"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
template <class Types>
|
||||
class CYapfDestinationTileWaterT
|
||||
{
|
||||
public:
|
||||
typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class)
|
||||
typedef typename Types::TrackFollower TrackFollower;
|
||||
typedef typename Types::NodeList::Titem Node; ///< this will be our node type
|
||||
typedef typename Node::Key Key; ///< key to hash tables
|
||||
|
||||
protected:
|
||||
TileIndex m_destTile;
|
||||
TrackdirBits m_destTrackdirs;
|
||||
StationID m_destStation;
|
||||
|
||||
public:
|
||||
void SetDestination(const Ship *v)
|
||||
{
|
||||
if (v->current_order.IsType(OT_GOTO_STATION)) {
|
||||
m_destStation = v->current_order.GetDestination();
|
||||
m_destTile = CalcClosestStationTile(m_destStation, v->tile, STATION_DOCK);
|
||||
m_destTrackdirs = INVALID_TRACKDIR_BIT;
|
||||
} else {
|
||||
m_destStation = INVALID_STATION;
|
||||
m_destTile = v->dest_tile;
|
||||
m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0));
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/** to access inherited path finder */
|
||||
inline Tpf& Yapf()
|
||||
{
|
||||
return *static_cast<Tpf*>(this);
|
||||
}
|
||||
|
||||
public:
|
||||
/** Called by YAPF to detect if node ends in the desired destination */
|
||||
inline bool PfDetectDestination(Node& n)
|
||||
{
|
||||
return PfDetectDestinationTile(n.m_segment_last_tile, n.m_segment_last_td);
|
||||
}
|
||||
|
||||
inline bool PfDetectDestinationTile(TileIndex tile, Trackdir trackdir)
|
||||
{
|
||||
if (m_destStation != INVALID_STATION) {
|
||||
return IsDockingTile(tile) && IsShipDestinationTile(tile, m_destStation);
|
||||
}
|
||||
|
||||
return tile == m_destTile && ((m_destTrackdirs & TrackdirToTrackdirBits(trackdir)) != TRACKDIR_BIT_NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by YAPF to calculate cost estimate. Calculates distance to the destination
|
||||
* adds it to the actual cost from origin and stores the sum to the Node::m_estimate
|
||||
*/
|
||||
inline bool PfCalcEstimate(Node& n)
|
||||
{
|
||||
static const int dg_dir_to_x_offs[] = {-1, 0, 1, 0};
|
||||
static const int dg_dir_to_y_offs[] = {0, 1, 0, -1};
|
||||
if (PfDetectDestination(n)) {
|
||||
n.m_estimate = n.m_cost;
|
||||
return true;
|
||||
}
|
||||
|
||||
TileIndex tile = n.m_segment_last_tile;
|
||||
DiagDirection exitdir = TrackdirToExitdir(n.m_segment_last_td);
|
||||
int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir];
|
||||
int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir];
|
||||
int x2 = 2 * TileX(m_destTile);
|
||||
int y2 = 2 * TileY(m_destTile);
|
||||
int dx = abs(x1 - x2);
|
||||
int dy = abs(y1 - y2);
|
||||
int dmin = min(dx, dy);
|
||||
int dxy = abs(dx - dy);
|
||||
int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2);
|
||||
n.m_estimate = n.m_cost + d;
|
||||
assert(n.m_estimate >= n.m_parent->m_estimate);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Node Follower module of YAPF for ships */
|
||||
template <class Types>
|
||||
class CYapfFollowShipT
|
||||
@@ -90,12 +174,16 @@ public:
|
||||
if (pNode != nullptr) {
|
||||
uint steps = 0;
|
||||
for (Node *n = pNode; n->m_parent != nullptr; n = n->m_parent) steps++;
|
||||
uint skip = 0;
|
||||
if (path_found) skip = YAPF_SHIP_PATH_CACHE_LENGTH / 2;
|
||||
|
||||
/* walk through the path back to the origin */
|
||||
Node *pPrevNode = nullptr;
|
||||
while (pNode->m_parent != nullptr) {
|
||||
steps--;
|
||||
if (steps > 0 && steps < YAPF_SHIP_PATH_CACHE_LENGTH) {
|
||||
/* Skip tiles at end of path near destination. */
|
||||
if (skip > 0) skip--;
|
||||
if (skip == 0 && steps > 0 && steps < YAPF_SHIP_PATH_CACHE_LENGTH) {
|
||||
path_cache.push_front(pNode->GetTrackdir());
|
||||
}
|
||||
pPrevNode = pNode;
|
||||
@@ -178,6 +266,15 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Vehicle *CountShipProc(Vehicle *v, void *data)
|
||||
{
|
||||
uint *count = (uint *)data;
|
||||
/* Ignore other vehicles (aircraft) and ships inside depot. */
|
||||
if (v->type == VEH_SHIP && (v->vehstatus & VS_HIDDEN) == 0) (*count)++;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by YAPF to calculate the cost from the origin to the given node.
|
||||
* Calculates only the cost of given node, adds it to the parent node cost
|
||||
@@ -190,6 +287,13 @@ public:
|
||||
/* additional penalty for curves */
|
||||
c += CurveCost(n.m_parent->GetTrackdir(), n.GetTrackdir());
|
||||
|
||||
if (IsDockingTile(n.GetTile())) {
|
||||
/* Check docking tile for occupancy */
|
||||
uint count = 1;
|
||||
HasVehicleOnPos(n.GetTile(), &count, &CountShipProc);
|
||||
c += count * 3 * YAPF_TILE_LENGTH;
|
||||
}
|
||||
|
||||
/* Skipped tile cost for aqueducts. */
|
||||
c += YAPF_TILE_LENGTH * tf->m_tiles_skipped;
|
||||
|
||||
@@ -204,80 +308,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/** YAPF destination provider for ships */
|
||||
template <class Types>
|
||||
class CYapfDestinationShipT
|
||||
{
|
||||
public:
|
||||
typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class)
|
||||
typedef typename Types::NodeList::Titem Node; ///< this will be our node type
|
||||
typedef typename Node::Key Key; ///< key to hash tables
|
||||
|
||||
protected:
|
||||
StationID m_destStation; ///< destinatin station
|
||||
TileIndex m_destTile; ///< destination tile
|
||||
|
||||
public:
|
||||
/** set the destination */
|
||||
void SetDestination(const Ship *v)
|
||||
{
|
||||
if (v->current_order.IsType(OT_GOTO_STATION)) {
|
||||
m_destStation = v->current_order.GetDestination();
|
||||
m_destTile = CalcClosestStationTile(m_destStation, v->tile, STATION_DOCK);
|
||||
} else {
|
||||
m_destStation = INVALID_STATION;
|
||||
m_destTile = v->dest_tile;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/** to access inherited path finder */
|
||||
Tpf& Yapf()
|
||||
{
|
||||
return *static_cast<Tpf *>(this);
|
||||
}
|
||||
|
||||
public:
|
||||
/** Called by YAPF to detect if node ends in the desired destination */
|
||||
inline bool PfDetectDestination(Node &n)
|
||||
{
|
||||
if (m_destStation == INVALID_STATION) {
|
||||
return n.m_key.m_tile == m_destTile;
|
||||
} else {
|
||||
return Station::Get(m_destStation)->IsDockingTile(n.m_key.m_tile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by YAPF to calculate cost estimate. Calculates distance to the destination
|
||||
* adds it to the actual cost from origin and stores the sum to the Node::m_estimate
|
||||
*/
|
||||
inline bool PfCalcEstimate(Node &n)
|
||||
{
|
||||
static const int dg_dir_to_x_offs[] = {-1, 0, 1, 0};
|
||||
static const int dg_dir_to_y_offs[] = {0, 1, 0, -1};
|
||||
if (PfDetectDestination(n)) {
|
||||
n.m_estimate = n.m_cost;
|
||||
return true;
|
||||
}
|
||||
|
||||
TileIndex tile = n.GetTile();
|
||||
DiagDirection exitdir = TrackdirToExitdir(n.GetTrackdir());
|
||||
int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir];
|
||||
int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir];
|
||||
int x2 = 2 * TileX(m_destTile);
|
||||
int y2 = 2 * TileY(m_destTile);
|
||||
int dx = abs(x1 - x2);
|
||||
int dy = abs(y1 - y2);
|
||||
int dmin = min(dx, dy);
|
||||
int dxy = abs(dx - dy);
|
||||
int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2);
|
||||
n.m_estimate = n.m_cost + d;
|
||||
assert(n.m_estimate >= n.m_parent->m_estimate);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Config struct of YAPF for ships.
|
||||
* Defines all 6 base YAPF modules as classes providing services for CYapfBaseT.
|
||||
@@ -299,7 +329,7 @@ struct CYapfShip_TypesT
|
||||
typedef CYapfBaseT<Types> PfBase; // base pathfinder class
|
||||
typedef CYapfFollowShipT<Types> PfFollow; // node follower
|
||||
typedef CYapfOriginTileT<Types> PfOrigin; // origin provider
|
||||
typedef CYapfDestinationShipT<Types> PfDestination; // destination/distance provider
|
||||
typedef CYapfDestinationTileWaterT<Types> PfDestination; // destination/distance provider
|
||||
typedef CYapfSegmentCostCacheNoneT<Types> PfCache; // segment cost cache provider
|
||||
typedef CYapfCostShipT<Types> PfCost; // cost provider
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user