mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-12 18:40:29 +00:00
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>
|
||||
<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>m2: see signals</li>
|
||||
<li>m3 bits 7..4: see signals</li>
|
||||
@ -871,6 +872,7 @@
|
||||
<td valign=top nowrap> </td>
|
||||
<td>
|
||||
<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 4..0: <a href="#OwnershipInfo">owner</a> of the station</li>
|
||||
<li>m2: index into the array of stations</li>
|
||||
@ -1008,6 +1010,7 @@
|
||||
<td valign=top nowrap> </td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>m1 bit 7: Ship docking tile status</li>
|
||||
<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>m2: Depot index (for depots only)</li>
|
||||
@ -1459,6 +1462,7 @@
|
||||
<td valign=top nowrap> </td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>m1 bit 7: Ship docking tile status (for aqueducts)</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>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="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 OOOO</span></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="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 <span class="free">OOOO</span></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="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</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="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">XXXX <span class="free">OOOO</span></td>
|
||||
<td class="bits"><span class="free">OO</span>XX XXXX</td>
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "rail_map.h"
|
||||
#include "road_map.h"
|
||||
#include "bridge.h"
|
||||
#include "water_map.h"
|
||||
|
||||
/**
|
||||
* 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);
|
||||
SetTileOwner(t, o);
|
||||
SetDockingTile(t, false);
|
||||
_m[t].m2 = 0;
|
||||
_m[t].m3 = 0;
|
||||
_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) {
|
||||
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 (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;
|
||||
}
|
||||
|
||||
|
@ -165,8 +165,8 @@ static int32 NPFCalcStationOrTileHeuristic(AyStar *as, AyStarNode *current, Open
|
||||
uint dist;
|
||||
AyStarUserData *user = (AyStarUserData *)as->user_data;
|
||||
|
||||
/* for train-stations, we are going to aim for the closest station tile */
|
||||
if (user->type != TRANSPORT_WATER && fstd->station_index != INVALID_STATION) {
|
||||
/* aim for the closest station tile */
|
||||
if (fstd->station_index != INVALID_STATION) {
|
||||
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->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 (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.
|
||||
* So only for train orders to stations we fill fstd->station_index, for all
|
||||
* others only dest_coords */
|
||||
if (v->type != VEH_SHIP && (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_WAYPOINT))) {
|
||||
assert(v->IsGroundVehicle());
|
||||
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_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,95 @@
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "../../ship.h"
|
||||
#include "../../industry.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
|
||||
@ -75,14 +158,12 @@ public:
|
||||
|
||||
/* convert origin trackdir to TrackdirBits */
|
||||
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 */
|
||||
Tpf pf;
|
||||
/* set origin and destination nodes */
|
||||
pf.SetOrigin(src_tile, trackdirs);
|
||||
pf.SetDestination(v->dest_tile, dest_trackdirs);
|
||||
pf.SetDestination(v);
|
||||
/* find best path */
|
||||
path_found = pf.FindPath(v);
|
||||
|
||||
@ -124,14 +205,11 @@ public:
|
||||
*/
|
||||
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 */
|
||||
Tpf pf;
|
||||
/* set origin and destination nodes */
|
||||
pf.SetOrigin(tile, TrackdirToTrackdirBits(td1) | TrackdirToTrackdirBits(td2));
|
||||
pf.SetDestination(v->dest_tile, dest_trackdirs);
|
||||
pf.SetDestination(v);
|
||||
/* find best path */
|
||||
if (!pf.FindPath(v)) return false;
|
||||
|
||||
@ -230,7 +308,7 @@ struct CYapfShip_TypesT
|
||||
typedef CYapfBaseT<Types> PfBase; // base pathfinder class
|
||||
typedef CYapfFollowShipT<Types> PfFollow; // node follower
|
||||
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 CYapfCostShipT<Types> PfCost; // cost provider
|
||||
};
|
||||
|
@ -570,6 +570,7 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||
default: {
|
||||
/* Will there be flat water on the lower halftile? */
|
||||
bool water_ground = IsTileType(tile, MP_WATER) && IsSlopeWithOneCornerRaised(tileh);
|
||||
bool docking = IsPossibleDockingTile(tile) && IsDockingTile(tile);
|
||||
|
||||
CommandCost ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile);
|
||||
if (ret.Failed()) return ret;
|
||||
@ -586,7 +587,10 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
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]++;
|
||||
DirtyCompanyInfrastructureWindows(_current_company);
|
||||
}
|
||||
@ -708,7 +712,9 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
Slope tileh = GetTileSlope(tile);
|
||||
/* 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)) {
|
||||
bool docking = IsDockingTile(tile);
|
||||
MakeShore(tile);
|
||||
SetDockingTile(tile, docking);
|
||||
} else {
|
||||
DoClearSquare(tile);
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "signal_func.h"
|
||||
#include "track_func.h"
|
||||
#include "tile_map.h"
|
||||
#include "water_map.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);
|
||||
SetTileOwner(t, o);
|
||||
SetDockingTile(t, false);
|
||||
_m[t].m2 = 0;
|
||||
_m[t].m3 = 0;
|
||||
_m[t].m4 = 0;
|
||||
@ -535,6 +537,7 @@ static inline void MakeRailDepot(TileIndex t, Owner o, DepotID did, DiagDirectio
|
||||
{
|
||||
SetTileType(t, MP_RAILWAY);
|
||||
SetTileOwner(t, o);
|
||||
SetDockingTile(t, false);
|
||||
_m[t].m2 = did;
|
||||
_m[t].m3 = 0;
|
||||
_m[t].m4 = 0;
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include "../error.h"
|
||||
#include "../disaster_vehicle.h"
|
||||
#include "../ship.h"
|
||||
#include "../water.h"
|
||||
|
||||
|
||||
#include "saveload_internal.h"
|
||||
@ -675,7 +676,6 @@ bool AfterLoadGame()
|
||||
Station *st;
|
||||
FOR_ALL_STATIONS(st) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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. */
|
||||
Station::RecomputeCatchmentForAll();
|
||||
|
||||
|
@ -725,7 +725,7 @@ static const OldChunks station_chunk[] = {
|
||||
OCL_NULL( 4 ), ///< bus/lorry tile
|
||||
OCL_SVAR( OC_TILE, Station, train_station.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_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_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
|
||||
};
|
||||
|
@ -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, 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, dock_tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
|
||||
SLE_CONDVAR(Station, dock_tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
|
||||
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6),
|
||||
SLE_CONDNULL(4, SLV_6, SLV_MULTITILE_DOCKS),
|
||||
SLE_REF(Station, town, REF_TOWN),
|
||||
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),
|
||||
@ -423,7 +423,13 @@ static const SaveLoad _station_desc[] = {
|
||||
|
||||
SLE_REF(Station, bus_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_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),
|
||||
|
@ -261,8 +261,10 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
|
||||
TILE_AREA_LOOP(t, st->train_station) {
|
||||
if (st->TileBelongsToRailStation(t)) return t;
|
||||
}
|
||||
} else if (st->dock_tile != INVALID_TILE) {
|
||||
return st->dock_tile;
|
||||
} else if (st->ship_station.tile != INVALID_TILE) {
|
||||
TILE_AREA_LOOP(t, st->ship_station) {
|
||||
if (IsDockTile(t) && GetStationIndex(t) == st->index) return t;
|
||||
}
|
||||
} else if (st->bus_stops != nullptr) {
|
||||
return st->bus_stops->xy;
|
||||
} else if (st->truck_stops != nullptr) {
|
||||
|
@ -57,6 +57,8 @@ struct Ship FINAL : public SpecializedVehicle<Ship, VEH_SHIP> {
|
||||
void SetDestTile(TileIndex tile);
|
||||
};
|
||||
|
||||
bool IsShipDestinationTile(TileIndex tile, StationID station);
|
||||
|
||||
/**
|
||||
* Iterate over all ships.
|
||||
* @param var The variable used for iteration.
|
||||
|
@ -34,6 +34,8 @@
|
||||
#include "tunnelbridge_map.h"
|
||||
#include "zoom_func.h"
|
||||
#include "framerate_type.h"
|
||||
#include "industry.h"
|
||||
#include "industry_map.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;
|
||||
|
||||
const Station *st = Station::Get(station);
|
||||
if (st->dock_tile != INVALID_TILE) {
|
||||
return TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile)));
|
||||
if (CanVehicleUseStation(this, st)) {
|
||||
return st->xy;
|
||||
} else {
|
||||
this->IncrementRealOrderIndex();
|
||||
return 0;
|
||||
@ -597,6 +599,28 @@ static bool ShipMoveUpDownOnLock(Ship *v)
|
||||
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)
|
||||
{
|
||||
uint32 r;
|
||||
@ -665,26 +689,24 @@ static void ShipController(Ship *v)
|
||||
UpdateVehicleTimetable(v, true);
|
||||
v->IncrementRealOrderIndex();
|
||||
v->current_order.MakeDummy();
|
||||
} else {
|
||||
/* Non-buoy orders really need to reach the tile */
|
||||
if (v->dest_tile == gp.new_tile) {
|
||||
if (v->current_order.IsType(OT_GOTO_DEPOT)) {
|
||||
if ((gp.x & 0xF) == 8 && (gp.y & 0xF) == 8) {
|
||||
VehicleEnterDepot(v);
|
||||
return;
|
||||
}
|
||||
} else if (v->current_order.IsType(OT_GOTO_STATION)) {
|
||||
v->last_station_visited = v->current_order.GetDestination();
|
||||
|
||||
/* Process station in the orderlist. */
|
||||
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
|
||||
ShipArrivesAt(v, st);
|
||||
v->BeginLoading();
|
||||
} else { // leave stations without docks right aways
|
||||
v->current_order.MakeLeaveStation();
|
||||
v->IncrementRealOrderIndex();
|
||||
}
|
||||
} else if (v->current_order.IsType(OT_GOTO_DEPOT) &&
|
||||
v->dest_tile == gp.new_tile) {
|
||||
/* Depot orders really need to reach the tile */
|
||||
if ((gp.x & 0xF) == 8 && (gp.y & 0xF) == 8) {
|
||||
VehicleEnterDepot(v);
|
||||
return;
|
||||
}
|
||||
} else if (v->current_order.IsType(OT_GOTO_STATION) && IsDockingTile(gp.new_tile)) {
|
||||
/* Process station in the orderlist. */
|
||||
Station *st = Station::Get(v->current_order.GetDestination());
|
||||
if (st->docking_station.Contains(gp.new_tile) && IsShipDestinationTile(gp.new_tile, st->index)) {
|
||||
v->last_station_visited = st->index;
|
||||
if (st->facilities & FACIL_DOCK) { // ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations
|
||||
ShipArrivesAt(v, st);
|
||||
v->BeginLoading();
|
||||
} else { // leave stations without docks right aways
|
||||
v->current_order.MakeLeaveStation();
|
||||
v->IncrementRealOrderIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ Station::Station(TileIndex tile) :
|
||||
SpecializedStation<Station, false>(tile),
|
||||
bus_station(INVALID_TILE, 0, 0),
|
||||
truck_station(INVALID_TILE, 0, 0),
|
||||
dock_tile(INVALID_TILE),
|
||||
ship_station(INVALID_TILE, 0, 0),
|
||||
indtype(IT_INVALID),
|
||||
time_since_load(255),
|
||||
time_since_unload(255),
|
||||
@ -329,10 +329,10 @@ uint Station::GetCatchmentRadius() const
|
||||
if (this->bus_stops != nullptr) ret = max<uint>(ret, CA_BUS);
|
||||
if (this->truck_stops != nullptr) ret = max<uint>(ret, CA_TRUCK);
|
||||
if (this->train_station.tile != INVALID_TILE) ret = max<uint>(ret, CA_TRAIN);
|
||||
if (this->dock_tile != INVALID_TILE) ret = max<uint>(ret, CA_DOCK);
|
||||
if (this->ship_station.tile != INVALID_TILE) ret = max<uint>(ret, CA_DOCK);
|
||||
if (this->airport.tile != INVALID_TILE) ret = max<uint>(ret, this->airport.GetSpec()->catchment);
|
||||
} else {
|
||||
if (this->bus_stops != 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;
|
||||
}
|
||||
}
|
||||
|
@ -463,8 +463,9 @@ public:
|
||||
RoadStop *truck_stops; ///< All the truck stops
|
||||
TileArea truck_station; ///< Tile area the truck 'station' part covers
|
||||
|
||||
Airport airport; ///< Tile area the airport covers
|
||||
TileIndex dock_tile; ///< The location of the dock
|
||||
Airport airport; ///< Tile area the airport covers
|
||||
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
|
||||
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include "linkgraph/linkgraph_base.h"
|
||||
#include "linkgraph/refresh.h"
|
||||
#include "widgets/station_widget.h"
|
||||
#include "tunnelbridge_map.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
@ -401,7 +402,7 @@ void Station::GetTileArea(TileArea *ta, StationType type) const
|
||||
|
||||
case STATION_DOCK:
|
||||
case STATION_OILRIG:
|
||||
ta->tile = this->dock_tile;
|
||||
*ta = this->docking_station;
|
||||
break;
|
||||
|
||||
default: NOT_REACHED();
|
||||
@ -1459,16 +1460,14 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32
|
||||
return cost;
|
||||
}
|
||||
|
||||
static void MakeRailStationAreaSmaller(BaseStation *st)
|
||||
static TileArea MakeStationAreaSmaller(BaseStation *st, TileArea ta, bool (*func)(BaseStation *, TileIndex))
|
||||
{
|
||||
TileArea ta = st->train_station;
|
||||
|
||||
restart:
|
||||
|
||||
/* too small? */
|
||||
if (ta.w != 0 && ta.h != 0) {
|
||||
/* 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? */
|
||||
if (++i == ta.h) {
|
||||
ta.tile += TileDiffXY(1, 0);
|
||||
@ -1478,7 +1477,7 @@ restart:
|
||||
}
|
||||
|
||||
/* 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? */
|
||||
if (++i == ta.h) {
|
||||
ta.w--;
|
||||
@ -1487,7 +1486,7 @@ restart:
|
||||
}
|
||||
|
||||
/* 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? */
|
||||
if (++i == ta.w) {
|
||||
ta.tile += TileDiffXY(0, 1);
|
||||
@ -1497,7 +1496,7 @@ restart:
|
||||
}
|
||||
|
||||
/* 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? */
|
||||
if (++i == ta.w) {
|
||||
ta.h--;
|
||||
@ -1508,7 +1507,28 @@ restart:
|
||||
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);
|
||||
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) {
|
||||
st->dock_tile = tile;
|
||||
st->ship_station.Add(tile);
|
||||
st->ship_station.Add(tile + TileOffsByDiagDir(direction));
|
||||
st->AddFacility(FACIL_DOCK, tile);
|
||||
|
||||
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;
|
||||
|
||||
MakeDock(tile, st->owner, st->index, direction, wc);
|
||||
UpdateStationDockingTiles(st);
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
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
|
||||
* @param tile TileIndex been queried
|
||||
@ -2588,9 +2665,10 @@ static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags)
|
||||
CommandCost ret = CheckOwnership(st->owner);
|
||||
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));
|
||||
|
||||
ret = EnsureNoVehicleOnGround(tile1);
|
||||
@ -2605,26 +2683,34 @@ static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags)
|
||||
st->rect.AfterRemoveTile(st, tile1);
|
||||
st->rect.AfterRemoveTile(st, tile2);
|
||||
|
||||
st->dock_tile = INVALID_TILE;
|
||||
st->facilities &= ~FACIL_DOCK;
|
||||
MakeShipStationAreaSmaller(st);
|
||||
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;
|
||||
|
||||
st->AfterStationTileSetChange(false, STATION_DOCK);
|
||||
|
||||
ClearDockingTilesCheckingNeighbours(tile1);
|
||||
ClearDockingTilesCheckingNeighbours(tile2);
|
||||
|
||||
/* All ships that were going to our station, can't go to it anymore.
|
||||
* Just clear the order, then automatically the next appropriate order
|
||||
* will be selected and in case of no appropriate order it will just
|
||||
* wander around the world. */
|
||||
Ship *s;
|
||||
FOR_ALL_SHIPS(s) {
|
||||
if (s->current_order.IsType(OT_LOADING) && s->tile == docking_location) {
|
||||
s->LeaveStation();
|
||||
}
|
||||
if (!(st->facilities & FACIL_DOCK)) {
|
||||
Ship *s;
|
||||
FOR_ALL_SHIPS(s) {
|
||||
if (s->current_order.IsType(OT_LOADING) && s->current_order.GetDestination() == st->index) {
|
||||
s->LeaveStation();
|
||||
}
|
||||
|
||||
if (s->dest_tile == docking_location) {
|
||||
s->SetDestTile(0);
|
||||
s->current_order.Free();
|
||||
if (s->current_order.IsType(OT_GOTO_STATION) && s->current_order.GetDestination() == st->index) {
|
||||
s->SetDestTile(s->GetOrderStationLocation(st->index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2873,7 +2959,7 @@ draw_default_foundation:
|
||||
} else {
|
||||
assert(IsDock(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) {
|
||||
DrawShoreTile(ti->tileh);
|
||||
} 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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!Station::CanAllocateItem()) {
|
||||
@ -4014,9 +4126,10 @@ void BuildOilRig(TileIndex tile)
|
||||
st->owner = OWNER_NONE;
|
||||
st->airport.type = AT_OILRIG;
|
||||
st->airport.Add(tile);
|
||||
st->dock_tile = tile;
|
||||
st->ship_station.Add(tile);
|
||||
st->facilities = FACIL_AIRPORT | FACIL_DOCK;
|
||||
st->build_date = _date;
|
||||
UpdateStationDockingTiles(st);
|
||||
|
||||
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);
|
||||
|
||||
void DeleteOilRig(TileIndex t);
|
||||
void UpdateStationDockingTiles(Station *st);
|
||||
void RemoveDockingTile(TileIndex t);
|
||||
void ClearDockingTilesCheckingNeighbours(TileIndex tile);
|
||||
|
||||
/* Check if a rail station tile is traversable. */
|
||||
bool IsStationTileBlocked(TileIndex tile);
|
||||
|
@ -536,6 +536,7 @@ static inline void MakeStation(TileIndex t, Owner o, StationID sid, StationType
|
||||
SetTileType(t, MP_STATION);
|
||||
SetTileOwner(t, o);
|
||||
SetWaterClass(t, wc);
|
||||
SetDockingTile(t, false);
|
||||
_m[t].m2 = sid;
|
||||
_m[t].m3 = 0;
|
||||
_m[t].m4 = 0;
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "object_base.h"
|
||||
#include "water.h"
|
||||
#include "company_gui.h"
|
||||
#include "station_func.h"
|
||||
|
||||
#include "table/strings.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;
|
||||
MakeAqueductBridgeRamp(tile_start, owner, dir);
|
||||
MakeAqueductBridgeRamp(tile_end, owner, ReverseDiagDir(dir));
|
||||
CheckForDockingTile(tile_start);
|
||||
CheckForDockingTile(tile_end);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -944,6 +947,9 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
|
||||
if (v != nullptr) FreeTrainTrackReservation(v);
|
||||
}
|
||||
|
||||
bool removetile = false;
|
||||
bool removeendtile = false;
|
||||
|
||||
/* Update company infrastructure counts. */
|
||||
if (rail) {
|
||||
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));
|
||||
} else { // Aqueduct
|
||||
if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.water -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||
removetile = IsDockingTile(tile);
|
||||
removeendtile = IsDockingTile(endtile);
|
||||
}
|
||||
DirtyCompanyInfrastructureWindows(owner);
|
||||
|
||||
DoClearSquare(tile);
|
||||
DoClearSquare(endtile);
|
||||
|
||||
if (removetile) RemoveDockingTile(tile);
|
||||
if (removeendtile) RemoveDockingTile(endtile);
|
||||
for (TileIndex c = tile + delta; c != endtile; c += delta) {
|
||||
/* do not let trees appear from 'nowhere' after removing bridge */
|
||||
if (IsNormalRoadTile(c) && GetRoadside(c) == ROADSIDE_TREES) {
|
||||
|
@ -38,6 +38,7 @@ void DrawWaterClassGround(const struct TileInfo *ti);
|
||||
void DrawShoreTile(Slope tileh);
|
||||
|
||||
void MakeWaterKeepingClass(TileIndex tile, Owner o);
|
||||
void CheckForDockingTile(TileIndex t);
|
||||
|
||||
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.
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "company_base.h"
|
||||
#include "company_gui.h"
|
||||
#include "newgrf_generic.h"
|
||||
#include "industry.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(tile2, _current_company, depot->index, DEPOT_PART_SOUTH, axis, wc2);
|
||||
CheckForDockingTile(tile);
|
||||
CheckForDockingTile(tile2);
|
||||
MarkTileDirtyByTile(tile);
|
||||
MarkTileDirtyByTile(tile2);
|
||||
MakeDefaultName(depot);
|
||||
@ -156,6 +159,48 @@ CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, ui
|
||||
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)
|
||||
{
|
||||
WaterClass wc = GetWaterClass(tile);
|
||||
@ -204,6 +249,7 @@ void MakeWaterKeepingClass(TileIndex tile, Owner o)
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (wc != WATER_CLASS_INVALID) CheckForDockingTile(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);
|
||||
CheckForDockingTile(tile - delta);
|
||||
CheckForDockingTile(tile + delta);
|
||||
MarkTileDirtyByTile(tile);
|
||||
MarkTileDirtyByTile(tile - delta);
|
||||
MarkTileDirtyByTile(tile + delta);
|
||||
@ -449,6 +497,7 @@ CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
||||
}
|
||||
MarkTileDirtyByTile(tile);
|
||||
MarkCanalsAndRiversAroundDirty(tile);
|
||||
CheckForDockingTile(tile);
|
||||
}
|
||||
|
||||
cost.AddCost(_price[PR_BUILD_CANAL]);
|
||||
@ -489,8 +538,10 @@ static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
|
||||
Company::Get(owner)->infrastructure.water--;
|
||||
DirtyCompanyInfrastructureWindows(owner);
|
||||
}
|
||||
bool remove = IsDockingTile(tile);
|
||||
DoClearSquare(tile);
|
||||
MarkCanalsAndRiversAroundDirty(tile);
|
||||
if (remove) RemoveDockingTile(tile);
|
||||
}
|
||||
|
||||
return CommandCost(EXPENSES_CONSTRUCTION, base_cost);
|
||||
@ -504,8 +555,10 @@ static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
bool remove = IsDockingTile(tile);
|
||||
DoClearSquare(tile);
|
||||
MarkCanalsAndRiversAroundDirty(tile);
|
||||
if (remove) RemoveDockingTile(tile);
|
||||
}
|
||||
if (IsSlopeWithOneCornerRaised(slope)) {
|
||||
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]);
|
||||
@ -1095,6 +1148,8 @@ void DoFloodTile(TileIndex target)
|
||||
|
||||
/* update signals if needed */
|
||||
UpdateSignalsInBuffer();
|
||||
|
||||
if (IsPossibleDockingTile(target)) CheckForDockingTile(target);
|
||||
}
|
||||
|
||||
cur_company.Restore();
|
||||
|
@ -69,6 +69,8 @@ enum LockPart {
|
||||
LOCK_PART_UPPER = 2, ///< Upper part of a lock.
|
||||
};
|
||||
|
||||
bool IsPossibleDockingTile(TileIndex t);
|
||||
|
||||
/**
|
||||
* Get the water tile type at a tile.
|
||||
* @param t Water tile to query.
|
||||
@ -346,6 +348,27 @@ static inline bool HasTileWaterGround(TileIndex 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.
|
||||
@ -356,6 +379,7 @@ static inline void MakeShore(TileIndex t)
|
||||
SetTileType(t, MP_WATER);
|
||||
SetTileOwner(t, OWNER_WATER);
|
||||
SetWaterClass(t, WATER_CLASS_SEA);
|
||||
SetDockingTile(t, false);
|
||||
_m[t].m2 = 0;
|
||||
_m[t].m3 = 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);
|
||||
SetTileOwner(t, o);
|
||||
SetWaterClass(t, wc);
|
||||
SetDockingTile(t, false);
|
||||
_m[t].m2 = 0;
|
||||
_m[t].m3 = 0;
|
||||
_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);
|
||||
SetTileOwner(t, o);
|
||||
SetWaterClass(t, original_water_class);
|
||||
SetDockingTile(t, false);
|
||||
_m[t].m2 = did;
|
||||
_m[t].m3 = 0;
|
||||
_m[t].m4 = 0;
|
||||
@ -451,6 +477,7 @@ static inline void MakeLockTile(TileIndex t, Owner o, LockPart part, DiagDirecti
|
||||
SetTileType(t, MP_WATER);
|
||||
SetTileOwner(t, o);
|
||||
SetWaterClass(t, original_water_class);
|
||||
SetDockingTile(t, false);
|
||||
_m[t].m2 = 0;
|
||||
_m[t].m3 = 0;
|
||||
_m[t].m4 = 0;
|
||||
|
@ -332,6 +332,7 @@ CommandCost CmdBuildBuoy(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
||||
if (wp->town == nullptr) MakeDefaultName(wp);
|
||||
|
||||
MakeBuoy(tile, wp->index, GetWaterClass(tile));
|
||||
CheckForDockingTile(tile);
|
||||
MarkTileDirtyByTile(tile);
|
||||
|
||||
wp->UpdateVirtCoord();
|
||||
|
Loading…
Reference in New Issue
Block a user