Allow drive-through road stops to be one-way
This commit is contained in:
@@ -892,6 +892,18 @@
|
|||||||
<li>m2: index into the array of stations</li>
|
<li>m2: index into the array of stations</li>
|
||||||
<li>m3 bits 7..4: persistent random data for railway stations/waypoints and airports)</li>
|
<li>m3 bits 7..4: persistent random data for railway stations/waypoints and airports)</li>
|
||||||
<li>m3 bits 7..4: <a href="#OwnershipInfo">owner</a> of tram tracks (road stop)</li>
|
<li>m3 bits 7..4: <a href="#OwnershipInfo">owner</a> of tram tracks (road stop)</li>
|
||||||
|
<li style="color: blue">m3 bits 1..0: bits to disallow vehicles to go a specific direction (drive-through road stop)
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td align=left>bit 0: </td>
|
||||||
|
<td>set = disallow driving in south-west or south-east direction</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=left>bit 1: </td>
|
||||||
|
<td>set = disallow driving in north-west or north-east direction</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</li>
|
||||||
<li>m4: custom station id; 0 means standard graphics</li>
|
<li>m4: custom station id; 0 means standard graphics</li>
|
||||||
<li>m4: <a href="#RoadType">Roadtype</a> for road stops</li>
|
<li>m4: <a href="#RoadType">Roadtype</a> for road stops</li>
|
||||||
<li>m5: graphics index (range from 0..255 for each station type):
|
<li>m5: graphics index (range from 0..255 for each station type):
|
||||||
|
@@ -238,7 +238,7 @@ the array so you can quickly see what is used and what is not.
|
|||||||
<td class="bits">-inherit-</td>
|
<td class="bits">-inherit-</td>
|
||||||
<td class="bits"><span class="free">O</span>XXX XXXX</td>
|
<td class="bits"><span class="free">O</span>XXX XXXX</td>
|
||||||
<td class="bits">-inherit-</td>
|
<td class="bits">-inherit-</td>
|
||||||
<td class="bits">XXXX <span class="free">OOOO</span></td>
|
<td class="bits">XXXX <span class="free">OO</span><span class="used_p">PP</span></td>
|
||||||
<td class="bits"><span class="free">OO</span>XX XXXX</td>
|
<td class="bits"><span class="free">OO</span>XX XXXX</td>
|
||||||
<td class="bits"><span class="option">~~~~ ~</span>XXX</td>
|
<td class="bits"><span class="option">~~~~ ~</span>XXX</td>
|
||||||
<td class="bits"><span class="free">OO</span>XX X<span class="free">OOO</span></td>
|
<td class="bits"><span class="free">OO</span>XX X<span class="free">OOO</span></td>
|
||||||
|
@@ -92,7 +92,7 @@ struct CFollowTrackT
|
|||||||
inline static TransportType TT() { return Ttr_type_; }
|
inline static TransportType TT() { return Ttr_type_; }
|
||||||
inline static bool IsWaterTT() { return TT() == TRANSPORT_WATER; }
|
inline static bool IsWaterTT() { return TT() == TRANSPORT_WATER; }
|
||||||
inline static bool IsRailTT() { return TT() == TRANSPORT_RAIL; }
|
inline static bool IsRailTT() { return TT() == TRANSPORT_RAIL; }
|
||||||
inline bool IsTram() { return IsRoadTT() && RoadTypeIsTram(RoadVehicle::From(m_veh)->roadtype); }
|
inline bool IsTram() const { return IsRoadTT() && RoadTypeIsTram(RoadVehicle::From(m_veh)->roadtype); }
|
||||||
inline static bool IsRoadTT() { return TT() == TRANSPORT_ROAD; }
|
inline static bool IsRoadTT() { return TT() == TRANSPORT_ROAD; }
|
||||||
inline static bool Allow90degTurns() { return T90deg_turns_allowed_; }
|
inline static bool Allow90degTurns() { return T90deg_turns_allowed_; }
|
||||||
inline static bool DoTrackMasking() { return Tmask_reserved_tracks; }
|
inline static bool DoTrackMasking() { return Tmask_reserved_tracks; }
|
||||||
|
@@ -369,7 +369,11 @@ static int32 NPFRoadPathCost(AyStar *as, AyStarNode *current, OpenListNode *pare
|
|||||||
/* When we're the first road stop in a 'queue' of them we increase
|
/* When we're the first road stop in a 'queue' of them we increase
|
||||||
* cost based on the fill percentage of the whole queue. */
|
* cost based on the fill percentage of the whole queue. */
|
||||||
const RoadStop::Entry *entry = rs->GetEntry(dir);
|
const RoadStop::Entry *entry = rs->GetEntry(dir);
|
||||||
cost += entry->GetOccupied() * _settings_game.pf.npf.npf_road_dt_occupied_penalty / entry->GetLength();
|
if (GetDriveThroughStopDisallowedRoadDirections(tile) != DRD_NONE) {
|
||||||
|
cost += (entry->GetOccupied() + rs->GetEntry(ReverseDiagDir(dir))->GetOccupied()) * _settings_game.pf.npf.npf_road_dt_occupied_penalty / (2 * entry->GetLength());
|
||||||
|
} else {
|
||||||
|
cost += entry->GetOccupied() * _settings_game.pf.npf.npf_road_dt_occupied_penalty / entry->GetLength();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Increase cost for filled road stops */
|
/* Increase cost for filled road stops */
|
||||||
|
@@ -68,7 +68,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** return one tile cost */
|
/** return one tile cost */
|
||||||
inline int OneTileCost(TileIndex tile, Trackdir trackdir)
|
inline int OneTileCost(TileIndex tile, Trackdir trackdir, const TrackFollower *tf)
|
||||||
{
|
{
|
||||||
int cost = 0;
|
int cost = 0;
|
||||||
|
|
||||||
@@ -101,7 +101,11 @@ protected:
|
|||||||
/* When we're the first road stop in a 'queue' of them we increase
|
/* When we're the first road stop in a 'queue' of them we increase
|
||||||
* cost based on the fill percentage of the whole queue. */
|
* cost based on the fill percentage of the whole queue. */
|
||||||
const RoadStop::Entry *entry = rs->GetEntry(dir);
|
const RoadStop::Entry *entry = rs->GetEntry(dir);
|
||||||
cost += entry->GetOccupied() * Yapf().PfGetSettings().road_stop_occupied_penalty / entry->GetLength();
|
if (GetDriveThroughStopDisallowedRoadDirections(tile) != DRD_NONE && !tf->IsTram()) {
|
||||||
|
cost += (entry->GetOccupied() + rs->GetEntry(ReverseDiagDir(dir))->GetOccupied()) * Yapf().PfGetSettings().road_stop_occupied_penalty / (2 * entry->GetLength());
|
||||||
|
} else {
|
||||||
|
cost += entry->GetOccupied() * Yapf().PfGetSettings().road_stop_occupied_penalty / entry->GetLength();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (predicted_occupied) {
|
if (predicted_occupied) {
|
||||||
@@ -153,7 +157,7 @@ public:
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* base tile cost depending on distance between edges */
|
/* base tile cost depending on distance between edges */
|
||||||
segment_cost += Yapf().OneTileCost(tile, trackdir);
|
segment_cost += Yapf().OneTileCost(tile, trackdir, tf);
|
||||||
|
|
||||||
const RoadVehicle *v = Yapf().GetVehicle();
|
const RoadVehicle *v = Yapf().GetVehicle();
|
||||||
/* we have reached the vehicle's destination - segment should end here to avoid target skipping */
|
/* we have reached the vehicle's destination - segment should end here to avoid target skipping */
|
||||||
|
@@ -37,6 +37,7 @@
|
|||||||
#include "genworld.h"
|
#include "genworld.h"
|
||||||
#include "company_gui.h"
|
#include "company_gui.h"
|
||||||
#include "road_func.h"
|
#include "road_func.h"
|
||||||
|
#include "roadstop_base.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
#include "table/roadtypes.h"
|
#include "table/roadtypes.h"
|
||||||
@@ -871,7 +872,38 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
|||||||
}
|
}
|
||||||
|
|
||||||
case MP_STATION: {
|
case MP_STATION: {
|
||||||
if ((GetAnyRoadBits(tile, rtt) & pieces) == pieces) return_cmd_error(STR_ERROR_ALREADY_BUILT);
|
if ((GetAnyRoadBits(tile, rtt) & pieces) == pieces) {
|
||||||
|
if (toggle_drd != DRD_NONE && rtt == RTT_ROAD && IsDriveThroughStopTile(tile)) {
|
||||||
|
Owner owner = GetRoadOwner(tile, rtt);
|
||||||
|
if (owner != OWNER_NONE) {
|
||||||
|
CommandCost ret = CheckOwnership(owner, tile);
|
||||||
|
if (ret.Failed()) return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisallowedRoadDirections dis_existing = GetDriveThroughStopDisallowedRoadDirections(tile);
|
||||||
|
DisallowedRoadDirections dis_new = dis_existing ^ toggle_drd;
|
||||||
|
|
||||||
|
/* We allow removing disallowed directions to break up
|
||||||
|
* deadlocks, but adding them can break articulated
|
||||||
|
* vehicles. As such, only when less is disallowed,
|
||||||
|
* i.e. bits are removed, we skip the vehicle check. */
|
||||||
|
if (CountBits(dis_existing) <= CountBits(dis_new)) {
|
||||||
|
CommandCost ret = EnsureNoVehicleOnGround(tile);
|
||||||
|
if (ret.Failed()) return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & DC_EXEC) {
|
||||||
|
RoadStop *rs = RoadStop::GetByTile(tile, GetRoadStopType(tile));
|
||||||
|
rs->ChangeDriveThroughDisallowedRoadDirections(dis_new);
|
||||||
|
MarkTileDirtyByTile(tile);
|
||||||
|
NotifyRoadLayoutChanged(CountBits(dis_existing) > CountBits(dis_new));
|
||||||
|
}
|
||||||
|
return CommandCost();
|
||||||
|
}
|
||||||
|
return_cmd_error(STR_ERROR_ALREADY_BUILT);
|
||||||
|
} else {
|
||||||
|
toggle_drd = DRD_NONE;
|
||||||
|
}
|
||||||
if (!IsDriveThroughStopTile(tile)) goto do_clear;
|
if (!IsDriveThroughStopTile(tile)) goto do_clear;
|
||||||
|
|
||||||
RoadBits curbits = AxisToRoadBits(DiagDirToAxis(GetRoadStopDir(tile)));
|
RoadBits curbits = AxisToRoadBits(DiagDirToAxis(GetRoadStopDir(tile)));
|
||||||
|
108
src/roadstop.cpp
108
src/roadstop.cpp
@@ -209,6 +209,103 @@ void RoadStop::ClearDriveThrough()
|
|||||||
this->west = nullptr;
|
this->west = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change disallowed road directions of this stop; update other neighbouring stops
|
||||||
|
* if needed. Also update the length etc.
|
||||||
|
*/
|
||||||
|
void RoadStop::ChangeDriveThroughDisallowedRoadDirections(DisallowedRoadDirections drd)
|
||||||
|
{
|
||||||
|
assert(this->east != nullptr && this->west != nullptr);
|
||||||
|
|
||||||
|
RoadStopType rst = GetRoadStopType(this->xy);
|
||||||
|
DiagDirection dir = GetRoadStopDir(this->xy);
|
||||||
|
/* Use absolute so we always go towards the northern tile */
|
||||||
|
TileIndexDiff offset = abs(TileOffsByDiagDir(dir));
|
||||||
|
|
||||||
|
/* Information about the tile north of us */
|
||||||
|
TileIndex north_tile = this->xy - offset;
|
||||||
|
bool north = IsDriveThroughRoadStopContinuation(this->xy, north_tile);
|
||||||
|
RoadStop *rs_north = north ? RoadStop::GetByTile(north_tile, rst) : nullptr;
|
||||||
|
|
||||||
|
/* Information about the tile south of us */
|
||||||
|
TileIndex south_tile = this->xy + offset;
|
||||||
|
bool south = IsDriveThroughRoadStopContinuation(this->xy, south_tile);
|
||||||
|
RoadStop *rs_south = south ? RoadStop::GetByTile(south_tile, rst) : nullptr;
|
||||||
|
|
||||||
|
/* Must only be changed after we determined which neighbours are
|
||||||
|
* part of our little entry 'queue' */
|
||||||
|
SetDriveThroughStopDisallowedRoadDirections(this->xy, drd);
|
||||||
|
|
||||||
|
if (north) {
|
||||||
|
/* There is a tile to the north, so we can't clear ourselves. */
|
||||||
|
if (south) {
|
||||||
|
/* There are more southern tiles too, they must be split;
|
||||||
|
* first make the new southern 'base' */
|
||||||
|
SetBit(rs_south->status, RSSFB_BASE_ENTRY);
|
||||||
|
rs_south->east = new Entry();
|
||||||
|
rs_south->west = new Entry();
|
||||||
|
|
||||||
|
/* Keep track of the base because we need it later on */
|
||||||
|
RoadStop *rs_south_base = rs_south;
|
||||||
|
TileIndex base_tile = south_tile;
|
||||||
|
|
||||||
|
/* Make all (even more) southern stops part of the new entry queue */
|
||||||
|
for (south_tile += offset; IsDriveThroughRoadStopContinuation(base_tile, south_tile); south_tile += offset) {
|
||||||
|
rs_south = RoadStop::GetByTile(south_tile, rst);
|
||||||
|
rs_south->east = rs_south_base->east;
|
||||||
|
rs_south->west = rs_south_base->west;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We have to rebuild the entries because we cannot easily determine
|
||||||
|
* how full each part is. So instead of keeping and maintaining a list
|
||||||
|
* of vehicles and using that to 'rebuild' the occupied state we just
|
||||||
|
* rebuild it from scratch as that removes lots of maintenance code
|
||||||
|
* for the vehicle list and it's faster in real games as long as you
|
||||||
|
* do not keep split and merge road stop every tick by the millions. */
|
||||||
|
rs_south_base->east->Rebuild(rs_south_base);
|
||||||
|
rs_south_base->west->Rebuild(rs_south_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the other end; the northern most tile */
|
||||||
|
TileIndex base_tile = north_tile;
|
||||||
|
for (north_tile -= offset; IsDriveThroughRoadStopContinuation(base_tile, north_tile); north_tile -= offset) {
|
||||||
|
rs_north = RoadStop::GetByTile(north_tile, rst);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(HasBit(rs_north->status, RSSFB_BASE_ENTRY));
|
||||||
|
rs_north->east->Rebuild(rs_north);
|
||||||
|
rs_north->west->Rebuild(rs_north);
|
||||||
|
} else if (south) {
|
||||||
|
/* There is only something to the south. Hand over the base entry */
|
||||||
|
SetBit(rs_south->status, RSSFB_BASE_ENTRY);
|
||||||
|
rs_south->east->Rebuild(rs_south);
|
||||||
|
rs_south->west->Rebuild(rs_south);
|
||||||
|
} else {
|
||||||
|
/* We were the last */
|
||||||
|
delete this->east;
|
||||||
|
delete this->west;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure we don't get used for something 'incorrect' */
|
||||||
|
ClrBit(this->status, RSSFB_BASE_ENTRY);
|
||||||
|
this->east = nullptr;
|
||||||
|
this->west = nullptr;
|
||||||
|
|
||||||
|
this->MakeDriveThrough();
|
||||||
|
|
||||||
|
/* Find the other end; the northern most tile */
|
||||||
|
TileIndex self_north = this->xy - offset;
|
||||||
|
RoadStop *rs_self = RoadStop::GetByTile(this->xy, rst);
|
||||||
|
for (; IsDriveThroughRoadStopContinuation(this->xy, self_north); self_north -= offset) {
|
||||||
|
rs_self = RoadStop::GetByTile(self_north, rst);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update occupancy of stop covering this tile */
|
||||||
|
assert(HasBit(rs_self->status, RSSFB_BASE_ENTRY));
|
||||||
|
rs_self->east->Rebuild(rs_self);
|
||||||
|
rs_self->west->Rebuild(rs_self);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Leave the road stop
|
* Leave the road stop
|
||||||
* @param rv the vehicle that leaves the stop
|
* @param rv the vehicle that leaves the stop
|
||||||
@@ -221,7 +318,7 @@ void RoadStop::Leave(RoadVehicle *rv)
|
|||||||
this->SetEntranceBusy(false);
|
this->SetEntranceBusy(false);
|
||||||
} else {
|
} else {
|
||||||
/* Otherwise just leave the drive through's entry cache. */
|
/* Otherwise just leave the drive through's entry cache. */
|
||||||
this->GetEntry(DirToDiagDir(rv->direction))->Leave(rv);
|
this->GetEntry(rv)->Leave(rv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +346,7 @@ bool RoadStop::Enter(RoadVehicle *rv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Vehicles entering a drive-through stop from the 'normal' side use first bay (bay 0). */
|
/* Vehicles entering a drive-through stop from the 'normal' side use first bay (bay 0). */
|
||||||
this->GetEntry(DirToDiagDir(rv->direction))->Enter(rv);
|
this->GetEntry(rv)->Enter(rv);
|
||||||
|
|
||||||
/* Indicate a drive-through stop */
|
/* Indicate a drive-through stop */
|
||||||
SetBit(rv->state, RVS_IN_DT_ROAD_STOP);
|
SetBit(rv->state, RVS_IN_DT_ROAD_STOP);
|
||||||
@@ -308,7 +405,8 @@ void RoadStop::Entry::Enter(const RoadVehicle *rv)
|
|||||||
GetStationIndex(next) == GetStationIndex(rs) &&
|
GetStationIndex(next) == GetStationIndex(rs) &&
|
||||||
GetStationType(next) == GetStationType(rs) &&
|
GetStationType(next) == GetStationType(rs) &&
|
||||||
GetRoadStopDir(next) == GetRoadStopDir(rs) &&
|
GetRoadStopDir(next) == GetRoadStopDir(rs) &&
|
||||||
IsDriveThroughStopTile(next);
|
IsDriveThroughStopTile(next) &&
|
||||||
|
GetDriveThroughStopDisallowedRoadDirections(next) == GetDriveThroughStopDisallowedRoadDirections(rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef std::list<const RoadVehicle *> RVList; ///< A list of road vehicles
|
typedef std::list<const RoadVehicle *> RVList; ///< A list of road vehicles
|
||||||
@@ -329,7 +427,9 @@ Vehicle *FindVehiclesInRoadStop(Vehicle *v, void *data)
|
|||||||
{
|
{
|
||||||
RoadStopEntryRebuilderHelper *rserh = (RoadStopEntryRebuilderHelper*)data;
|
RoadStopEntryRebuilderHelper *rserh = (RoadStopEntryRebuilderHelper*)data;
|
||||||
/* Not a RV or not in the right direction or crashed :( */
|
/* Not a RV or not in the right direction or crashed :( */
|
||||||
if (DirToDiagDir(v->direction) != rserh->dir || !v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0) return nullptr;
|
DiagDirection diag_dir = DirToDiagDir(v->direction);
|
||||||
|
if (RoadVehicle::From(v)->overtaking != 0) diag_dir = ReverseDiagDir(diag_dir);
|
||||||
|
if (diag_dir != rserh->dir || !v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0) return nullptr;
|
||||||
|
|
||||||
RoadVehicle *rv = RoadVehicle::From(v);
|
RoadVehicle *rv = RoadVehicle::From(v);
|
||||||
/* Don't add ones not in a road stop */
|
/* Don't add ones not in a road stop */
|
||||||
|
@@ -14,6 +14,8 @@
|
|||||||
#include "core/pool_type.hpp"
|
#include "core/pool_type.hpp"
|
||||||
#include "core/bitmath_func.hpp"
|
#include "core/bitmath_func.hpp"
|
||||||
#include "vehicle_type.h"
|
#include "vehicle_type.h"
|
||||||
|
#include "roadveh.h"
|
||||||
|
#include "road_map.h"
|
||||||
|
|
||||||
typedef Pool<RoadStop, RoadStopID, 32, 64000> RoadStopPool;
|
typedef Pool<RoadStop, RoadStopID, 32, 64000> RoadStopPool;
|
||||||
extern RoadStopPool _roadstop_pool;
|
extern RoadStopPool _roadstop_pool;
|
||||||
@@ -134,8 +136,19 @@ struct RoadStop : RoadStopPool::PoolItem<&_roadstop_pool> {
|
|||||||
return HasBit((int)dir, 1) ? this->west : this->east;
|
return HasBit((int)dir, 1) ? this->west : this->east;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const Entry *GetEntry(const RoadVehicle *rv) const {
|
||||||
|
DiagDirection diag_dir = DirToDiagDir(rv->direction);
|
||||||
|
return this->GetEntry(rv->overtaking != 0 ? ReverseDiagDir(diag_dir) : diag_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Entry *GetEntry(const RoadVehicle *rv) {
|
||||||
|
DiagDirection diag_dir = DirToDiagDir(rv->direction);
|
||||||
|
return this->GetEntry(rv->overtaking != 0 ? ReverseDiagDir(diag_dir) : diag_dir);
|
||||||
|
}
|
||||||
|
|
||||||
void MakeDriveThrough();
|
void MakeDriveThrough();
|
||||||
void ClearDriveThrough();
|
void ClearDriveThrough();
|
||||||
|
void ChangeDriveThroughDisallowedRoadDirections(DisallowedRoadDirections drd);
|
||||||
|
|
||||||
void Leave(RoadVehicle *rv);
|
void Leave(RoadVehicle *rv);
|
||||||
bool Enter(RoadVehicle *rv);
|
bool Enter(RoadVehicle *rv);
|
||||||
|
@@ -171,12 +171,7 @@ struct RoadVehicle FINAL : public GroundVehicle<RoadVehicle, VEH_ROAD> {
|
|||||||
return RV_OVERTAKE_TIMEOUT + (this->gcache.cached_total_length / 2) - (VEHICLE_LENGTH / 2);
|
return RV_OVERTAKE_TIMEOUT + (this->gcache.cached_total_length / 2) - (VEHICLE_LENGTH / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void SetRoadVehicleOvertaking(byte overtaking)
|
void SetRoadVehicleOvertaking(byte overtaking);
|
||||||
{
|
|
||||||
for (RoadVehicle *u = this; u != nullptr; u = u->Next()) {
|
|
||||||
u->overtaking = overtaking;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected: // These functions should not be called outside acceleration code.
|
protected: // These functions should not be called outside acceleration code.
|
||||||
|
|
||||||
|
@@ -373,6 +373,13 @@ bool RoadVehicle::FindClosestDepot(TileIndex *location, DestinationID *destinati
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool IsOneWayRoadTile(TileIndex tile)
|
||||||
|
{
|
||||||
|
if (IsNormalRoadTile(tile) && GetDisallowedRoadDirections(tile) != DRD_NONE) return true;
|
||||||
|
if (IsDriveThroughStopTile(tile) && GetDriveThroughStopDisallowedRoadDirections(tile) != DRD_NONE) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turn a roadvehicle around.
|
* Turn a roadvehicle around.
|
||||||
* @param tile unused
|
* @param tile unused
|
||||||
@@ -401,7 +408,7 @@ CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||||||
return CMD_ERROR;
|
return CMD_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) return CMD_ERROR;
|
if (IsOneWayRoadTile(v->tile)) return CMD_ERROR;
|
||||||
|
|
||||||
if (IsTileType(v->tile, MP_TUNNELBRIDGE) && DirToDiagDir(v->direction) == GetTunnelBridgeDirection(v->tile)) return CMD_ERROR;
|
if (IsTileType(v->tile, MP_TUNNELBRIDGE) && DirToDiagDir(v->direction) == GetTunnelBridgeDirection(v->tile)) return CMD_ERROR;
|
||||||
|
|
||||||
@@ -848,13 +855,7 @@ static Vehicle *EnumFindVehBlockingOvertake(Vehicle *v, void *data)
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static bool CheckRoadInfraUnsuitableForOvertaking(OvertakeData *od)
|
||||||
* Check if overtaking is possible on a piece of track
|
|
||||||
*
|
|
||||||
* @param od Information about the tile and the involved vehicles
|
|
||||||
* @return true if we have to abort overtaking
|
|
||||||
*/
|
|
||||||
static bool CheckRoadBlockedForOvertaking(OvertakeData *od)
|
|
||||||
{
|
{
|
||||||
if (!HasTileAnyRoadType(od->tile, od->v->compatible_roadtypes)) return true;
|
if (!HasTileAnyRoadType(od->tile, od->v->compatible_roadtypes)) return true;
|
||||||
TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, GetRoadTramType(od->v->roadtype));
|
TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, GetRoadTramType(od->v->roadtype));
|
||||||
@@ -865,22 +866,45 @@ static bool CheckRoadBlockedForOvertaking(OvertakeData *od)
|
|||||||
/* Track does not continue along overtaking direction || track has junction || levelcrossing is barred */
|
/* Track does not continue along overtaking direction || track has junction || levelcrossing is barred */
|
||||||
if (!HasBit(trackdirbits, od->trackdir) || (trackbits & ~TRACK_BIT_CROSS) || (red_signals != TRACKDIR_BIT_NONE)) return true;
|
if (!HasBit(trackdirbits, od->trackdir) || (trackbits & ~TRACK_BIT_CROSS) || (red_signals != TRACKDIR_BIT_NONE)) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if overtaking is possible on a piece of track
|
||||||
|
*
|
||||||
|
* @param od Information about the tile and the involved vehicles
|
||||||
|
* @return true if we have to abort overtaking
|
||||||
|
*/
|
||||||
|
static bool CheckRoadBlockedForOvertaking(OvertakeData *od)
|
||||||
|
{
|
||||||
/* Are there more vehicles on the tile except the two vehicles involved in overtaking */
|
/* Are there more vehicles on the tile except the two vehicles involved in overtaking */
|
||||||
return HasVehicleOnPos(od->tile, VEH_ROAD, od, EnumFindVehBlockingOvertake);
|
return HasVehicleOnPos(od->tile, VEH_ROAD, od, EnumFindVehBlockingOvertake);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if overtaking is possible on a piece of track
|
||||||
|
*
|
||||||
|
* @param od Information about the tile and the involved vehicles
|
||||||
|
* @return true if we have to abort overtaking
|
||||||
|
*/
|
||||||
|
static bool IsNonOvertakingStationTile(TileIndex tile, DiagDirection diag_dir)
|
||||||
|
{
|
||||||
|
if (!IsTileType(tile, MP_STATION)) return false;
|
||||||
|
if (!IsDriveThroughStopTile(tile)) return true;
|
||||||
|
const DisallowedRoadDirections diagdir_to_drd[DIAGDIR_END] = { DRD_NORTHBOUND, DRD_NORTHBOUND, DRD_SOUTHBOUND, DRD_SOUTHBOUND };
|
||||||
|
return GetDriveThroughStopDisallowedRoadDirections(tile) != diagdir_to_drd[diag_dir];
|
||||||
|
}
|
||||||
|
|
||||||
static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u)
|
static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u)
|
||||||
{
|
{
|
||||||
OvertakeData od;
|
|
||||||
|
|
||||||
od.v = v;
|
|
||||||
od.u = u;
|
|
||||||
|
|
||||||
/* Trams can't overtake other trams */
|
/* Trams can't overtake other trams */
|
||||||
if (RoadTypeIsTram(v->roadtype)) return;
|
if (RoadTypeIsTram(v->roadtype)) return;
|
||||||
|
|
||||||
|
/* Vehicles are not driving in same direction || direction is not a diagonal direction */
|
||||||
|
if (v->direction != u->direction || !(v->direction & 1)) return;
|
||||||
|
|
||||||
/* Don't overtake in stations */
|
/* Don't overtake in stations */
|
||||||
if (IsTileType(u->tile, MP_STATION)) return;
|
if (IsNonOvertakingStationTile(u->tile, DirToDiagDir(u->direction))) return;
|
||||||
|
|
||||||
/* If not permitted, articulated road vehicles can't overtake anything. */
|
/* If not permitted, articulated road vehicles can't overtake anything. */
|
||||||
if (!_settings_game.vehicle.roadveh_articulated_overtaking && v->HasArticulatedPart()) return;
|
if (!_settings_game.vehicle.roadveh_articulated_overtaking && v->HasArticulatedPart()) return;
|
||||||
@@ -888,21 +912,21 @@ static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u)
|
|||||||
/* Don't overtake if the vehicle is broken or about to break down */
|
/* Don't overtake if the vehicle is broken or about to break down */
|
||||||
if (v->breakdown_ctr != 0) return;
|
if (v->breakdown_ctr != 0) return;
|
||||||
|
|
||||||
/* Vehicles are not driving in same direction || direction is not a diagonal direction */
|
|
||||||
if (v->direction != u->direction || !(v->direction & 1)) return;
|
|
||||||
|
|
||||||
/* Vehicles chain is too long to overtake */
|
/* Vehicles chain is too long to overtake */
|
||||||
if (v->GetOvertakingCounterThreshold() > 255) return;
|
if (v->GetOvertakingCounterThreshold() > 255) return;
|
||||||
|
|
||||||
for (RoadVehicle *w = v; w != nullptr; w = w->Next()) {
|
for (RoadVehicle *w = v; w != nullptr; w = w->Next()) {
|
||||||
/* Don't overtake in stations */
|
/* Don't overtake in stations */
|
||||||
if (IsTileType(w->tile, MP_STATION)) return;
|
if (IsNonOvertakingStationTile(w->tile, DirToDiagDir(w->direction))) return;
|
||||||
|
|
||||||
/* Don't overtake if vehicle parts not all in same direction */
|
/* Don't overtake if vehicle parts not all in same direction */
|
||||||
if (w->direction != v->direction) return;
|
if (w->direction != v->direction) return;
|
||||||
|
|
||||||
/* Check if vehicle is in a road stop, depot, tunnel or bridge or not on a straight road */
|
/* Check if vehicle is in a road stop, depot, tunnel or bridge or not on a straight road */
|
||||||
if (w->state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir((Trackdir)(w->state & RVSB_TRACKDIR_MASK))) return;
|
if ((w->state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir((Trackdir)(w->state & RVSB_TRACKDIR_MASK))) &&
|
||||||
|
!IsInsideMM(w->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Can't overtake a vehicle that is moving faster than us. If the vehicle in front is
|
/* Can't overtake a vehicle that is moving faster than us. If the vehicle in front is
|
||||||
@@ -915,6 +939,9 @@ static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OvertakeData od;
|
||||||
|
od.v = v;
|
||||||
|
od.u = u;
|
||||||
od.trackdir = DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
|
od.trackdir = DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
|
||||||
|
|
||||||
/* Are the current and the next tile suitable for overtaking?
|
/* Are the current and the next tile suitable for overtaking?
|
||||||
@@ -928,12 +955,22 @@ static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u)
|
|||||||
TileIndexDiff check_tile_diff = TileOffsByDiagDir(DirToDiagDir(v->direction));
|
TileIndexDiff check_tile_diff = TileOffsByDiagDir(DirToDiagDir(v->direction));
|
||||||
for (; tile_count != 0; tile_count--, check_tile += check_tile_diff) {
|
for (; tile_count != 0; tile_count--, check_tile += check_tile_diff) {
|
||||||
od.tile = check_tile;
|
od.tile = check_tile;
|
||||||
|
if (CheckRoadInfraUnsuitableForOvertaking(&od)) return;
|
||||||
|
if (IsDriveThroughStopTile(check_tile) && GetDriveThroughStopDisallowedRoadDirections(check_tile) != DRD_NONE) {
|
||||||
|
const RoadStop *rs = RoadStop::GetByTile(check_tile, GetRoadStopType(check_tile));
|
||||||
|
DiagDirection dir = DirToDiagDir(v->direction);
|
||||||
|
const RoadStop::Entry *entry = rs->GetEntry(dir);
|
||||||
|
const RoadStop::Entry *opposite_entry = rs->GetEntry(ReverseDiagDir(dir));
|
||||||
|
if (entry->GetOccupied() < opposite_entry->GetOccupied()) return;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (CheckRoadBlockedForOvertaking(&od)) return;
|
if (CheckRoadBlockedForOvertaking(&od)) return;
|
||||||
}
|
}
|
||||||
tile_count = v->gcache.cached_total_length / TILE_SIZE;
|
tile_count = v->gcache.cached_total_length / TILE_SIZE;
|
||||||
check_tile = v->tile - check_tile_diff;
|
check_tile = v->tile - check_tile_diff;
|
||||||
for (; tile_count != 0; tile_count--, check_tile -= check_tile_diff) {
|
for (; tile_count != 0; tile_count--, check_tile -= check_tile_diff) {
|
||||||
od.tile = check_tile;
|
od.tile = check_tile;
|
||||||
|
if (CheckRoadInfraUnsuitableForOvertaking(&od)) return;
|
||||||
if (CheckRoadBlockedForOvertaking(&od)) return;
|
if (CheckRoadBlockedForOvertaking(&od)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1239,14 +1276,37 @@ static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadType rt, RoadB
|
|||||||
return ret.Succeeded();
|
return ret.Succeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool IsRoadVehicleOnOtherSideOfRoad(const RoadVehicle *v)
|
||||||
|
{
|
||||||
|
bool is_right;
|
||||||
|
switch (DirToDiagDir(v->direction)) {
|
||||||
|
case DIAGDIR_NE:
|
||||||
|
is_right = ((TILE_UNIT_MASK & v->y_pos) == 9);
|
||||||
|
break;
|
||||||
|
case DIAGDIR_SE:
|
||||||
|
is_right = ((TILE_UNIT_MASK & v->x_pos) == 9);
|
||||||
|
break;
|
||||||
|
case DIAGDIR_SW:
|
||||||
|
is_right = ((TILE_UNIT_MASK & v->y_pos) == 5);
|
||||||
|
break;
|
||||||
|
case DIAGDIR_NW:
|
||||||
|
is_right = ((TILE_UNIT_MASK & v->x_pos) == 5);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_right != (bool) _settings_game.vehicle.road_side;
|
||||||
|
}
|
||||||
|
|
||||||
bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
|
bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
|
||||||
{
|
{
|
||||||
SCOPE_INFO_FMT([&], "IndividualRoadVehicleController: %s, %s", scope_dumper().VehicleInfo(v), scope_dumper().VehicleInfo(prev));
|
SCOPE_INFO_FMT([&], "IndividualRoadVehicleController: %s, %s", scope_dumper().VehicleInfo(v), scope_dumper().VehicleInfo(prev));
|
||||||
if (v->overtaking != 0 && v->IsFrontEngine()) {
|
if (v->overtaking != 0 && v->IsFrontEngine()) {
|
||||||
if (IsTileType(v->tile, MP_STATION)) {
|
if (IsNonOvertakingStationTile(v->tile, DirToDiagDir(v->direction))) {
|
||||||
/* Force us to be not overtaking! */
|
/* Force us to be not overtaking! */
|
||||||
v->SetRoadVehicleOvertaking(0);
|
v->SetRoadVehicleOvertaking(0);
|
||||||
} else if (v->HasArticulatedPart() && (v->state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir((Trackdir)v->state))) {
|
} else if (v->HasArticulatedPart() && (v->state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir((Trackdir)v->state)) && !IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
|
||||||
/* Articulated RVs may not overtake on corners */
|
/* Articulated RVs may not overtake on corners */
|
||||||
v->SetRoadVehicleOvertaking(0);
|
v->SetRoadVehicleOvertaking(0);
|
||||||
} else if (v->HasArticulatedPart() && IsBridgeTile(v->tile) && (IsRoadCustomBridgeHeadTile(v->tile) || IsRoadCustomBridgeHeadTile(GetOtherBridgeEnd(v->tile)))) {
|
} else if (v->HasArticulatedPart() && IsBridgeTile(v->tile) && (IsRoadCustomBridgeHeadTile(v->tile) || IsRoadCustomBridgeHeadTile(GetOtherBridgeEnd(v->tile)))) {
|
||||||
@@ -1258,6 +1318,9 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
|
|||||||
* overtake if we are on straight roads */
|
* overtake if we are on straight roads */
|
||||||
if (v->overtaking_ctr >= v->GetOvertakingCounterThreshold() && v->state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->state)) {
|
if (v->overtaking_ctr >= v->GetOvertakingCounterThreshold() && v->state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->state)) {
|
||||||
v->SetRoadVehicleOvertaking(0);
|
v->SetRoadVehicleOvertaking(0);
|
||||||
|
} else if (v->overtaking_ctr == 0) {
|
||||||
|
/* prevent overflow issues */
|
||||||
|
v->overtaking_ctr = 255;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1396,7 +1459,7 @@ again:
|
|||||||
v->cur_speed = 0;
|
v->cur_speed = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) {
|
} else if (IsOneWayRoadTile(v->tile)) {
|
||||||
v->cur_speed = 0;
|
v->cur_speed = 0;
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
@@ -1572,14 +1635,17 @@ again:
|
|||||||
if (u != nullptr) {
|
if (u != nullptr) {
|
||||||
u = u->First();
|
u = u->First();
|
||||||
/* There is a vehicle in front overtake it if possible */
|
/* There is a vehicle in front overtake it if possible */
|
||||||
|
byte old_overtaking = v->overtaking;
|
||||||
if (v->overtaking == 0) RoadVehCheckOvertake(v, u);
|
if (v->overtaking == 0) RoadVehCheckOvertake(v, u);
|
||||||
if (v->overtaking == 0) v->cur_speed = u->cur_speed;
|
if (v->overtaking == old_overtaking) v->cur_speed = u->cur_speed;
|
||||||
|
|
||||||
/* In case an RV is stopped in a road stop, why not try to load? */
|
/* In case an RV is stopped in a road stop, why not try to load? */
|
||||||
if (v->cur_speed == 0 && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
|
if (v->cur_speed == 0 && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
|
||||||
v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile), false) &&
|
v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile), false) &&
|
||||||
IsInfraTileUsageAllowed(VEH_ROAD, v->owner, v->tile) && !v->current_order.IsType(OT_LEAVESTATION) &&
|
IsInfraTileUsageAllowed(VEH_ROAD, v->owner, v->tile) && !v->current_order.IsType(OT_LEAVESTATION) &&
|
||||||
GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK)) {
|
GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK)) {
|
||||||
|
byte cur_overtaking = IsRoadVehicleOnOtherSideOfRoad(v) ? RVSB_DRIVE_SIDE : 0;
|
||||||
|
if (cur_overtaking != v->overtaking) v->SetRoadVehicleOvertaking(cur_overtaking);
|
||||||
Station *st = Station::GetByTile(v->tile);
|
Station *st = Station::GetByTile(v->tile);
|
||||||
v->last_station_visited = st->index;
|
v->last_station_visited = st->index;
|
||||||
RoadVehArrivesAt(v, st);
|
RoadVehArrivesAt(v, st);
|
||||||
@@ -1787,6 +1853,17 @@ void RoadVehicle::SetDestTile(TileIndex tile)
|
|||||||
this->dest_tile = tile;
|
this->dest_tile = tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RoadVehicle::SetRoadVehicleOvertaking(byte overtaking)
|
||||||
|
{
|
||||||
|
if (IsInsideMM(this->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) RoadStop::GetByTile(this->tile, GetRoadStopType(this->tile))->Leave(this);
|
||||||
|
|
||||||
|
for (RoadVehicle *u = this; u != nullptr; u = u->Next()) {
|
||||||
|
u->overtaking = overtaking;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsInsideMM(this->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) RoadStop::GetByTile(this->tile, GetRoadStopType(this->tile))->Enter(this);
|
||||||
|
}
|
||||||
|
|
||||||
static void CheckIfRoadVehNeedsService(RoadVehicle *v)
|
static void CheckIfRoadVehNeedsService(RoadVehicle *v)
|
||||||
{
|
{
|
||||||
/* If we already got a slot at a stop, use that FIRST, and go to a depot later */
|
/* If we already got a slot at a stop, use that FIRST, and go to a depot later */
|
||||||
|
@@ -3787,6 +3787,14 @@ bool AfterLoadGame()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SlXvIsFeatureMissing(XSLFI_ONE_WAY_DT_ROAD_STOP)) {
|
||||||
|
for (TileIndex t = 0; t < map_size; t++) {
|
||||||
|
if (IsDriveThroughStopTile(t)) {
|
||||||
|
SetDriveThroughStopDisallowedRoadDirections(t, DRD_NONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
InitializeRoadGUI();
|
InitializeRoadGUI();
|
||||||
|
|
||||||
/* This needs to be done after conversion. */
|
/* This needs to be done after conversion. */
|
||||||
|
@@ -136,6 +136,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
|||||||
{ XSLFI_THROUGH_TRAIN_DEPOT, XSCF_NULL, 1, 1, "drive_through_train_depot", nullptr, nullptr, nullptr },
|
{ XSLFI_THROUGH_TRAIN_DEPOT, XSCF_NULL, 1, 1, "drive_through_train_depot", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_MORE_VEHICLE_ORDERS, XSCF_NULL, 1, 1, "more_veh_orders", nullptr, nullptr, nullptr },
|
{ XSLFI_MORE_VEHICLE_ORDERS, XSCF_NULL, 1, 1, "more_veh_orders", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_ORDER_FLAGS_EXTRA, XSCF_NULL, 1, 1, "order_flags_extra", nullptr, nullptr, nullptr },
|
{ XSLFI_ORDER_FLAGS_EXTRA, XSCF_NULL, 1, 1, "order_flags_extra", nullptr, nullptr, nullptr },
|
||||||
|
{ XSLFI_ONE_WAY_DT_ROAD_STOP, XSCF_NULL, 1, 1, "one_way_dt_road_stop", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker
|
{ XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -90,6 +90,7 @@ enum SlXvFeatureIndex {
|
|||||||
XSLFI_THROUGH_TRAIN_DEPOT, ///< Drive-through train depots
|
XSLFI_THROUGH_TRAIN_DEPOT, ///< Drive-through train depots
|
||||||
XSLFI_MORE_VEHICLE_ORDERS, ///< More vehicle orders - VehicleOrderID is 16 bits instead of 8
|
XSLFI_MORE_VEHICLE_ORDERS, ///< More vehicle orders - VehicleOrderID is 16 bits instead of 8
|
||||||
XSLFI_ORDER_FLAGS_EXTRA, ///< Order flags field extra size
|
XSLFI_ORDER_FLAGS_EXTRA, ///< Order flags field extra size
|
||||||
|
XSLFI_ONE_WAY_DT_ROAD_STOP, ///< One-way drive-through road stops
|
||||||
|
|
||||||
XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit
|
XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit
|
||||||
XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk
|
XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk
|
||||||
|
@@ -115,6 +115,7 @@
|
|||||||
uint dir_2 = 2 ^ dir_1;
|
uint dir_2 = 2 ^ dir_1;
|
||||||
|
|
||||||
DisallowedRoadDirections drd2 = IsNormalRoadTile(t2) ? GetDisallowedRoadDirections(t2) : DRD_NONE;
|
DisallowedRoadDirections drd2 = IsNormalRoadTile(t2) ? GetDisallowedRoadDirections(t2) : DRD_NONE;
|
||||||
|
if (IsDriveThroughStopTile(t2)) drd2 = GetDriveThroughStopDisallowedRoadDirections(t2);
|
||||||
|
|
||||||
return HasBit(r1, dir_1) && HasBit(r2, dir_2) && drd2 != DRD_BOTH && drd2 != (dir_1 > dir_2 ? DRD_SOUTHBOUND : DRD_NORTHBOUND);
|
return HasBit(r1, dir_1) && HasBit(r2, dir_2) && drd2 != DRD_BOTH && drd2 != (dir_1 > dir_2 ? DRD_SOUTHBOUND : DRD_NORTHBOUND);
|
||||||
}
|
}
|
||||||
|
@@ -1080,11 +1080,6 @@ static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags
|
|||||||
|
|
||||||
if (RoadTypeIsRoad(rt) && !HasPowerOnRoad(rt, road_rt)) return_cmd_error(STR_ERROR_NO_SUITABLE_ROAD);
|
if (RoadTypeIsRoad(rt) && !HasPowerOnRoad(rt, road_rt)) return_cmd_error(STR_ERROR_NO_SUITABLE_ROAD);
|
||||||
|
|
||||||
if (GetDisallowedRoadDirections(cur_tile) != DRD_NONE && road_owner != OWNER_TOWN) {
|
|
||||||
CommandCost ret = CheckOwnership(road_owner);
|
|
||||||
if (ret.Failed()) return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
cost.AddCost(RoadBuildCost(road_rt) * (2 - num_pieces));
|
cost.AddCost(RoadBuildCost(road_rt) * (2 - num_pieces));
|
||||||
} else if (RoadTypeIsRoad(rt)) {
|
} else if (RoadTypeIsRoad(rt)) {
|
||||||
cost.AddCost(RoadBuildCost(rt) * 2);
|
cost.AddCost(RoadBuildCost(rt) * 2);
|
||||||
@@ -2034,6 +2029,7 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
|
|||||||
RoadType tram_rt = MayHaveRoad(cur_tile) ? GetRoadType(cur_tile, RTT_TRAM) : INVALID_ROADTYPE;
|
RoadType tram_rt = MayHaveRoad(cur_tile) ? GetRoadType(cur_tile, RTT_TRAM) : INVALID_ROADTYPE;
|
||||||
Owner road_owner = road_rt != INVALID_ROADTYPE ? GetRoadOwner(cur_tile, RTT_ROAD) : _current_company;
|
Owner road_owner = road_rt != INVALID_ROADTYPE ? GetRoadOwner(cur_tile, RTT_ROAD) : _current_company;
|
||||||
Owner tram_owner = tram_rt != INVALID_ROADTYPE ? GetRoadOwner(cur_tile, RTT_TRAM) : _current_company;
|
Owner tram_owner = tram_rt != INVALID_ROADTYPE ? GetRoadOwner(cur_tile, RTT_TRAM) : _current_company;
|
||||||
|
DisallowedRoadDirections drd = IsNormalRoadTile(cur_tile) ? GetDisallowedRoadDirections(cur_tile) : DRD_NONE;
|
||||||
|
|
||||||
if (IsTileType(cur_tile, MP_STATION) && IsRoadStop(cur_tile)) {
|
if (IsTileType(cur_tile, MP_STATION) && IsRoadStop(cur_tile)) {
|
||||||
RemoveRoadStop(cur_tile, flags);
|
RemoveRoadStop(cur_tile, flags);
|
||||||
@@ -2071,6 +2067,7 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
|
|||||||
UpdateCompanyRoadInfrastructure(tram_rt, tram_owner, 2);
|
UpdateCompanyRoadInfrastructure(tram_rt, tram_owner, 2);
|
||||||
|
|
||||||
MakeDriveThroughRoadStop(cur_tile, st->owner, road_owner, tram_owner, st->index, rs_type, road_rt, tram_rt, axis);
|
MakeDriveThroughRoadStop(cur_tile, st->owner, road_owner, tram_owner, st->index, rs_type, road_rt, tram_rt, axis);
|
||||||
|
SetDriveThroughStopDisallowedRoadDirections(cur_tile, drd);
|
||||||
road_stop->MakeDriveThrough();
|
road_stop->MakeDriveThrough();
|
||||||
} else {
|
} else {
|
||||||
if (road_rt == INVALID_ROADTYPE && RoadTypeIsRoad(rt)) road_rt = rt;
|
if (road_rt == INVALID_ROADTYPE && RoadTypeIsRoad(rt)) road_rt = rt;
|
||||||
@@ -2246,6 +2243,7 @@ CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, ui
|
|||||||
RoadBits road_bits = ROAD_NONE;
|
RoadBits road_bits = ROAD_NONE;
|
||||||
RoadType road_type[] = { INVALID_ROADTYPE, INVALID_ROADTYPE };
|
RoadType road_type[] = { INVALID_ROADTYPE, INVALID_ROADTYPE };
|
||||||
Owner road_owner[] = { OWNER_NONE, OWNER_NONE };
|
Owner road_owner[] = { OWNER_NONE, OWNER_NONE };
|
||||||
|
DisallowedRoadDirections drd = DRD_NONE;
|
||||||
if (IsDriveThroughStopTile(cur_tile)) {
|
if (IsDriveThroughStopTile(cur_tile)) {
|
||||||
FOR_ALL_ROADTRAMTYPES(rtt) {
|
FOR_ALL_ROADTRAMTYPES(rtt) {
|
||||||
road_type[rtt] = GetRoadType(cur_tile, rtt);
|
road_type[rtt] = GetRoadType(cur_tile, rtt);
|
||||||
@@ -2255,6 +2253,7 @@ CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, ui
|
|||||||
if (!keep_drive_through_roads && road_owner[rtt] == _current_company) road_type[rtt] = INVALID_ROADTYPE;
|
if (!keep_drive_through_roads && road_owner[rtt] == _current_company) road_type[rtt] = INVALID_ROADTYPE;
|
||||||
}
|
}
|
||||||
road_bits = AxisToRoadBits(DiagDirToAxis(GetRoadStopDir(cur_tile)));
|
road_bits = AxisToRoadBits(DiagDirToAxis(GetRoadStopDir(cur_tile)));
|
||||||
|
drd = GetDriveThroughStopDisallowedRoadDirections(cur_tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandCost ret = RemoveRoadStop(cur_tile, flags);
|
CommandCost ret = RemoveRoadStop(cur_tile, flags);
|
||||||
@@ -2269,6 +2268,7 @@ CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, ui
|
|||||||
if ((flags & DC_EXEC) && (road_type[RTT_ROAD] != INVALID_ROADTYPE || road_type[RTT_TRAM] != INVALID_ROADTYPE)) {
|
if ((flags & DC_EXEC) && (road_type[RTT_ROAD] != INVALID_ROADTYPE || road_type[RTT_TRAM] != INVALID_ROADTYPE)) {
|
||||||
MakeRoadNormal(cur_tile, road_bits, road_type[RTT_ROAD], road_type[RTT_TRAM], ClosestTownFromTile(cur_tile, UINT_MAX)->index,
|
MakeRoadNormal(cur_tile, road_bits, road_type[RTT_ROAD], road_type[RTT_TRAM], ClosestTownFromTile(cur_tile, UINT_MAX)->index,
|
||||||
road_owner[RTT_ROAD], road_owner[RTT_TRAM]);
|
road_owner[RTT_ROAD], road_owner[RTT_TRAM]);
|
||||||
|
if (drd != DRD_NONE) SetDisallowedRoadDirections(cur_tile, drd);
|
||||||
|
|
||||||
/* Update company infrastructure counts. */
|
/* Update company infrastructure counts. */
|
||||||
int count = CountBits(road_bits);
|
int count = CountBits(road_bits);
|
||||||
@@ -3270,6 +3270,11 @@ draw_default_foundation:
|
|||||||
uint sprite_offset = axis == AXIS_X ? 1 : 0;
|
uint sprite_offset = axis == AXIS_X ? 1 : 0;
|
||||||
|
|
||||||
DrawRoadOverlays(ti, PAL_NONE, road_rti, tram_rti, sprite_offset, sprite_offset);
|
DrawRoadOverlays(ti, PAL_NONE, road_rti, tram_rti, sprite_offset, sprite_offset);
|
||||||
|
|
||||||
|
DisallowedRoadDirections drd = GetDriveThroughStopDisallowedRoadDirections(ti->tile);
|
||||||
|
if (drd != DRD_NONE) {
|
||||||
|
DrawGroundSpriteAt(SPR_ONEWAY_BASE + drd - 1 + ((axis == AXIS_X) ? 0 : 3), PAL_NONE, 8, 8, 0);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Non-drivethrough road stops are only valid for roads. */
|
/* Non-drivethrough road stops are only valid for roads. */
|
||||||
assert_tile(road_rt != INVALID_ROADTYPE && tram_rt == INVALID_ROADTYPE, ti->tile);
|
assert_tile(road_rt != INVALID_ROADTYPE && tram_rt == INVALID_ROADTYPE, ti->tile);
|
||||||
@@ -3460,23 +3465,24 @@ static void GetTileDesc_Station(TileIndex tile, TileDesc *td)
|
|||||||
|
|
||||||
static TrackStatus GetTileTrackStatus_Station(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
|
static TrackStatus GetTileTrackStatus_Station(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
|
||||||
{
|
{
|
||||||
TrackBits trackbits = TRACK_BIT_NONE;
|
TrackdirBits trackdirbits = TRACKDIR_BIT_NONE;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case TRANSPORT_RAIL:
|
case TRANSPORT_RAIL:
|
||||||
if (HasStationRail(tile) && !IsStationTileBlocked(tile)) {
|
if (HasStationRail(tile) && !IsStationTileBlocked(tile)) {
|
||||||
trackbits = TrackToTrackBits(GetRailStationTrack(tile));
|
trackdirbits = TrackToTrackdirBits(GetRailStationTrack(tile));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TRANSPORT_WATER:
|
case TRANSPORT_WATER:
|
||||||
/* buoy is coded as a station, it is always on open water */
|
/* buoy is coded as a station, it is always on open water */
|
||||||
if (IsBuoy(tile)) {
|
if (IsBuoy(tile)) {
|
||||||
trackbits = TRACK_BIT_ALL;
|
TrackBits trackbits = TRACK_BIT_ALL;
|
||||||
/* remove tracks that connect NE map edge */
|
/* remove tracks that connect NE map edge */
|
||||||
if (TileX(tile) == 0) trackbits &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
|
if (TileX(tile) == 0) trackbits &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
|
||||||
/* remove tracks that connect NW map edge */
|
/* remove tracks that connect NW map edge */
|
||||||
if (TileY(tile) == 0) trackbits &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
|
if (TileY(tile) == 0) trackbits &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
|
||||||
|
trackdirbits = TrackBitsToTrackdirBits(trackbits);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -3492,7 +3498,13 @@ static TrackStatus GetTileTrackStatus_Station(TileIndex tile, TransportType mode
|
|||||||
if (axis != DiagDirToAxis(side) || (IsStandardRoadStopTile(tile) && dir != side)) break;
|
if (axis != DiagDirToAxis(side) || (IsStandardRoadStopTile(tile) && dir != side)) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
trackbits = AxisToTrackBits(axis);
|
TrackBits trackbits = AxisToTrackBits(axis);
|
||||||
|
if (IsDriveThroughStopTile(tile)) {
|
||||||
|
const uint drd_to_multiplier[DRD_END] = { 0x101, 0x100, 0x1, 0x0 };
|
||||||
|
trackdirbits = (TrackdirBits)(trackbits * drd_to_multiplier[GetDriveThroughStopDisallowedRoadDirections(tile)]);
|
||||||
|
} else {
|
||||||
|
trackdirbits = TrackBitsToTrackdirBits(trackbits);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -3500,7 +3512,7 @@ static TrackStatus GetTileTrackStatus_Station(TileIndex tile, TransportType mode
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), TRACKDIR_BIT_NONE);
|
return CombineTrackStatus(trackdirbits, TRACKDIR_BIT_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -235,6 +235,29 @@ static inline bool IsDriveThroughStopTile(TileIndex t)
|
|||||||
return IsRoadStopTile(t) && GetStationGfx(t) >= GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET;
|
return IsRoadStopTile(t) && GetStationGfx(t) >= GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the disallowed directions
|
||||||
|
* @param t the tile to get the directions from
|
||||||
|
* @return the disallowed directions
|
||||||
|
*/
|
||||||
|
static inline DisallowedRoadDirections GetDriveThroughStopDisallowedRoadDirections(TileIndex t)
|
||||||
|
{
|
||||||
|
assert_tile(IsDriveThroughStopTile(t), t);
|
||||||
|
return (DisallowedRoadDirections)GB(_m[t].m3, 0, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the disallowed directions
|
||||||
|
* @param t the tile to set the directions for
|
||||||
|
* @param drd the disallowed directions
|
||||||
|
*/
|
||||||
|
static inline void SetDriveThroughStopDisallowedRoadDirections(TileIndex t, DisallowedRoadDirections drd)
|
||||||
|
{
|
||||||
|
assert_tile(IsDriveThroughStopTile(t), t);
|
||||||
|
assert(drd < DRD_END);
|
||||||
|
SB(_m[t].m3, 0, 2, drd);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the station graphics of this airport tile
|
* Get the station graphics of this airport tile
|
||||||
* @param t the tile to query
|
* @param t the tile to query
|
||||||
|
Reference in New Issue
Block a user