mirror of https://github.com/OpenTTD/OpenTTD.git
Feature: Multi-tile docks and docking points.
This commit is contained in:
parent
f1c3915341
commit
f538179878
|
@ -249,6 +249,7 @@
|
||||||
<td valign=top nowrap> </td>
|
<td valign=top nowrap> </td>
|
||||||
<td>
|
<td>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>m1 bit 7: Ship docking tile status (for half-tile with water)</li>
|
||||||
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a> of the tile</li>
|
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a> of the tile</li>
|
||||||
<li>m2: see signals</li>
|
<li>m2: see signals</li>
|
||||||
<li>m3 bits 7..4: see signals</li>
|
<li>m3 bits 7..4: see signals</li>
|
||||||
|
@ -871,6 +872,7 @@
|
||||||
<td valign=top nowrap> </td>
|
<td valign=top nowrap> </td>
|
||||||
<td>
|
<td>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>m1 bit 7: Ship docking tile status (for buoys)</li>
|
||||||
<li>m1 bits 6..5: water class for buoys, water part of docks and for airport tiles</li>
|
<li>m1 bits 6..5: water class for buoys, water part of docks and for airport tiles</li>
|
||||||
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a> of the station</li>
|
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a> of the station</li>
|
||||||
<li>m2: index into the array of stations</li>
|
<li>m2: index into the array of stations</li>
|
||||||
|
@ -1008,6 +1010,7 @@
|
||||||
<td valign=top nowrap> </td>
|
<td valign=top nowrap> </td>
|
||||||
<td>
|
<td>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>m1 bit 7: Ship docking tile status</li>
|
||||||
<li>m1 bits 6..5 : Water class (sea, canal or river)
|
<li>m1 bits 6..5 : Water class (sea, canal or river)
|
||||||
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a> (for sea, rivers, and coasts normally <tt>11</tt>)</li>
|
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a> (for sea, rivers, and coasts normally <tt>11</tt>)</li>
|
||||||
<li>m2: Depot index (for depots only)</li>
|
<li>m2: Depot index (for depots only)</li>
|
||||||
|
@ -1459,6 +1462,7 @@
|
||||||
<td valign=top nowrap> </td>
|
<td valign=top nowrap> </td>
|
||||||
<td>
|
<td>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>m1 bit 7: Ship docking tile status (for aqueducts)</li>
|
||||||
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a></li>
|
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a></li>
|
||||||
<li>m3 bits 7..4: <a href="#OwnershipInfo">owner</a> of tram</li>
|
<li>m3 bits 7..4: <a href="#OwnershipInfo">owner</a> of tram</li>
|
||||||
<li>m4: <a href="#RoadType">Roadtype</a></li>
|
<li>m4: <a href="#RoadType">Roadtype</a></li>
|
||||||
|
|
|
@ -100,7 +100,7 @@ the array so you can quickly see what is used and what is not.
|
||||||
<td class="caption">rail</td>
|
<td class="caption">rail</td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits"><span class="free">OOO</span>X XXXX</td>
|
<td class="bits">X<span class="free">OO</span>X XXXX</td>
|
||||||
<td class="bits"><span class="free">OOOO</span> XXXX <span class="free">OOOO OOOO</span></td>
|
<td class="bits"><span class="free">OOOO</span> XXXX <span class="free">OOOO OOOO</span></td>
|
||||||
<td class="bits"><span class="free">OOOO OOOO</span></td>
|
<td class="bits"><span class="free">OOOO OOOO</span></td>
|
||||||
<td class="bits"><span class="free">OOOO</span> XXXX</td>
|
<td class="bits"><span class="free">OOOO</span> XXXX</td>
|
||||||
|
@ -208,7 +208,7 @@ the array so you can quickly see what is used and what is not.
|
||||||
<td class="caption">rail station</td>
|
<td class="caption">rail station</td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits"><span class="free">O</span>XXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits">XXXX XXXX XXXX XXXX</td>
|
<td class="bits">XXXX XXXX XXXX XXXX</td>
|
||||||
<td class="bits">XXXX <span class="free">OOOO</span></td>
|
<td class="bits">XXXX <span class="free">OOOO</span></td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
|
@ -300,7 +300,7 @@ the array so you can quickly see what is used and what is not.
|
||||||
<td class="caption">sea, shore</td>
|
<td class="caption">sea, shore</td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits"><span class="free">O</span>XXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
|
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
|
||||||
<td class="bits"><span class="free">OOOO OOOO</span></td>
|
<td class="bits"><span class="free">OOOO OOOO</span></td>
|
||||||
<td class="bits"><span class="free">OOOO OOOO</span></td>
|
<td class="bits"><span class="free">OOOO OOOO</span></td>
|
||||||
|
@ -354,7 +354,7 @@ the array so you can quickly see what is used and what is not.
|
||||||
<td class="caption">tunnel entrance</td>
|
<td class="caption">tunnel entrance</td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits"><span class="free">OOO</span>X XXXX</td>
|
<td class="bits">X<span class="free">OO</span>X XXXX</td>
|
||||||
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
|
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
|
||||||
<td class="bits">XXXX <span class="free">OOOO</span></td>
|
<td class="bits">XXXX <span class="free">OOOO</span></td>
|
||||||
<td class="bits"><span class="free">OO</span>XX XXXX</td>
|
<td class="bits"><span class="free">OO</span>XX XXXX</td>
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "rail_map.h"
|
#include "rail_map.h"
|
||||||
#include "road_map.h"
|
#include "road_map.h"
|
||||||
#include "bridge.h"
|
#include "bridge.h"
|
||||||
|
#include "water_map.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if this is a bridge, instead of a tunnel
|
* Checks if this is a bridge, instead of a tunnel
|
||||||
|
@ -130,6 +131,7 @@ static inline void MakeBridgeRamp(TileIndex t, Owner o, BridgeType bridgetype, D
|
||||||
{
|
{
|
||||||
SetTileType(t, MP_TUNNELBRIDGE);
|
SetTileType(t, MP_TUNNELBRIDGE);
|
||||||
SetTileOwner(t, o);
|
SetTileOwner(t, o);
|
||||||
|
SetDockingTile(t, false);
|
||||||
_m[t].m2 = 0;
|
_m[t].m2 = 0;
|
||||||
_m[t].m3 = 0;
|
_m[t].m3 = 0;
|
||||||
_m[t].m4 = INVALID_ROADTYPE;
|
_m[t].m4 = INVALID_ROADTYPE;
|
||||||
|
|
|
@ -155,6 +155,13 @@ Industry::~Industry()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->neutral_station != nullptr) {
|
||||||
|
/* Remove possible docking tiles */
|
||||||
|
TILE_AREA_LOOP(tile_cur, this->location) {
|
||||||
|
ClearDockingTilesCheckingNeighbours(tile_cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (GetIndustrySpec(this->type)->behaviour & INDUSTRYBEH_PLANT_FIELDS) {
|
if (GetIndustrySpec(this->type)->behaviour & INDUSTRYBEH_PLANT_FIELDS) {
|
||||||
TileArea ta = TileArea(this->location.tile, 0, 0).Expand(21);
|
TileArea ta = TileArea(this->location.tile, 0, 0).Expand(21);
|
||||||
|
|
||||||
|
|
|
@ -2198,7 +2198,7 @@ bool ProcessOrders(Vehicle *v)
|
||||||
|
|
||||||
/* If it is unchanged, keep it. */
|
/* If it is unchanged, keep it. */
|
||||||
if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
|
if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
|
||||||
(v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->dock_tile != INVALID_TILE)) {
|
(v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->ship_station.tile != INVALID_TILE > 0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -165,8 +165,8 @@ static int32 NPFCalcStationOrTileHeuristic(AyStar *as, AyStarNode *current, Open
|
||||||
uint dist;
|
uint dist;
|
||||||
AyStarUserData *user = (AyStarUserData *)as->user_data;
|
AyStarUserData *user = (AyStarUserData *)as->user_data;
|
||||||
|
|
||||||
/* for train-stations, we are going to aim for the closest station tile */
|
/* aim for the closest station tile */
|
||||||
if (user->type != TRANSPORT_WATER && fstd->station_index != INVALID_STATION) {
|
if (fstd->station_index != INVALID_STATION) {
|
||||||
to = CalcClosestStationTile(fstd->station_index, from, fstd->station_type);
|
to = CalcClosestStationTile(fstd->station_index, from, fstd->station_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,6 +563,12 @@ static int32 NPFFindStationOrTile(const AyStar *as, const OpenListNode *current)
|
||||||
|
|
||||||
if (fstd->station_index == INVALID_STATION && tile == fstd->dest_coords) return AYSTAR_FOUND_END_NODE;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index) {
|
if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index) {
|
||||||
if (fstd->v->type == VEH_TRAIN) return AYSTAR_FOUND_END_NODE;
|
if (fstd->v->type == VEH_TRAIN) return AYSTAR_FOUND_END_NODE;
|
||||||
|
|
||||||
|
@ -1111,10 +1117,16 @@ static void NPFFillWithOrderData(NPFFindStationOrTileData *fstd, const Vehicle *
|
||||||
* dest_tile, not just any stop of that station.
|
* dest_tile, not just any stop of that station.
|
||||||
* So only for train orders to stations we fill fstd->station_index, for all
|
* So only for train orders to stations we fill fstd->station_index, for all
|
||||||
* others only dest_coords */
|
* others only dest_coords */
|
||||||
if (v->type != VEH_SHIP && (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_WAYPOINT))) {
|
if (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_WAYPOINT)) {
|
||||||
assert(v->IsGroundVehicle());
|
|
||||||
fstd->station_index = v->current_order.GetDestination();
|
fstd->station_index = v->current_order.GetDestination();
|
||||||
fstd->station_type = (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();
|
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 */
|
/* 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);
|
fstd->dest_coords = CalcClosestStationTile(fstd->station_index, v->tile, fstd->station_type);
|
||||||
|
|
|
@ -14,7 +14,19 @@
|
||||||
|
|
||||||
/** Yapf Node for ships */
|
/** Yapf Node for ships */
|
||||||
template <class Tkey_>
|
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) */
|
/* now define two major node types (that differ by key type) */
|
||||||
typedef CYapfShipNodeT<CYapfNodeKeyExitDir> CYapfShipNodeExitDir;
|
typedef CYapfShipNodeT<CYapfNodeKeyExitDir> CYapfShipNodeExitDir;
|
||||||
|
|
|
@ -11,12 +11,95 @@
|
||||||
|
|
||||||
#include "../../stdafx.h"
|
#include "../../stdafx.h"
|
||||||
#include "../../ship.h"
|
#include "../../ship.h"
|
||||||
|
#include "../../industry.h"
|
||||||
|
|
||||||
#include "yapf.hpp"
|
#include "yapf.hpp"
|
||||||
#include "yapf_node_ship.hpp"
|
#include "yapf_node_ship.hpp"
|
||||||
|
|
||||||
#include "../../safeguards.h"
|
#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 */
|
/** Node Follower module of YAPF for ships */
|
||||||
template <class Types>
|
template <class Types>
|
||||||
class CYapfFollowShipT
|
class CYapfFollowShipT
|
||||||
|
@ -75,14 +158,12 @@ public:
|
||||||
|
|
||||||
/* convert origin trackdir to TrackdirBits */
|
/* convert origin trackdir to TrackdirBits */
|
||||||
TrackdirBits trackdirs = TrackdirToTrackdirBits(trackdir);
|
TrackdirBits trackdirs = TrackdirToTrackdirBits(trackdir);
|
||||||
/* get available trackdirs on the destination tile */
|
|
||||||
TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0));
|
|
||||||
|
|
||||||
/* create pathfinder instance */
|
/* create pathfinder instance */
|
||||||
Tpf pf;
|
Tpf pf;
|
||||||
/* set origin and destination nodes */
|
/* set origin and destination nodes */
|
||||||
pf.SetOrigin(src_tile, trackdirs);
|
pf.SetOrigin(src_tile, trackdirs);
|
||||||
pf.SetDestination(v->dest_tile, dest_trackdirs);
|
pf.SetDestination(v);
|
||||||
/* find best path */
|
/* find best path */
|
||||||
path_found = pf.FindPath(v);
|
path_found = pf.FindPath(v);
|
||||||
|
|
||||||
|
@ -124,14 +205,11 @@ public:
|
||||||
*/
|
*/
|
||||||
static bool CheckShipReverse(const Ship *v, TileIndex tile, Trackdir td1, Trackdir td2)
|
static bool CheckShipReverse(const Ship *v, TileIndex tile, Trackdir td1, Trackdir td2)
|
||||||
{
|
{
|
||||||
/* get available trackdirs on the destination tile */
|
|
||||||
TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0));
|
|
||||||
|
|
||||||
/* create pathfinder instance */
|
/* create pathfinder instance */
|
||||||
Tpf pf;
|
Tpf pf;
|
||||||
/* set origin and destination nodes */
|
/* set origin and destination nodes */
|
||||||
pf.SetOrigin(tile, TrackdirToTrackdirBits(td1) | TrackdirToTrackdirBits(td2));
|
pf.SetOrigin(tile, TrackdirToTrackdirBits(td1) | TrackdirToTrackdirBits(td2));
|
||||||
pf.SetDestination(v->dest_tile, dest_trackdirs);
|
pf.SetDestination(v);
|
||||||
/* find best path */
|
/* find best path */
|
||||||
if (!pf.FindPath(v)) return false;
|
if (!pf.FindPath(v)) return false;
|
||||||
|
|
||||||
|
@ -230,7 +308,7 @@ struct CYapfShip_TypesT
|
||||||
typedef CYapfBaseT<Types> PfBase; // base pathfinder class
|
typedef CYapfBaseT<Types> PfBase; // base pathfinder class
|
||||||
typedef CYapfFollowShipT<Types> PfFollow; // node follower
|
typedef CYapfFollowShipT<Types> PfFollow; // node follower
|
||||||
typedef CYapfOriginTileT<Types> PfOrigin; // origin provider
|
typedef CYapfOriginTileT<Types> PfOrigin; // origin provider
|
||||||
typedef CYapfDestinationTileT<Types> PfDestination; // destination/distance provider
|
typedef CYapfDestinationTileWaterT<Types> PfDestination; // destination/distance provider
|
||||||
typedef CYapfSegmentCostCacheNoneT<Types> PfCache; // segment cost cache provider
|
typedef CYapfSegmentCostCacheNoneT<Types> PfCache; // segment cost cache provider
|
||||||
typedef CYapfCostShipT<Types> PfCost; // cost provider
|
typedef CYapfCostShipT<Types> PfCost; // cost provider
|
||||||
};
|
};
|
||||||
|
|
|
@ -570,6 +570,7 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||||
default: {
|
default: {
|
||||||
/* Will there be flat water on the lower halftile? */
|
/* Will there be flat water on the lower halftile? */
|
||||||
bool water_ground = IsTileType(tile, MP_WATER) && IsSlopeWithOneCornerRaised(tileh);
|
bool water_ground = IsTileType(tile, MP_WATER) && IsSlopeWithOneCornerRaised(tileh);
|
||||||
|
bool docking = IsPossibleDockingTile(tile) && IsDockingTile(tile);
|
||||||
|
|
||||||
CommandCost ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile);
|
CommandCost ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile);
|
||||||
if (ret.Failed()) return ret;
|
if (ret.Failed()) return ret;
|
||||||
|
@ -586,7 +587,10 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||||
|
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
MakeRailNormal(tile, _current_company, trackbit, railtype);
|
MakeRailNormal(tile, _current_company, trackbit, railtype);
|
||||||
if (water_ground) SetRailGroundType(tile, RAIL_GROUND_WATER);
|
if (water_ground) {
|
||||||
|
SetRailGroundType(tile, RAIL_GROUND_WATER);
|
||||||
|
SetDockingTile(tile, docking);
|
||||||
|
}
|
||||||
Company::Get(_current_company)->infrastructure.rail[railtype]++;
|
Company::Get(_current_company)->infrastructure.rail[railtype]++;
|
||||||
DirtyCompanyInfrastructureWindows(_current_company);
|
DirtyCompanyInfrastructureWindows(_current_company);
|
||||||
}
|
}
|
||||||
|
@ -708,7 +712,9 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||||
Slope tileh = GetTileSlope(tile);
|
Slope tileh = GetTileSlope(tile);
|
||||||
/* If there is flat water on the lower halftile, convert the tile to shore so the water remains */
|
/* If there is flat water on the lower halftile, convert the tile to shore so the water remains */
|
||||||
if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh)) {
|
if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh)) {
|
||||||
|
bool docking = IsDockingTile(tile);
|
||||||
MakeShore(tile);
|
MakeShore(tile);
|
||||||
|
SetDockingTile(tile, docking);
|
||||||
} else {
|
} else {
|
||||||
DoClearSquare(tile);
|
DoClearSquare(tile);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "signal_func.h"
|
#include "signal_func.h"
|
||||||
#include "track_func.h"
|
#include "track_func.h"
|
||||||
#include "tile_map.h"
|
#include "tile_map.h"
|
||||||
|
#include "water_map.h"
|
||||||
#include "signal_type.h"
|
#include "signal_type.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -521,6 +522,7 @@ static inline void MakeRailNormal(TileIndex t, Owner o, TrackBits b, RailType r)
|
||||||
{
|
{
|
||||||
SetTileType(t, MP_RAILWAY);
|
SetTileType(t, MP_RAILWAY);
|
||||||
SetTileOwner(t, o);
|
SetTileOwner(t, o);
|
||||||
|
SetDockingTile(t, false);
|
||||||
_m[t].m2 = 0;
|
_m[t].m2 = 0;
|
||||||
_m[t].m3 = 0;
|
_m[t].m3 = 0;
|
||||||
_m[t].m4 = 0;
|
_m[t].m4 = 0;
|
||||||
|
@ -535,6 +537,7 @@ static inline void MakeRailDepot(TileIndex t, Owner o, DepotID did, DiagDirectio
|
||||||
{
|
{
|
||||||
SetTileType(t, MP_RAILWAY);
|
SetTileType(t, MP_RAILWAY);
|
||||||
SetTileOwner(t, o);
|
SetTileOwner(t, o);
|
||||||
|
SetDockingTile(t, false);
|
||||||
_m[t].m2 = did;
|
_m[t].m2 = did;
|
||||||
_m[t].m3 = 0;
|
_m[t].m3 = 0;
|
||||||
_m[t].m4 = 0;
|
_m[t].m4 = 0;
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
#include "../error.h"
|
#include "../error.h"
|
||||||
#include "../disaster_vehicle.h"
|
#include "../disaster_vehicle.h"
|
||||||
#include "../ship.h"
|
#include "../ship.h"
|
||||||
|
#include "../water.h"
|
||||||
|
|
||||||
|
|
||||||
#include "saveload_internal.h"
|
#include "saveload_internal.h"
|
||||||
|
@ -675,7 +676,6 @@ bool AfterLoadGame()
|
||||||
Station *st;
|
Station *st;
|
||||||
FOR_ALL_STATIONS(st) {
|
FOR_ALL_STATIONS(st) {
|
||||||
if (st->airport.tile == 0) st->airport.tile = INVALID_TILE;
|
if (st->airport.tile == 0) st->airport.tile = INVALID_TILE;
|
||||||
if (st->dock_tile == 0) st->dock_tile = INVALID_TILE;
|
|
||||||
if (st->train_station.tile == 0) st->train_station.tile = INVALID_TILE;
|
if (st->train_station.tile == 0) st->train_station.tile = INVALID_TILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3177,6 +3177,27 @@ bool AfterLoadGame()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update structures for multitile docks */
|
||||||
|
if (IsSavegameVersionBefore(SLV_MULTITILE_DOCKS)) {
|
||||||
|
for (TileIndex t = 0; t < map_size; t++) {
|
||||||
|
/* Clear docking tile flag from relevant tiles as it
|
||||||
|
* was not previously cleared. */
|
||||||
|
if (IsTileType(t, MP_WATER) || IsTileType(t, MP_RAILWAY) || IsTileType(t, MP_STATION) || IsTileType(t, MP_TUNNELBRIDGE)) {
|
||||||
|
SetDockingTile(t, false);
|
||||||
|
}
|
||||||
|
/* Add docks and oilrigs to Station::ship_station. */
|
||||||
|
if (IsTileType(t, MP_STATION)) {
|
||||||
|
if (IsDock(t) || IsOilRig(t)) Station::GetByTile(t)->ship_station.Add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scan for docking tiles */
|
||||||
|
Station *st;
|
||||||
|
FOR_ALL_STATIONS(st) {
|
||||||
|
if (st->ship_station.tile != INVALID_TILE) UpdateStationDockingTiles(st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Compute station catchment areas. This is needed here in case UpdateStationAcceptance is called below. */
|
/* Compute station catchment areas. This is needed here in case UpdateStationAcceptance is called below. */
|
||||||
Station::RecomputeCatchmentForAll();
|
Station::RecomputeCatchmentForAll();
|
||||||
|
|
||||||
|
|
|
@ -725,7 +725,7 @@ static const OldChunks station_chunk[] = {
|
||||||
OCL_NULL( 4 ), ///< bus/lorry tile
|
OCL_NULL( 4 ), ///< bus/lorry tile
|
||||||
OCL_SVAR( OC_TILE, Station, train_station.tile ),
|
OCL_SVAR( OC_TILE, Station, train_station.tile ),
|
||||||
OCL_SVAR( OC_TILE, Station, airport.tile ),
|
OCL_SVAR( OC_TILE, Station, airport.tile ),
|
||||||
OCL_SVAR( OC_TILE, Station, dock_tile ),
|
OCL_NULL( 4 ), ///< dock tile
|
||||||
OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Station, train_station.w ),
|
OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Station, train_station.w ),
|
||||||
|
|
||||||
OCL_NULL( 1 ), ///< sort-index, no longer in use
|
OCL_NULL( 1 ), ///< sort-index, no longer in use
|
||||||
|
|
|
@ -301,6 +301,7 @@ enum SaveLoadVersion : uint16 {
|
||||||
SLV_ROAD_TYPES, ///< 214 PR#6811 NewGRF road types.
|
SLV_ROAD_TYPES, ///< 214 PR#6811 NewGRF road types.
|
||||||
|
|
||||||
SLV_SCRIPT_MEMLIMIT, ///< 215 PR#7516 Limit on AI/GS memory consumption.
|
SLV_SCRIPT_MEMLIMIT, ///< 215 PR#7516 Limit on AI/GS memory consumption.
|
||||||
|
SLV_MULTITILE_DOCKS, ///< 216 PR#7380 Multiple docks per station.
|
||||||
|
|
||||||
SL_MAX_VERSION, ///< Highest possible saveload version
|
SL_MAX_VERSION, ///< Highest possible saveload version
|
||||||
};
|
};
|
||||||
|
|
|
@ -174,8 +174,8 @@ static const SaveLoad _old_station_desc[] = {
|
||||||
SLE_CONDVAR(Station, train_station.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
|
SLE_CONDVAR(Station, train_station.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
|
||||||
SLE_CONDVAR(Station, airport.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
|
SLE_CONDVAR(Station, airport.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
|
||||||
SLE_CONDVAR(Station, airport.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
|
SLE_CONDVAR(Station, airport.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
|
||||||
SLE_CONDVAR(Station, dock_tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
|
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6),
|
||||||
SLE_CONDVAR(Station, dock_tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
|
SLE_CONDNULL(4, SLV_6, SLV_MULTITILE_DOCKS),
|
||||||
SLE_REF(Station, town, REF_TOWN),
|
SLE_REF(Station, town, REF_TOWN),
|
||||||
SLE_VAR(Station, train_station.w, SLE_FILE_U8 | SLE_VAR_U16),
|
SLE_VAR(Station, train_station.w, SLE_FILE_U8 | SLE_VAR_U16),
|
||||||
SLE_CONDVAR(Station, train_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_2, SL_MAX_VERSION),
|
SLE_CONDVAR(Station, train_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_2, SL_MAX_VERSION),
|
||||||
|
@ -423,7 +423,13 @@ static const SaveLoad _station_desc[] = {
|
||||||
|
|
||||||
SLE_REF(Station, bus_stops, REF_ROADSTOPS),
|
SLE_REF(Station, bus_stops, REF_ROADSTOPS),
|
||||||
SLE_REF(Station, truck_stops, REF_ROADSTOPS),
|
SLE_REF(Station, truck_stops, REF_ROADSTOPS),
|
||||||
SLE_VAR(Station, dock_tile, SLE_UINT32),
|
SLE_CONDNULL(4, SL_MIN_VERSION, SLV_MULTITILE_DOCKS),
|
||||||
|
SLE_CONDVAR(Station, ship_station.tile, SLE_UINT32, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
|
||||||
|
SLE_CONDVAR(Station, ship_station.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
|
||||||
|
SLE_CONDVAR(Station, ship_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
|
||||||
|
SLE_CONDVAR(Station, docking_station.tile, SLE_UINT32, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
|
||||||
|
SLE_CONDVAR(Station, docking_station.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
|
||||||
|
SLE_CONDVAR(Station, docking_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
|
||||||
SLE_VAR(Station, airport.tile, SLE_UINT32),
|
SLE_VAR(Station, airport.tile, SLE_UINT32),
|
||||||
SLE_CONDVAR(Station, airport.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_140, SL_MAX_VERSION),
|
SLE_CONDVAR(Station, airport.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_140, SL_MAX_VERSION),
|
||||||
SLE_CONDVAR(Station, airport.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_140, SL_MAX_VERSION),
|
SLE_CONDVAR(Station, airport.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_140, SL_MAX_VERSION),
|
||||||
|
|
|
@ -261,8 +261,10 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
|
||||||
TILE_AREA_LOOP(t, st->train_station) {
|
TILE_AREA_LOOP(t, st->train_station) {
|
||||||
if (st->TileBelongsToRailStation(t)) return t;
|
if (st->TileBelongsToRailStation(t)) return t;
|
||||||
}
|
}
|
||||||
} else if (st->dock_tile != INVALID_TILE) {
|
} else if (st->ship_station.tile != INVALID_TILE) {
|
||||||
return st->dock_tile;
|
TILE_AREA_LOOP(t, st->ship_station) {
|
||||||
|
if (IsDockTile(t) && GetStationIndex(t) == st->index) return t;
|
||||||
|
}
|
||||||
} else if (st->bus_stops != nullptr) {
|
} else if (st->bus_stops != nullptr) {
|
||||||
return st->bus_stops->xy;
|
return st->bus_stops->xy;
|
||||||
} else if (st->truck_stops != nullptr) {
|
} else if (st->truck_stops != nullptr) {
|
||||||
|
|
|
@ -57,6 +57,8 @@ struct Ship FINAL : public SpecializedVehicle<Ship, VEH_SHIP> {
|
||||||
void SetDestTile(TileIndex tile);
|
void SetDestTile(TileIndex tile);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool IsShipDestinationTile(TileIndex tile, StationID station);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate over all ships.
|
* Iterate over all ships.
|
||||||
* @param var The variable used for iteration.
|
* @param var The variable used for iteration.
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
#include "tunnelbridge_map.h"
|
#include "tunnelbridge_map.h"
|
||||||
#include "zoom_func.h"
|
#include "zoom_func.h"
|
||||||
#include "framerate_type.h"
|
#include "framerate_type.h"
|
||||||
|
#include "industry.h"
|
||||||
|
#include "industry_map.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
|
@ -289,8 +291,8 @@ TileIndex Ship::GetOrderStationLocation(StationID station)
|
||||||
if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION;
|
if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION;
|
||||||
|
|
||||||
const Station *st = Station::Get(station);
|
const Station *st = Station::Get(station);
|
||||||
if (st->dock_tile != INVALID_TILE) {
|
if (CanVehicleUseStation(this, st)) {
|
||||||
return TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile)));
|
return st->xy;
|
||||||
} else {
|
} else {
|
||||||
this->IncrementRealOrderIndex();
|
this->IncrementRealOrderIndex();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -597,6 +599,28 @@ static bool ShipMoveUpDownOnLock(Ship *v)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if a tile is a docking tile for the given station.
|
||||||
|
* @param tile Docking tile to test.
|
||||||
|
* @param station Destination station.
|
||||||
|
* @return true iff docking tile is next to station.
|
||||||
|
*/
|
||||||
|
bool IsShipDestinationTile(TileIndex tile, StationID station)
|
||||||
|
{
|
||||||
|
assert(IsDockingTile(tile));
|
||||||
|
/* Check each tile adjacent to docking tile. */
|
||||||
|
for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
|
||||||
|
TileIndex t = tile + TileOffsByDiagDir(d);
|
||||||
|
if (!IsValidTile(t)) continue;
|
||||||
|
if (IsDockTile(t) && GetStationIndex(t) == station) return true;
|
||||||
|
if (IsTileType(t, MP_INDUSTRY)) {
|
||||||
|
const Industry *i = Industry::GetByTile(t);
|
||||||
|
if (i->neutral_station != nullptr && i->neutral_station->index == station) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void ShipController(Ship *v)
|
static void ShipController(Ship *v)
|
||||||
{
|
{
|
||||||
uint32 r;
|
uint32 r;
|
||||||
|
@ -665,26 +689,24 @@ static void ShipController(Ship *v)
|
||||||
UpdateVehicleTimetable(v, true);
|
UpdateVehicleTimetable(v, true);
|
||||||
v->IncrementRealOrderIndex();
|
v->IncrementRealOrderIndex();
|
||||||
v->current_order.MakeDummy();
|
v->current_order.MakeDummy();
|
||||||
} else {
|
} else if (v->current_order.IsType(OT_GOTO_DEPOT) &&
|
||||||
/* Non-buoy orders really need to reach the tile */
|
v->dest_tile == gp.new_tile) {
|
||||||
if (v->dest_tile == gp.new_tile) {
|
/* Depot orders really need to reach the tile */
|
||||||
if (v->current_order.IsType(OT_GOTO_DEPOT)) {
|
if ((gp.x & 0xF) == 8 && (gp.y & 0xF) == 8) {
|
||||||
if ((gp.x & 0xF) == 8 && (gp.y & 0xF) == 8) {
|
VehicleEnterDepot(v);
|
||||||
VehicleEnterDepot(v);
|
return;
|
||||||
return;
|
}
|
||||||
}
|
} else if (v->current_order.IsType(OT_GOTO_STATION) && IsDockingTile(gp.new_tile)) {
|
||||||
} else if (v->current_order.IsType(OT_GOTO_STATION)) {
|
/* Process station in the orderlist. */
|
||||||
v->last_station_visited = v->current_order.GetDestination();
|
Station *st = Station::Get(v->current_order.GetDestination());
|
||||||
|
if (st->docking_station.Contains(gp.new_tile) && IsShipDestinationTile(gp.new_tile, st->index)) {
|
||||||
/* Process station in the orderlist. */
|
v->last_station_visited = st->index;
|
||||||
Station *st = Station::Get(v->current_order.GetDestination());
|
if (st->facilities & FACIL_DOCK) { // ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations
|
||||||
if (st->facilities & FACIL_DOCK) { // ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations
|
ShipArrivesAt(v, st);
|
||||||
ShipArrivesAt(v, st);
|
v->BeginLoading();
|
||||||
v->BeginLoading();
|
} else { // leave stations without docks right aways
|
||||||
} else { // leave stations without docks right aways
|
v->current_order.MakeLeaveStation();
|
||||||
v->current_order.MakeLeaveStation();
|
v->IncrementRealOrderIndex();
|
||||||
v->IncrementRealOrderIndex();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ Station::Station(TileIndex tile) :
|
||||||
SpecializedStation<Station, false>(tile),
|
SpecializedStation<Station, false>(tile),
|
||||||
bus_station(INVALID_TILE, 0, 0),
|
bus_station(INVALID_TILE, 0, 0),
|
||||||
truck_station(INVALID_TILE, 0, 0),
|
truck_station(INVALID_TILE, 0, 0),
|
||||||
dock_tile(INVALID_TILE),
|
ship_station(INVALID_TILE, 0, 0),
|
||||||
indtype(IT_INVALID),
|
indtype(IT_INVALID),
|
||||||
time_since_load(255),
|
time_since_load(255),
|
||||||
time_since_unload(255),
|
time_since_unload(255),
|
||||||
|
@ -329,10 +329,10 @@ uint Station::GetCatchmentRadius() const
|
||||||
if (this->bus_stops != nullptr) ret = max<uint>(ret, CA_BUS);
|
if (this->bus_stops != nullptr) ret = max<uint>(ret, CA_BUS);
|
||||||
if (this->truck_stops != nullptr) ret = max<uint>(ret, CA_TRUCK);
|
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->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);
|
if (this->airport.tile != INVALID_TILE) ret = max<uint>(ret, this->airport.GetSpec()->catchment);
|
||||||
} else {
|
} else {
|
||||||
if (this->bus_stops != nullptr || this->truck_stops != nullptr || 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;
|
ret = CA_UNMODIFIED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -463,8 +463,9 @@ public:
|
||||||
RoadStop *truck_stops; ///< All the truck stops
|
RoadStop *truck_stops; ///< All the truck stops
|
||||||
TileArea truck_station; ///< Tile area the truck 'station' part covers
|
TileArea truck_station; ///< Tile area the truck 'station' part covers
|
||||||
|
|
||||||
Airport airport; ///< Tile area the airport covers
|
Airport airport; ///< Tile area the airport covers
|
||||||
TileIndex dock_tile; ///< The location of the dock
|
TileArea ship_station; ///< Tile area the ship 'station' part covers
|
||||||
|
TileArea docking_station; ///< Tile area the docking tiles cover
|
||||||
|
|
||||||
IndustryType indtype; ///< Industry type to get the name from
|
IndustryType indtype; ///< Industry type to get the name from
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
#include "linkgraph/linkgraph_base.h"
|
#include "linkgraph/linkgraph_base.h"
|
||||||
#include "linkgraph/refresh.h"
|
#include "linkgraph/refresh.h"
|
||||||
#include "widgets/station_widget.h"
|
#include "widgets/station_widget.h"
|
||||||
|
#include "tunnelbridge_map.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
|
@ -401,7 +402,7 @@ void Station::GetTileArea(TileArea *ta, StationType type) const
|
||||||
|
|
||||||
case STATION_DOCK:
|
case STATION_DOCK:
|
||||||
case STATION_OILRIG:
|
case STATION_OILRIG:
|
||||||
ta->tile = this->dock_tile;
|
*ta = this->docking_station;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: NOT_REACHED();
|
default: NOT_REACHED();
|
||||||
|
@ -1459,16 +1460,14 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MakeRailStationAreaSmaller(BaseStation *st)
|
static TileArea MakeStationAreaSmaller(BaseStation *st, TileArea ta, bool (*func)(BaseStation *, TileIndex))
|
||||||
{
|
{
|
||||||
TileArea ta = st->train_station;
|
|
||||||
|
|
||||||
restart:
|
restart:
|
||||||
|
|
||||||
/* too small? */
|
/* too small? */
|
||||||
if (ta.w != 0 && ta.h != 0) {
|
if (ta.w != 0 && ta.h != 0) {
|
||||||
/* check the left side, x = constant, y changes */
|
/* check the left side, x = constant, y changes */
|
||||||
for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(0, i));) {
|
for (uint i = 0; !func(st, ta.tile + TileDiffXY(0, i));) {
|
||||||
/* the left side is unused? */
|
/* the left side is unused? */
|
||||||
if (++i == ta.h) {
|
if (++i == ta.h) {
|
||||||
ta.tile += TileDiffXY(1, 0);
|
ta.tile += TileDiffXY(1, 0);
|
||||||
|
@ -1478,7 +1477,7 @@ restart:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check the right side, x = constant, y changes */
|
/* check the right side, x = constant, y changes */
|
||||||
for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(ta.w - 1, i));) {
|
for (uint i = 0; !func(st, ta.tile + TileDiffXY(ta.w - 1, i));) {
|
||||||
/* the right side is unused? */
|
/* the right side is unused? */
|
||||||
if (++i == ta.h) {
|
if (++i == ta.h) {
|
||||||
ta.w--;
|
ta.w--;
|
||||||
|
@ -1487,7 +1486,7 @@ restart:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check the upper side, y = constant, x changes */
|
/* check the upper side, y = constant, x changes */
|
||||||
for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(i, 0));) {
|
for (uint i = 0; !func(st, ta.tile + TileDiffXY(i, 0));) {
|
||||||
/* the left side is unused? */
|
/* the left side is unused? */
|
||||||
if (++i == ta.w) {
|
if (++i == ta.w) {
|
||||||
ta.tile += TileDiffXY(0, 1);
|
ta.tile += TileDiffXY(0, 1);
|
||||||
|
@ -1497,7 +1496,7 @@ restart:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check the lower side, y = constant, x changes */
|
/* check the lower side, y = constant, x changes */
|
||||||
for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(i, ta.h - 1));) {
|
for (uint i = 0; !func(st, ta.tile + TileDiffXY(i, ta.h - 1));) {
|
||||||
/* the left side is unused? */
|
/* the left side is unused? */
|
||||||
if (++i == ta.w) {
|
if (++i == ta.w) {
|
||||||
ta.h--;
|
ta.h--;
|
||||||
|
@ -1508,7 +1507,28 @@ restart:
|
||||||
ta.Clear();
|
ta.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
st->train_station = ta;
|
return ta;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool TileBelongsToRailStation(BaseStation *st, TileIndex tile)
|
||||||
|
{
|
||||||
|
return st->TileBelongsToRailStation(tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MakeRailStationAreaSmaller(BaseStation *st)
|
||||||
|
{
|
||||||
|
st->train_station = MakeStationAreaSmaller(st, st->train_station, TileBelongsToRailStation);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool TileBelongsToShipStation(BaseStation *st, TileIndex tile)
|
||||||
|
{
|
||||||
|
return IsDockTile(tile) && GetStationIndex(tile) == st->index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MakeShipStationAreaSmaller(Station *st)
|
||||||
|
{
|
||||||
|
st->ship_station = MakeStationAreaSmaller(st, st->ship_station, TileBelongsToShipStation);
|
||||||
|
UpdateStationDockingTiles(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2553,10 +2573,9 @@ CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
||||||
ret = BuildStationPart(&st, flags, reuse, dock_area, STATIONNAMING_DOCK);
|
ret = BuildStationPart(&st, flags, reuse, dock_area, STATIONNAMING_DOCK);
|
||||||
if (ret.Failed()) return ret;
|
if (ret.Failed()) return ret;
|
||||||
|
|
||||||
if (st != nullptr && st->dock_tile != INVALID_TILE) return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK);
|
|
||||||
|
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
st->dock_tile = tile;
|
st->ship_station.Add(tile);
|
||||||
|
st->ship_station.Add(tile + TileOffsByDiagDir(direction));
|
||||||
st->AddFacility(FACIL_DOCK, tile);
|
st->AddFacility(FACIL_DOCK, tile);
|
||||||
|
|
||||||
st->rect.BeforeAddRect(dock_area.tile, dock_area.w, dock_area.h, StationRect::ADD_TRY);
|
st->rect.BeforeAddRect(dock_area.tile, dock_area.w, dock_area.h, StationRect::ADD_TRY);
|
||||||
|
@ -2569,6 +2588,7 @@ CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
||||||
Company::Get(st->owner)->infrastructure.station += 2;
|
Company::Get(st->owner)->infrastructure.station += 2;
|
||||||
|
|
||||||
MakeDock(tile, st->owner, st->index, direction, wc);
|
MakeDock(tile, st->owner, st->index, direction, wc);
|
||||||
|
UpdateStationDockingTiles(st);
|
||||||
|
|
||||||
st->AfterStationTileSetChange(true, STATION_DOCK);
|
st->AfterStationTileSetChange(true, STATION_DOCK);
|
||||||
}
|
}
|
||||||
|
@ -2576,6 +2596,63 @@ CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
||||||
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_STATION_DOCK]);
|
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_STATION_DOCK]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RemoveDockingTile(TileIndex t)
|
||||||
|
{
|
||||||
|
for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
|
||||||
|
TileIndex tile = t + TileOffsByDiagDir(d);
|
||||||
|
if (!IsValidTile(tile)) continue;
|
||||||
|
|
||||||
|
if (IsTileType(tile, MP_STATION)) {
|
||||||
|
UpdateStationDockingTiles(Station::GetByTile(tile));
|
||||||
|
} else if (IsTileType(tile, MP_INDUSTRY)) {
|
||||||
|
UpdateStationDockingTiles(Industry::GetByTile(tile)->neutral_station);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear docking tile status from tiles around a removed dock, if the tile has
|
||||||
|
* no neighbours which would keep it as a docking tile.
|
||||||
|
* @param tile Ex-dock tile to check.
|
||||||
|
*/
|
||||||
|
void ClearDockingTilesCheckingNeighbours(TileIndex tile)
|
||||||
|
{
|
||||||
|
assert(IsValidTile(tile));
|
||||||
|
|
||||||
|
/* Clear and maybe re-set docking tile */
|
||||||
|
for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
|
||||||
|
TileIndex docking_tile = tile + TileOffsByDiagDir(d);
|
||||||
|
if (!IsValidTile(docking_tile)) continue;
|
||||||
|
|
||||||
|
if (IsPossibleDockingTile(docking_tile)) {
|
||||||
|
SetDockingTile(docking_tile, false);
|
||||||
|
CheckForDockingTile(docking_tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the part of a dock that is land-based
|
||||||
|
* @param t Dock tile to find land part of
|
||||||
|
* @return tile of land part of dock
|
||||||
|
*/
|
||||||
|
static TileIndex FindDockLandPart(TileIndex t)
|
||||||
|
{
|
||||||
|
assert(IsDockTile(t));
|
||||||
|
|
||||||
|
StationGfx gfx = GetStationGfx(t);
|
||||||
|
if (gfx < GFX_DOCK_BASE_WATER_PART) return t;
|
||||||
|
|
||||||
|
for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
|
||||||
|
TileIndex tile = t + TileOffsByDiagDir(d);
|
||||||
|
if (!IsValidTile(tile)) continue;
|
||||||
|
if (!IsDockTile(tile)) continue;
|
||||||
|
if (GetStationGfx(tile) < GFX_DOCK_BASE_WATER_PART && tile + TileOffsByDiagDir(GetDockDirection(tile)) == t) return tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
return INVALID_TILE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a dock
|
* Remove a dock
|
||||||
* @param tile TileIndex been queried
|
* @param tile TileIndex been queried
|
||||||
|
@ -2588,9 +2665,10 @@ static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags)
|
||||||
CommandCost ret = CheckOwnership(st->owner);
|
CommandCost ret = CheckOwnership(st->owner);
|
||||||
if (ret.Failed()) return ret;
|
if (ret.Failed()) return ret;
|
||||||
|
|
||||||
TileIndex docking_location = TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile)));
|
if (!IsDockTile(tile)) return CMD_ERROR;
|
||||||
|
|
||||||
TileIndex tile1 = st->dock_tile;
|
TileIndex tile1 = FindDockLandPart(tile);
|
||||||
|
if (tile1 == INVALID_TILE) return CMD_ERROR;
|
||||||
TileIndex tile2 = tile1 + TileOffsByDiagDir(GetDockDirection(tile1));
|
TileIndex tile2 = tile1 + TileOffsByDiagDir(GetDockDirection(tile1));
|
||||||
|
|
||||||
ret = EnsureNoVehicleOnGround(tile1);
|
ret = EnsureNoVehicleOnGround(tile1);
|
||||||
|
@ -2605,26 +2683,34 @@ static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags)
|
||||||
st->rect.AfterRemoveTile(st, tile1);
|
st->rect.AfterRemoveTile(st, tile1);
|
||||||
st->rect.AfterRemoveTile(st, tile2);
|
st->rect.AfterRemoveTile(st, tile2);
|
||||||
|
|
||||||
st->dock_tile = INVALID_TILE;
|
MakeShipStationAreaSmaller(st);
|
||||||
st->facilities &= ~FACIL_DOCK;
|
if (st->ship_station.tile == INVALID_TILE) {
|
||||||
|
st->ship_station.Clear();
|
||||||
|
st->docking_station.Clear();
|
||||||
|
st->facilities &= ~FACIL_DOCK;
|
||||||
|
}
|
||||||
|
|
||||||
Company::Get(st->owner)->infrastructure.station -= 2;
|
Company::Get(st->owner)->infrastructure.station -= 2;
|
||||||
|
|
||||||
st->AfterStationTileSetChange(false, STATION_DOCK);
|
st->AfterStationTileSetChange(false, STATION_DOCK);
|
||||||
|
|
||||||
|
ClearDockingTilesCheckingNeighbours(tile1);
|
||||||
|
ClearDockingTilesCheckingNeighbours(tile2);
|
||||||
|
|
||||||
/* All ships that were going to our station, can't go to it anymore.
|
/* All ships that were going to our station, can't go to it anymore.
|
||||||
* Just clear the order, then automatically the next appropriate order
|
* Just clear the order, then automatically the next appropriate order
|
||||||
* will be selected and in case of no appropriate order it will just
|
* will be selected and in case of no appropriate order it will just
|
||||||
* wander around the world. */
|
* wander around the world. */
|
||||||
Ship *s;
|
if (!(st->facilities & FACIL_DOCK)) {
|
||||||
FOR_ALL_SHIPS(s) {
|
Ship *s;
|
||||||
if (s->current_order.IsType(OT_LOADING) && s->tile == docking_location) {
|
FOR_ALL_SHIPS(s) {
|
||||||
s->LeaveStation();
|
if (s->current_order.IsType(OT_LOADING) && s->current_order.GetDestination() == st->index) {
|
||||||
}
|
s->LeaveStation();
|
||||||
|
}
|
||||||
|
|
||||||
if (s->dest_tile == docking_location) {
|
if (s->current_order.IsType(OT_GOTO_STATION) && s->current_order.GetDestination() == st->index) {
|
||||||
s->SetDestTile(0);
|
s->SetDestTile(s->GetOrderStationLocation(st->index));
|
||||||
s->current_order.Free();
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2873,7 +2959,7 @@ draw_default_foundation:
|
||||||
} else {
|
} else {
|
||||||
assert(IsDock(ti->tile));
|
assert(IsDock(ti->tile));
|
||||||
TileIndex water_tile = ti->tile + TileOffsByDiagDir(GetDockDirection(ti->tile));
|
TileIndex water_tile = ti->tile + TileOffsByDiagDir(GetDockDirection(ti->tile));
|
||||||
WaterClass wc = GetWaterClass(water_tile);
|
WaterClass wc = HasTileWaterClass(water_tile) ? GetWaterClass(water_tile) : WATER_CLASS_INVALID;
|
||||||
if (wc == WATER_CLASS_SEA) {
|
if (wc == WATER_CLASS_SEA) {
|
||||||
DrawShoreTile(ti->tileh);
|
DrawShoreTile(ti->tileh);
|
||||||
} else {
|
} else {
|
||||||
|
@ -3991,6 +4077,32 @@ uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, Sourc
|
||||||
return moved + UpdateStationWaiting(st2, type, worst_cargo, source_type, source_id);
|
return moved + UpdateStationWaiting(st2, type, worst_cargo, source_type, source_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UpdateStationDockingTiles(Station *st)
|
||||||
|
{
|
||||||
|
st->docking_station.Clear();
|
||||||
|
|
||||||
|
/* For neutral stations, start with the industry area instead of dock area */
|
||||||
|
const TileArea *area = st->industry != nullptr ? &st->industry->location : &st->ship_station;
|
||||||
|
|
||||||
|
if (area->tile == INVALID_TILE) return;
|
||||||
|
|
||||||
|
int x = TileX(area->tile);
|
||||||
|
int y = TileY(area->tile);
|
||||||
|
|
||||||
|
/* Expand the area by a tile on each side while
|
||||||
|
* making sure that we remain inside the map. */
|
||||||
|
int x2 = min(x + area->w + 1, MapSizeX());
|
||||||
|
int x1 = max(x - 1, 0);
|
||||||
|
|
||||||
|
int y2 = min(y + area->h + 1, MapSizeY());
|
||||||
|
int y1 = max(y - 1, 0);
|
||||||
|
|
||||||
|
TileArea ta(TileXY(x1, y1), TileXY(x2 - 1, y2 - 1));
|
||||||
|
TILE_AREA_LOOP(tile, ta) {
|
||||||
|
if (IsValidTile(tile) && IsPossibleDockingTile(tile)) CheckForDockingTile(tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BuildOilRig(TileIndex tile)
|
void BuildOilRig(TileIndex tile)
|
||||||
{
|
{
|
||||||
if (!Station::CanAllocateItem()) {
|
if (!Station::CanAllocateItem()) {
|
||||||
|
@ -4014,9 +4126,10 @@ void BuildOilRig(TileIndex tile)
|
||||||
st->owner = OWNER_NONE;
|
st->owner = OWNER_NONE;
|
||||||
st->airport.type = AT_OILRIG;
|
st->airport.type = AT_OILRIG;
|
||||||
st->airport.Add(tile);
|
st->airport.Add(tile);
|
||||||
st->dock_tile = tile;
|
st->ship_station.Add(tile);
|
||||||
st->facilities = FACIL_AIRPORT | FACIL_DOCK;
|
st->facilities = FACIL_AIRPORT | FACIL_DOCK;
|
||||||
st->build_date = _date;
|
st->build_date = _date;
|
||||||
|
UpdateStationDockingTiles(st);
|
||||||
|
|
||||||
st->rect.BeforeAddTile(tile, StationRect::ADD_FORCE);
|
st->rect.BeforeAddTile(tile, StationRect::ADD_FORCE);
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,9 @@ void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, Ro
|
||||||
bool HasStationInUse(StationID station, bool include_company, CompanyID company);
|
bool HasStationInUse(StationID station, bool include_company, CompanyID company);
|
||||||
|
|
||||||
void DeleteOilRig(TileIndex t);
|
void DeleteOilRig(TileIndex t);
|
||||||
|
void UpdateStationDockingTiles(Station *st);
|
||||||
|
void RemoveDockingTile(TileIndex t);
|
||||||
|
void ClearDockingTilesCheckingNeighbours(TileIndex tile);
|
||||||
|
|
||||||
/* Check if a rail station tile is traversable. */
|
/* Check if a rail station tile is traversable. */
|
||||||
bool IsStationTileBlocked(TileIndex tile);
|
bool IsStationTileBlocked(TileIndex tile);
|
||||||
|
|
|
@ -536,6 +536,7 @@ static inline void MakeStation(TileIndex t, Owner o, StationID sid, StationType
|
||||||
SetTileType(t, MP_STATION);
|
SetTileType(t, MP_STATION);
|
||||||
SetTileOwner(t, o);
|
SetTileOwner(t, o);
|
||||||
SetWaterClass(t, wc);
|
SetWaterClass(t, wc);
|
||||||
|
SetDockingTile(t, false);
|
||||||
_m[t].m2 = sid;
|
_m[t].m2 = sid;
|
||||||
_m[t].m3 = 0;
|
_m[t].m3 = 0;
|
||||||
_m[t].m4 = 0;
|
_m[t].m4 = 0;
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "object_base.h"
|
#include "object_base.h"
|
||||||
#include "water.h"
|
#include "water.h"
|
||||||
#include "company_gui.h"
|
#include "company_gui.h"
|
||||||
|
#include "station_func.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
#include "table/bridge_land.h"
|
#include "table/bridge_land.h"
|
||||||
|
@ -533,6 +534,8 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u
|
||||||
if (is_new_owner && c != nullptr) c->infrastructure.water += (bridge_len + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
if (is_new_owner && c != nullptr) c->infrastructure.water += (bridge_len + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||||
MakeAqueductBridgeRamp(tile_start, owner, dir);
|
MakeAqueductBridgeRamp(tile_start, owner, dir);
|
||||||
MakeAqueductBridgeRamp(tile_end, owner, ReverseDiagDir(dir));
|
MakeAqueductBridgeRamp(tile_end, owner, ReverseDiagDir(dir));
|
||||||
|
CheckForDockingTile(tile_start);
|
||||||
|
CheckForDockingTile(tile_end);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -944,6 +947,9 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
|
||||||
if (v != nullptr) FreeTrainTrackReservation(v);
|
if (v != nullptr) FreeTrainTrackReservation(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool removetile = false;
|
||||||
|
bool removeendtile = false;
|
||||||
|
|
||||||
/* Update company infrastructure counts. */
|
/* Update company infrastructure counts. */
|
||||||
if (rail) {
|
if (rail) {
|
||||||
if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||||
|
@ -953,11 +959,16 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
|
||||||
UpdateCompanyRoadInfrastructure(GetRoadTypeTram(tile), GetRoadOwner(tile, RTT_TRAM), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR));
|
UpdateCompanyRoadInfrastructure(GetRoadTypeTram(tile), GetRoadOwner(tile, RTT_TRAM), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR));
|
||||||
} else { // Aqueduct
|
} else { // Aqueduct
|
||||||
if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.water -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.water -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||||
|
removetile = IsDockingTile(tile);
|
||||||
|
removeendtile = IsDockingTile(endtile);
|
||||||
}
|
}
|
||||||
DirtyCompanyInfrastructureWindows(owner);
|
DirtyCompanyInfrastructureWindows(owner);
|
||||||
|
|
||||||
DoClearSquare(tile);
|
DoClearSquare(tile);
|
||||||
DoClearSquare(endtile);
|
DoClearSquare(endtile);
|
||||||
|
|
||||||
|
if (removetile) RemoveDockingTile(tile);
|
||||||
|
if (removeendtile) RemoveDockingTile(endtile);
|
||||||
for (TileIndex c = tile + delta; c != endtile; c += delta) {
|
for (TileIndex c = tile + delta; c != endtile; c += delta) {
|
||||||
/* do not let trees appear from 'nowhere' after removing bridge */
|
/* do not let trees appear from 'nowhere' after removing bridge */
|
||||||
if (IsNormalRoadTile(c) && GetRoadside(c) == ROADSIDE_TREES) {
|
if (IsNormalRoadTile(c) && GetRoadside(c) == ROADSIDE_TREES) {
|
||||||
|
|
|
@ -38,6 +38,7 @@ void DrawWaterClassGround(const struct TileInfo *ti);
|
||||||
void DrawShoreTile(Slope tileh);
|
void DrawShoreTile(Slope tileh);
|
||||||
|
|
||||||
void MakeWaterKeepingClass(TileIndex tile, Owner o);
|
void MakeWaterKeepingClass(TileIndex tile, Owner o);
|
||||||
|
void CheckForDockingTile(TileIndex t);
|
||||||
|
|
||||||
bool RiverModifyDesertZone(TileIndex tile, void *data);
|
bool RiverModifyDesertZone(TileIndex tile, void *data);
|
||||||
static const uint RIVER_OFFSET_DESERT_DISTANCE = 5; ///< Circular tile search radius to create non-desert around a river tile.
|
static const uint RIVER_OFFSET_DESERT_DISTANCE = 5; ///< Circular tile search radius to create non-desert around a river tile.
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "company_base.h"
|
#include "company_base.h"
|
||||||
#include "company_gui.h"
|
#include "company_gui.h"
|
||||||
#include "newgrf_generic.h"
|
#include "newgrf_generic.h"
|
||||||
|
#include "industry.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
|
@ -148,6 +149,8 @@ CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, ui
|
||||||
|
|
||||||
MakeShipDepot(tile, _current_company, depot->index, DEPOT_PART_NORTH, axis, wc1);
|
MakeShipDepot(tile, _current_company, depot->index, DEPOT_PART_NORTH, axis, wc1);
|
||||||
MakeShipDepot(tile2, _current_company, depot->index, DEPOT_PART_SOUTH, axis, wc2);
|
MakeShipDepot(tile2, _current_company, depot->index, DEPOT_PART_SOUTH, axis, wc2);
|
||||||
|
CheckForDockingTile(tile);
|
||||||
|
CheckForDockingTile(tile2);
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
MarkTileDirtyByTile(tile2);
|
MarkTileDirtyByTile(tile2);
|
||||||
MakeDefaultName(depot);
|
MakeDefaultName(depot);
|
||||||
|
@ -156,6 +159,48 @@ CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, ui
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsPossibleDockingTile(TileIndex t)
|
||||||
|
{
|
||||||
|
assert(IsValidTile(t));
|
||||||
|
switch (GetTileType(t)) {
|
||||||
|
case MP_WATER:
|
||||||
|
if (IsLock(t) && GetLockPart(t) == LOCK_PART_MIDDLE) return false;
|
||||||
|
FALLTHROUGH;
|
||||||
|
case MP_RAILWAY:
|
||||||
|
case MP_STATION:
|
||||||
|
case MP_TUNNELBRIDGE:
|
||||||
|
return TrackStatusToTrackBits(GetTileTrackStatus(t, TRANSPORT_WATER, 0)) != TRACK_BIT_NONE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark the supplied tile as a docking tile if it is suitable for docking.
|
||||||
|
* Tiles surrounding the tile are tested to be docks with correct orientation.
|
||||||
|
* @param t Tile to test.
|
||||||
|
*/
|
||||||
|
void CheckForDockingTile(TileIndex t)
|
||||||
|
{
|
||||||
|
for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
|
||||||
|
TileIndex tile = t + TileOffsByDiagDir(d);
|
||||||
|
if (!IsValidTile(tile)) continue;
|
||||||
|
|
||||||
|
if (IsDockTile(tile)) {
|
||||||
|
Station::GetByTile(tile)->docking_station.Add(t);
|
||||||
|
SetDockingTile(t, true);
|
||||||
|
}
|
||||||
|
if (IsTileType(tile, MP_INDUSTRY)) {
|
||||||
|
Station *st = Industry::GetByTile(tile)->neutral_station;
|
||||||
|
if (st != nullptr) {
|
||||||
|
st->docking_station.Add(t);
|
||||||
|
SetDockingTile(t, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MakeWaterKeepingClass(TileIndex tile, Owner o)
|
void MakeWaterKeepingClass(TileIndex tile, Owner o)
|
||||||
{
|
{
|
||||||
WaterClass wc = GetWaterClass(tile);
|
WaterClass wc = GetWaterClass(tile);
|
||||||
|
@ -204,6 +249,7 @@ void MakeWaterKeepingClass(TileIndex tile, Owner o)
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wc != WATER_CLASS_INVALID) CheckForDockingTile(tile);
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,6 +349,8 @@ static CommandCost DoBuildLock(TileIndex tile, DiagDirection dir, DoCommandFlag
|
||||||
}
|
}
|
||||||
|
|
||||||
MakeLock(tile, _current_company, dir, wc_lower, wc_upper, wc_middle);
|
MakeLock(tile, _current_company, dir, wc_lower, wc_upper, wc_middle);
|
||||||
|
CheckForDockingTile(tile - delta);
|
||||||
|
CheckForDockingTile(tile + delta);
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
MarkTileDirtyByTile(tile - delta);
|
MarkTileDirtyByTile(tile - delta);
|
||||||
MarkTileDirtyByTile(tile + delta);
|
MarkTileDirtyByTile(tile + delta);
|
||||||
|
@ -449,6 +497,7 @@ CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
||||||
}
|
}
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
MarkCanalsAndRiversAroundDirty(tile);
|
MarkCanalsAndRiversAroundDirty(tile);
|
||||||
|
CheckForDockingTile(tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
cost.AddCost(_price[PR_BUILD_CANAL]);
|
cost.AddCost(_price[PR_BUILD_CANAL]);
|
||||||
|
@ -489,8 +538,10 @@ static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
|
||||||
Company::Get(owner)->infrastructure.water--;
|
Company::Get(owner)->infrastructure.water--;
|
||||||
DirtyCompanyInfrastructureWindows(owner);
|
DirtyCompanyInfrastructureWindows(owner);
|
||||||
}
|
}
|
||||||
|
bool remove = IsDockingTile(tile);
|
||||||
DoClearSquare(tile);
|
DoClearSquare(tile);
|
||||||
MarkCanalsAndRiversAroundDirty(tile);
|
MarkCanalsAndRiversAroundDirty(tile);
|
||||||
|
if (remove) RemoveDockingTile(tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CommandCost(EXPENSES_CONSTRUCTION, base_cost);
|
return CommandCost(EXPENSES_CONSTRUCTION, base_cost);
|
||||||
|
@ -504,8 +555,10 @@ static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
|
||||||
if (ret.Failed()) return ret;
|
if (ret.Failed()) return ret;
|
||||||
|
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
|
bool remove = IsDockingTile(tile);
|
||||||
DoClearSquare(tile);
|
DoClearSquare(tile);
|
||||||
MarkCanalsAndRiversAroundDirty(tile);
|
MarkCanalsAndRiversAroundDirty(tile);
|
||||||
|
if (remove) RemoveDockingTile(tile);
|
||||||
}
|
}
|
||||||
if (IsSlopeWithOneCornerRaised(slope)) {
|
if (IsSlopeWithOneCornerRaised(slope)) {
|
||||||
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
|
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
|
||||||
|
@ -1095,6 +1148,8 @@ void DoFloodTile(TileIndex target)
|
||||||
|
|
||||||
/* update signals if needed */
|
/* update signals if needed */
|
||||||
UpdateSignalsInBuffer();
|
UpdateSignalsInBuffer();
|
||||||
|
|
||||||
|
if (IsPossibleDockingTile(target)) CheckForDockingTile(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_company.Restore();
|
cur_company.Restore();
|
||||||
|
|
|
@ -69,6 +69,8 @@ enum LockPart {
|
||||||
LOCK_PART_UPPER = 2, ///< Upper part of a lock.
|
LOCK_PART_UPPER = 2, ///< Upper part of a lock.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool IsPossibleDockingTile(TileIndex t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the water tile type at a tile.
|
* Get the water tile type at a tile.
|
||||||
* @param t Water tile to query.
|
* @param t Water tile to query.
|
||||||
|
@ -346,6 +348,27 @@ static inline bool HasTileWaterGround(TileIndex t)
|
||||||
return HasTileWaterClass(t) && IsTileOnWater(t) && !IsCoastTile(t);
|
return HasTileWaterClass(t) && IsTileOnWater(t) && !IsCoastTile(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the docking tile state of a tile. This is used by pathfinders to reach their destination.
|
||||||
|
* As well as water tiles, half-rail tiles, buoys and aqueduct ends can also be docking tiles.
|
||||||
|
* @param t the tile
|
||||||
|
* @param b the docking tile state
|
||||||
|
*/
|
||||||
|
static inline void SetDockingTile(TileIndex t, bool b)
|
||||||
|
{
|
||||||
|
assert(IsTileType(t, MP_WATER) || IsTileType(t, MP_RAILWAY) || IsTileType(t, MP_STATION) || IsTileType(t, MP_TUNNELBRIDGE));
|
||||||
|
SB(_m[t].m1, 7, 1, b ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the tile is marked as a dockling tile.
|
||||||
|
* @return true iff the tile is marked as a docking tile.
|
||||||
|
*/
|
||||||
|
static inline bool IsDockingTile(TileIndex t)
|
||||||
|
{
|
||||||
|
return (IsTileType(t, MP_WATER) || IsTileType(t, MP_RAILWAY) || IsTileType(t, MP_STATION) || IsTileType(t, MP_TUNNELBRIDGE)) && HasBit(_m[t].m1, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to make a coast tile.
|
* Helper function to make a coast tile.
|
||||||
|
@ -356,6 +379,7 @@ static inline void MakeShore(TileIndex t)
|
||||||
SetTileType(t, MP_WATER);
|
SetTileType(t, MP_WATER);
|
||||||
SetTileOwner(t, OWNER_WATER);
|
SetTileOwner(t, OWNER_WATER);
|
||||||
SetWaterClass(t, WATER_CLASS_SEA);
|
SetWaterClass(t, WATER_CLASS_SEA);
|
||||||
|
SetDockingTile(t, false);
|
||||||
_m[t].m2 = 0;
|
_m[t].m2 = 0;
|
||||||
_m[t].m3 = 0;
|
_m[t].m3 = 0;
|
||||||
_m[t].m4 = 0;
|
_m[t].m4 = 0;
|
||||||
|
@ -376,6 +400,7 @@ static inline void MakeWater(TileIndex t, Owner o, WaterClass wc, uint8 random_b
|
||||||
SetTileType(t, MP_WATER);
|
SetTileType(t, MP_WATER);
|
||||||
SetTileOwner(t, o);
|
SetTileOwner(t, o);
|
||||||
SetWaterClass(t, wc);
|
SetWaterClass(t, wc);
|
||||||
|
SetDockingTile(t, false);
|
||||||
_m[t].m2 = 0;
|
_m[t].m2 = 0;
|
||||||
_m[t].m3 = 0;
|
_m[t].m3 = 0;
|
||||||
_m[t].m4 = random_bits;
|
_m[t].m4 = random_bits;
|
||||||
|
@ -429,6 +454,7 @@ static inline void MakeShipDepot(TileIndex t, Owner o, DepotID did, DepotPart pa
|
||||||
SetTileType(t, MP_WATER);
|
SetTileType(t, MP_WATER);
|
||||||
SetTileOwner(t, o);
|
SetTileOwner(t, o);
|
||||||
SetWaterClass(t, original_water_class);
|
SetWaterClass(t, original_water_class);
|
||||||
|
SetDockingTile(t, false);
|
||||||
_m[t].m2 = did;
|
_m[t].m2 = did;
|
||||||
_m[t].m3 = 0;
|
_m[t].m3 = 0;
|
||||||
_m[t].m4 = 0;
|
_m[t].m4 = 0;
|
||||||
|
@ -451,6 +477,7 @@ static inline void MakeLockTile(TileIndex t, Owner o, LockPart part, DiagDirecti
|
||||||
SetTileType(t, MP_WATER);
|
SetTileType(t, MP_WATER);
|
||||||
SetTileOwner(t, o);
|
SetTileOwner(t, o);
|
||||||
SetWaterClass(t, original_water_class);
|
SetWaterClass(t, original_water_class);
|
||||||
|
SetDockingTile(t, false);
|
||||||
_m[t].m2 = 0;
|
_m[t].m2 = 0;
|
||||||
_m[t].m3 = 0;
|
_m[t].m3 = 0;
|
||||||
_m[t].m4 = 0;
|
_m[t].m4 = 0;
|
||||||
|
|
|
@ -332,6 +332,7 @@ CommandCost CmdBuildBuoy(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
||||||
if (wp->town == nullptr) MakeDefaultName(wp);
|
if (wp->town == nullptr) MakeDefaultName(wp);
|
||||||
|
|
||||||
MakeBuoy(tile, wp->index, GetWaterClass(tile));
|
MakeBuoy(tile, wp->index, GetWaterClass(tile));
|
||||||
|
CheckForDockingTile(tile);
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
|
|
||||||
wp->UpdateVirtCoord();
|
wp->UpdateVirtCoord();
|
||||||
|
|
Loading…
Reference in New Issue