Add road tile cached one way state, one way road section detection
This commit is contained in:
@@ -124,10 +124,22 @@
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>
|
||||
<li style="color: blue">
|
||||
<a name="RailType"></a>
|
||||
Bits 11..6: Secondary Railtype. Used for some tiles with rail (rail, tunnelbridge). Used for lower or right track when two parallel tracks on tile.
|
||||
</li>
|
||||
<li style="color: blue">
|
||||
<a name="RoadCachedOneWayState"></a>
|
||||
Bits 14..12: Road cached one way state. Used for all tiles with road (road, station, tunnelbridge).
|
||||
<table border="1" style="width: 30em;">
|
||||
<tr><td style="width: 5em;"><tt>00</tt></td><td align=left>road is not one-way</td></tr>
|
||||
<tr><td><tt>01</tt></td><td align=left>road is one-way in 'A' direction</td></tr>
|
||||
<tr><td><tt>02</tt></td><td align=left>road is one-way in 'B' direction</td></tr>
|
||||
<tr><td><tt>03</tt></td><td align=left>road is disallowed in both directions</td></tr>
|
||||
<tr><td><tt>04</tt></td><td align=left>road is a one-way side junction</td></tr>
|
||||
<tr><td><tt>05</tt></td><td align=left>road is a one-way side junction, with no exit access</td></tr>
|
||||
</table>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><span style="font-weight: bold;">m7:</span><br>
|
||||
@@ -578,6 +590,7 @@
|
||||
<li>m3 bits 7..4: <a href="#OwnershipInfo">owner</a> of road type 1 (tram); OWNER_NONE (<tt>10</tt>) is stored as OWNER_TOWN (<tt>0F</tt>)
|
||||
<li>m4 bits 5..0: <a href="#RoadType">Roadtype</a></li>
|
||||
<li>m7 bit 5 set = on snow or desert</li>
|
||||
<li style="color: blue">m8 bits 14..12: <a href="#RoadCachedOneWayState">Road cached one way state</a></li>
|
||||
<li>m8 bits 11..6: <a href="#TramType">Tramtype</a></li>
|
||||
<li>m5 bits 7 clear: road or level-crossing
|
||||
<ul>
|
||||
@@ -1022,6 +1035,7 @@
|
||||
|
||||
<li>m7 bits 4..0: <a href="#OwnershipInfo">owner</a> of road (road stops)</li>
|
||||
<li>m7: animation frame (railway stations/waypoints, airports)</li>
|
||||
<li style="color: blue">m8 bits 14..12: <a href="#RoadCachedOneWayState">Road cached one way state</a></li>
|
||||
<li>m8 bits 11..6: <a href="#TramType">Tramtype</a></li>
|
||||
<li>m8 bits 5..0: <a href="#TrackType">track type</a> for railway stations/waypoints</li>
|
||||
</ul>
|
||||
@@ -1812,6 +1826,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
<li style="color: blue">m8 bits 14..12: <a href="#RoadCachedOneWayState">Road cached one way state</a></li>
|
||||
<li>m8 bits 11..6: <a href="#TramType">Tramtype</a></li>
|
||||
<li>m8 bits 5..0: <a href="#TrackType">track type</a> for railway</li>
|
||||
<li style="color: blue">m8 bits 11..6 = <a name="TrackType">secondary track type</a> for railway (used for bridge-bypassing track when two parallel tracks on custom bridge head)</li>
|
||||
|
@@ -149,7 +149,7 @@ the array so you can quickly see what is used and what is not.
|
||||
<td class="bits">XXXX XXXX</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>X<span class="free">O</span> XXXX</td>
|
||||
<td class="bits"><span class="free">OOOO</span> XXXX XX<span class="free">OO OOOO</span></td>
|
||||
<td class="bits"><span class="free">O</span><span class="used_p">PPP</span> XXXX XX<span class="free">OO OOOO</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="caption">level crossing</td>
|
||||
@@ -162,7 +162,7 @@ the array so you can quickly see what is used and what is not.
|
||||
<td class="bits">XXXX <span class="free">OO</span><span class="used_p">P</span>X</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 XXXX</td>
|
||||
<td class="bits"><span class="free">OOOO</span> XXXX XXXX XXXX</td>
|
||||
<td class="bits"><span class="free">O<span class="used_p">PPP</span></span> XXXX XXXX XXXX</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="caption">road depot</td>
|
||||
@@ -243,7 +243,7 @@ the array so you can quickly see what is used and what is not.
|
||||
<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">OOO</span>X XXXX</td>
|
||||
<td class="bits"><span class="free">OOOO</span> XXXX XX<span class="free">OO OOOO</span></td>
|
||||
<td class="bits"><span class="free">O<span class="used_p">PPP</span></span> XXXX XX<span class="free">OO OOOO</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="caption">dock</td>
|
||||
@@ -363,7 +363,7 @@ the array so you can quickly see what is used and what is not.
|
||||
<td class="bits">X<span class="free">OO</span>X XXXX</td>
|
||||
<td class="bits"><span class="used_p">PP</span><span class="free">OO OO</span><span class="used_p">PP</span></td>
|
||||
<td class="bits"><span class="used_p">PP</span>XX XXXX</td>
|
||||
<td class="bits"><span class="free">OOOO</span> XXXX XXXX XXXX</td>
|
||||
<td class="bits"><span class="free">O<span class="used_p">PPP</span></span> XXXX XXXX XXXX</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>bridge ramp</td>
|
||||
@@ -376,7 +376,7 @@ the array so you can quickly see what is used and what is not.
|
||||
<td class="bits">-inherit-</td>
|
||||
<td class="bits"><span class="free"></span><span class="used_p">PP</span>XX XX<span class="used_p">PP</span></td>
|
||||
<td class="bits">-inherit-</td>
|
||||
<td class="bits"><span class="free">OOOO</span> <span class="abuse">PPPP PP</span>XX XXXX</td>
|
||||
<td class="bits"><span class="free">O<span class="used_p">PPP</span></span> <span class="abuse">PPPP PP</span>XX XXXX</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan=2>A</td>
|
||||
|
@@ -2419,6 +2419,19 @@ DEF_CONSOLE_CMD(ConCSleep)
|
||||
return true;
|
||||
}
|
||||
|
||||
DEF_CONSOLE_CMD(ConRecalculateRoadCachedOneWayStates)
|
||||
{
|
||||
if (argc == 0) {
|
||||
IConsoleHelp("Debug: Recalculate road cached one way states");
|
||||
return true;
|
||||
}
|
||||
|
||||
extern void RecalculateRoadCachedOneWayStates();
|
||||
RecalculateRoadCachedOneWayStates();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DEF_CONSOLE_CMD(ConDoDisaster)
|
||||
{
|
||||
if (argc == 0) {
|
||||
@@ -2847,6 +2860,7 @@ void IConsoleStdLibRegister()
|
||||
IConsoleCmdRegister("viewport_mark_dirty_st_overlay", ConViewportMarkStationOverlayDirty, nullptr, true);
|
||||
IConsoleCmdRegister("gfx_debug", ConGfxDebug, nullptr, true);
|
||||
IConsoleCmdRegister("csleep", ConCSleep, nullptr, true);
|
||||
IConsoleCmdRegister("recalculate_road_cached_one_way_states", ConRecalculateRoadCachedOneWayStates, ConHookNoNetwork, true);
|
||||
|
||||
/* NewGRF development stuff */
|
||||
IConsoleCmdRegister("reload_newgrfs", ConNewGRFReload, ConHookNewGRFDeveloperTool);
|
||||
|
@@ -739,6 +739,7 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||
Company::Get(tram_owner)->infrastructure.road[roadtype_tram] += num_new_tram_pieces;
|
||||
DirtyCompanyInfrastructureWindows(tram_owner);
|
||||
}
|
||||
UpdateRoadCachedOneWayStatesAroundTile(tile);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -847,6 +848,7 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
DirtyCompanyInfrastructureWindows(owner);
|
||||
MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypeRoad(tile), GetRoadTypeTram(tile), GetTownIndex(tile), GetRoadOwner(tile, RTT_ROAD), GetRoadOwner(tile, RTT_TRAM));
|
||||
DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile);
|
||||
UpdateRoadCachedOneWayStatesAroundTile(tile);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
294
src/road_cmd.cpp
294
src/road_cmd.cpp
@@ -38,6 +38,7 @@
|
||||
#include "company_gui.h"
|
||||
#include "road_func.h"
|
||||
#include "roadstop_base.h"
|
||||
#include "scope.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
#include "table/roadtypes.h"
|
||||
@@ -187,6 +188,229 @@ bool RoadVehiclesAreBuilt()
|
||||
return !RoadVehicle::Iterate().empty();
|
||||
}
|
||||
|
||||
static DisallowedRoadDirections GetOneWayRoadTileDisallowedRoadDirections(TileIndex tile)
|
||||
{
|
||||
if (IsNormalRoadTile(tile)) return GetDisallowedRoadDirections(tile);
|
||||
if (IsDriveThroughStopTile(tile)) return GetDriveThroughStopDisallowedRoadDirections(tile);
|
||||
return DRD_NONE;
|
||||
}
|
||||
|
||||
static DiagDirection OneWaySideJunctionRoadRoadBitsToDiagDir(RoadBits bits)
|
||||
{
|
||||
/*
|
||||
* Drive on left missing bit:
|
||||
* ROAD_SE (bit 2) -> DIAGDIR_NE (0)
|
||||
* ROAD_SW (bit 1) -> DIAGDIR_SE (1)
|
||||
* ROAD_NW (bit 0) -> DIAGDIR_SW (2)
|
||||
* ROAD_NE (bit 3) -> DIAGDIR_NW (3)
|
||||
*/
|
||||
uint8 bit = FIND_FIRST_BIT(bits ^ ROAD_ALL);
|
||||
bit ^= 3;
|
||||
return (DiagDirection)((bit + 3 + (_settings_game.vehicle.road_side * 2)) % 4);
|
||||
}
|
||||
|
||||
inline bool IsOneWaySideJunctionRoadDRDsPresent(TileIndex tile, DiagDirection dir)
|
||||
{
|
||||
const DisallowedRoadDirections diagdir_to_drd[DIAGDIR_END] = { DRD_NORTHBOUND, DRD_NORTHBOUND, DRD_SOUTHBOUND, DRD_SOUTHBOUND };
|
||||
|
||||
TileIndexDiffC ti = TileIndexDiffCByDiagDir(dir);
|
||||
TileIndex ahead = AddTileIndexDiffCWrap(tile, ti);
|
||||
if (ahead == INVALID_TILE || GetOneWayRoadTileDisallowedRoadDirections(ahead) != diagdir_to_drd[dir]) return false;
|
||||
TileIndex behind = AddTileIndexDiffCWrap(tile, { (int16)(-ti.x), (int16)(-ti.y) });
|
||||
if (behind == INVALID_TILE || GetOneWayRoadTileDisallowedRoadDirections(behind) != diagdir_to_drd[dir]) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static btree::btree_set<TileIndex> _road_cache_one_way_state_pending_tiles;
|
||||
static btree::btree_set<TileIndex> _road_cache_one_way_state_pending_interpolate_tiles;
|
||||
static bool _defer_update_road_cache_one_way_state = false;
|
||||
bool _mark_tile_dirty_on_road_cache_one_way_state_update = false;
|
||||
|
||||
static void UpdateTileRoadCachedOneWayState(TileIndex tile)
|
||||
{
|
||||
if (unlikely(_mark_tile_dirty_on_road_cache_one_way_state_update)) MarkTileGroundDirtyByTile(tile, VMDF_NOT_MAP_MODE);
|
||||
|
||||
DisallowedRoadDirections drd = GetOneWayRoadTileDisallowedRoadDirections(tile);
|
||||
if (drd != DRD_NONE) {
|
||||
SetRoadCachedOneWayState(tile, (RoadCachedOneWayState)drd);
|
||||
return;
|
||||
}
|
||||
if (IsNormalRoadTile(tile)) {
|
||||
RoadBits bits = GetRoadBits(tile, RTT_ROAD);
|
||||
if (HasExactlyOneBit(bits ^ ROAD_ALL)) {
|
||||
DiagDirection dir = OneWaySideJunctionRoadRoadBitsToDiagDir(bits);
|
||||
if (IsOneWaySideJunctionRoadDRDsPresent(tile, dir)) {
|
||||
DiagDirection side_dir = (DiagDirection)((dir + 3 + (_settings_game.vehicle.road_side * 2)) % 4);
|
||||
TileIndexDiffC ti = TileIndexDiffCByDiagDir(side_dir);
|
||||
TileIndex side = AddTileIndexDiffCWrap(tile, ti);
|
||||
|
||||
const DisallowedRoadDirections diagdir_to_drd[DIAGDIR_END] = { DRD_SOUTHBOUND, DRD_SOUTHBOUND, DRD_NORTHBOUND, DRD_NORTHBOUND };
|
||||
SetRoadCachedOneWayState(tile, (GetOneWayRoadTileDisallowedRoadDirections(side) & diagdir_to_drd[side_dir]) ? RCOWS_SIDE_JUNCTION_NO_EXIT : RCOWS_SIDE_JUNCTION);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!IsTileType(tile, MP_STATION)) _road_cache_one_way_state_pending_interpolate_tiles.insert(tile);
|
||||
SetRoadCachedOneWayState(tile, RCOWS_NORMAL);
|
||||
}
|
||||
|
||||
/* Do not re-order, see: RoadCachedOneWayState */
|
||||
enum InterpolateRoadResult {
|
||||
IRR_NONE,
|
||||
IRR_OUT,
|
||||
IRR_IN
|
||||
};
|
||||
|
||||
static TileIndex InterpolateRoadFollowTileStep(TileIndex tile, uint8 bit)
|
||||
{
|
||||
DiagDirection outgoing = (DiagDirection)(bit ^ 3);
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(tile) == outgoing) {
|
||||
return GetOtherTunnelBridgeEnd(tile);
|
||||
}
|
||||
TileIndexDiffC ti = TileIndexDiffCByDiagDir(outgoing);
|
||||
TileIndex next = AddTileIndexDiffCWrap(tile, ti);
|
||||
if (next == INVALID_TILE) return INVALID_TILE;
|
||||
if (IsTileType(next, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(next) == ReverseDiagDir(outgoing)) {
|
||||
return INVALID_TILE;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
static InterpolateRoadResult InterpolateRoadFollowRoadBit(TileIndex tile, uint8 bit)
|
||||
{
|
||||
const TileIndex start = tile;
|
||||
do {
|
||||
TileIndex next = InterpolateRoadFollowTileStep(tile, bit);
|
||||
if (next == INVALID_TILE) return IRR_NONE;
|
||||
DisallowedRoadDirections drd = GetOneWayRoadTileDisallowedRoadDirections(next);
|
||||
if (drd == DRD_BOTH) return IRR_NONE;
|
||||
if (drd != DRD_NONE) {
|
||||
const DisallowedRoadDirections outgoing_drd_by_exit_bit[4] = { DRD_SOUTHBOUND, DRD_SOUTHBOUND, DRD_NORTHBOUND, DRD_NORTHBOUND };
|
||||
return outgoing_drd_by_exit_bit[bit] == drd ? IRR_OUT : IRR_IN;
|
||||
}
|
||||
if (IsTileType(next, MP_STATION)) return IRR_NONE;
|
||||
RoadBits incoming = (RoadBits)(1 << (bit ^ 2));
|
||||
RoadBits rb = GetAnyRoadBits(next, RTT_ROAD, true);
|
||||
if ((incoming & rb) == 0) return IRR_NONE;
|
||||
RoadBits remaining = rb & ~incoming;
|
||||
if (!HasExactlyOneBit(remaining)) return IRR_NONE;
|
||||
tile = next;
|
||||
bit = FIND_FIRST_BIT(remaining);
|
||||
} while (tile != start);
|
||||
return IRR_NONE;
|
||||
}
|
||||
|
||||
static void InterpolateRoadFollowRoadBitSetState(TileIndex tile, uint8 bit, InterpolateRoadResult irr)
|
||||
{
|
||||
const TileIndex start = tile;
|
||||
do {
|
||||
if (irr == IRR_NONE) {
|
||||
SetRoadCachedOneWayState(tile, RCOWS_NORMAL);
|
||||
} else {
|
||||
uint8 inbit = FIND_FIRST_BIT(GetAnyRoadBits(tile, RTT_ROAD, true) & ~(1 << bit));
|
||||
/* inbit bit piece Outgoing Trackdir IRR_IN case
|
||||
*
|
||||
* 0 1 ROAD_W TRACKDIR_LEFT_S RCOWS_NON_JUNCTION_A
|
||||
* 0 2 ROAD_Y TRACKDIR_Y_SE RCOWS_NON_JUNCTION_A
|
||||
* 0 3 ROAD_N TRACKDIR_UPPER_E RCOWS_NON_JUNCTION_A
|
||||
*
|
||||
* 1 0 ROAD_W TRACKDIR_LEFT_N RCOWS_NON_JUNCTION_B
|
||||
* 1 2 ROAD_S TRACKDIR_LOWER_E RCOWS_NON_JUNCTION_A
|
||||
* 1 3 ROAD_X TRACKDIR_X_NE RCOWS_NON_JUNCTION_A
|
||||
*
|
||||
* 2 0 ROAD_Y TRACKDIR_Y_NW RCOWS_NON_JUNCTION_B
|
||||
* 2 1 ROAD_S TRACKDIR_LOWER_W RCOWS_NON_JUNCTION_B
|
||||
* 2 3 ROAD_E TRACKDIR_RIGHT_N RCOWS_NON_JUNCTION_B
|
||||
*
|
||||
* 3 0 ROAD_N TRACKDIR_UPPER_W RCOWS_NON_JUNCTION_B
|
||||
* 3 1 ROAD_X TRACKDIR_X_SW RCOWS_NON_JUNCTION_B
|
||||
* 3 2 ROAD_E TRACKDIR_RIGHT_S RCOWS_NON_JUNCTION_A
|
||||
*/
|
||||
|
||||
const uint16 bits_to_rcows = 0x3B10;
|
||||
SetRoadCachedOneWayState(tile, (RoadCachedOneWayState)(irr ^ (HasBit(bits_to_rcows, (inbit << 2) | bit) ? 0 : 3)));
|
||||
}
|
||||
_road_cache_one_way_state_pending_interpolate_tiles.erase(tile);
|
||||
if (unlikely(_mark_tile_dirty_on_road_cache_one_way_state_update)) MarkTileGroundDirtyByTile(tile, VMDF_NOT_MAP_MODE);
|
||||
TileIndex next = InterpolateRoadFollowTileStep(tile, bit);
|
||||
if (next == INVALID_TILE) return;
|
||||
DisallowedRoadDirections drd = GetOneWayRoadTileDisallowedRoadDirections(next);
|
||||
if (drd != DRD_NONE) {
|
||||
return;
|
||||
}
|
||||
if (IsTileType(next, MP_STATION)) return;
|
||||
RoadBits incoming = (RoadBits)(1 << (bit ^ 2));
|
||||
RoadBits rb = GetAnyRoadBits(next, RTT_ROAD, true);
|
||||
if ((incoming & rb) == 0) return;
|
||||
RoadBits remaining = rb & ~incoming;
|
||||
if (!HasExactlyOneBit(remaining)) return;
|
||||
tile = next;
|
||||
bit = FIND_FIRST_BIT(remaining);
|
||||
} while (tile != start);
|
||||
}
|
||||
|
||||
static void InterpolateRoadCachedOneWayStates()
|
||||
{
|
||||
while (!_road_cache_one_way_state_pending_interpolate_tiles.empty()) {
|
||||
auto iter = _road_cache_one_way_state_pending_interpolate_tiles.begin();
|
||||
TileIndex tile = *iter;
|
||||
_road_cache_one_way_state_pending_interpolate_tiles.erase(iter);
|
||||
|
||||
const RoadBits bits = GetAnyRoadBits(tile, RTT_ROAD, true);
|
||||
if (CountBits(bits) != 2) continue;
|
||||
|
||||
uint8 first_bit = FIND_FIRST_BIT(bits);
|
||||
uint8 second_bit = FIND_FIRST_BIT(KillFirstBit(bits));
|
||||
InterpolateRoadResult first_irr = InterpolateRoadFollowRoadBit(tile, first_bit);
|
||||
InterpolateRoadResult second_irr = first_irr;
|
||||
if (first_irr != IRR_NONE) {
|
||||
second_irr = InterpolateRoadFollowRoadBit(tile, second_bit);
|
||||
if (second_irr == IRR_NONE || second_irr == first_irr) first_irr = second_irr = IRR_NONE;
|
||||
}
|
||||
InterpolateRoadFollowRoadBitSetState(tile, first_bit, first_irr);
|
||||
InterpolateRoadFollowRoadBitSetState(tile, second_bit, second_irr);
|
||||
}
|
||||
}
|
||||
|
||||
void RecalculateRoadCachedOneWayStates()
|
||||
{
|
||||
for (TileIndex tile = 0; tile != MapSize(); tile++) {
|
||||
if (MayHaveRoad(tile)) UpdateTileRoadCachedOneWayState(tile);
|
||||
}
|
||||
InterpolateRoadCachedOneWayStates();
|
||||
}
|
||||
|
||||
void UpdateRoadCachedOneWayStatesAroundTile(TileIndex tile)
|
||||
{
|
||||
if (_generating_world) return;
|
||||
|
||||
auto check_tile = [](TileIndex t) {
|
||||
if (_defer_update_road_cache_one_way_state) {
|
||||
_road_cache_one_way_state_pending_tiles.insert(t);
|
||||
} else if (MayHaveRoad(t)) {
|
||||
UpdateTileRoadCachedOneWayState(t);
|
||||
}
|
||||
};
|
||||
check_tile(tile);
|
||||
uint x_offset = TileXY(1, 0);
|
||||
if (tile >= x_offset) check_tile(tile - x_offset);
|
||||
if (tile + x_offset < MapSize()) check_tile(tile + x_offset);
|
||||
uint y_offset = TileXY(0, 1);
|
||||
if (tile >= y_offset) check_tile(tile - y_offset);
|
||||
if (tile + y_offset < MapSize()) check_tile(tile + y_offset);
|
||||
if (!_defer_update_road_cache_one_way_state) InterpolateRoadCachedOneWayStates();
|
||||
}
|
||||
|
||||
void FlushDeferredUpdateRoadCachedOneWayStates()
|
||||
{
|
||||
_defer_update_road_cache_one_way_state = false;
|
||||
for (TileIndex t : _road_cache_one_way_state_pending_tiles) {
|
||||
if (MayHaveRoad(t)) UpdateTileRoadCachedOneWayState(t);
|
||||
}
|
||||
_road_cache_one_way_state_pending_tiles.clear();
|
||||
InterpolateRoadCachedOneWayStates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update road infrastructure counts for a company.
|
||||
* @param rt Road type to update count of.
|
||||
@@ -470,6 +694,10 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec
|
||||
|
||||
/* Todo: Change this to be more fine-grained if necessary */
|
||||
NotifyRoadLayoutChanged(false);
|
||||
if (rtt == RTT_ROAD) {
|
||||
UpdateRoadCachedOneWayStatesAroundTile(tile);
|
||||
UpdateRoadCachedOneWayStatesAroundTile(other_end);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assert_tile(IsDriveThroughStopTile(tile), tile);
|
||||
@@ -480,6 +708,9 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec
|
||||
SetRoadType(tile, rtt, INVALID_ROADTYPE);
|
||||
MarkTileDirtyByTile(tile);
|
||||
NotifyRoadLayoutChanged(false);
|
||||
if (rtt == RTT_ROAD) {
|
||||
UpdateRoadCachedOneWayStatesAroundTile(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
return cost;
|
||||
@@ -558,6 +789,9 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec
|
||||
SetRoadBits(tile, present, rtt);
|
||||
MarkTileDirtyByTile(tile);
|
||||
}
|
||||
if (rtt == RTT_ROAD) {
|
||||
UpdateRoadCachedOneWayStatesAroundTile(tile);
|
||||
}
|
||||
}
|
||||
|
||||
CommandCost cost(EXPENSES_CONSTRUCTION, CountBits(pieces) * RoadClearCost(existing_rt));
|
||||
@@ -596,6 +830,9 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec
|
||||
}
|
||||
MarkTileDirtyByTile(tile);
|
||||
YapfNotifyTrackLayoutChange(tile, railtrack);
|
||||
if (rtt == RTT_ROAD) {
|
||||
UpdateRoadCachedOneWayStatesAroundTile(tile);
|
||||
}
|
||||
}
|
||||
return CommandCost(EXPENSES_CONSTRUCTION, RoadClearCost(existing_rt) * 2);
|
||||
}
|
||||
@@ -771,6 +1008,7 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
||||
SetDisallowedRoadDirections(tile, dis_new);
|
||||
MarkTileDirtyByTile(tile);
|
||||
NotifyRoadLayoutChanged(CountBits(dis_existing) > CountBits(dis_new));
|
||||
UpdateRoadCachedOneWayStatesAroundTile(tile);
|
||||
}
|
||||
return CommandCost();
|
||||
}
|
||||
@@ -866,6 +1104,9 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
||||
SetCrossingReservation(tile, reserved);
|
||||
UpdateLevelCrossing(tile, false);
|
||||
if (RoadLayoutChangeNotificationEnabled(true)) NotifyRoadLayoutChangedIfTileNonLeaf(tile, rtt, GetCrossingRoadBits(tile));
|
||||
if (rtt == RTT_ROAD) {
|
||||
UpdateRoadCachedOneWayStatesAroundTile(tile);
|
||||
}
|
||||
MarkTileDirtyByTile(tile);
|
||||
}
|
||||
return CommandCost(EXPENSES_CONSTRUCTION, 2 * RoadBuildCost(rt));
|
||||
@@ -897,6 +1138,7 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
||||
rs->ChangeDriveThroughDisallowedRoadDirections(dis_new);
|
||||
MarkTileDirtyByTile(tile);
|
||||
NotifyRoadLayoutChanged(CountBits(dis_existing) > CountBits(dis_new));
|
||||
UpdateRoadCachedOneWayStatesAroundTile(tile);
|
||||
}
|
||||
return CommandCost();
|
||||
}
|
||||
@@ -1028,6 +1270,10 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
||||
|
||||
AddRoadTunnelBridgeInfrastructure(tile, other_end);
|
||||
NotifyRoadLayoutChanged(true);
|
||||
if (rtt == RTT_ROAD) {
|
||||
UpdateRoadCachedOneWayStatesAroundTile(tile);
|
||||
UpdateRoadCachedOneWayStatesAroundTile(other_end);
|
||||
}
|
||||
DirtyAllCompanyInfrastructureWindows();
|
||||
}
|
||||
|
||||
@@ -1144,6 +1390,9 @@ do_clear:;
|
||||
MarkTileDirtyByTile(other_end);
|
||||
MarkTileDirtyByTile(tile);
|
||||
}
|
||||
if (rtt == RTT_ROAD) {
|
||||
UpdateRoadCachedOneWayStatesAroundTile(other_end);
|
||||
}
|
||||
NotifyRoadLayoutChanged(true);
|
||||
break;
|
||||
}
|
||||
@@ -1171,6 +1420,9 @@ do_clear:;
|
||||
SetDisallowedRoadDirections(tile, IsStraightRoad(existing) ?
|
||||
GetDisallowedRoadDirections(tile) ^ toggle_drd : DRD_NONE);
|
||||
}
|
||||
if (rtt == RTT_ROAD) {
|
||||
UpdateRoadCachedOneWayStatesAroundTile(tile);
|
||||
}
|
||||
|
||||
MarkTileDirtyByTile(tile);
|
||||
}
|
||||
@@ -1252,6 +1504,11 @@ CommandCost CmdBuildLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 p
|
||||
bool had_success = false;
|
||||
bool is_ai = HasBit(p2, 11);
|
||||
|
||||
_defer_update_road_cache_one_way_state = true;
|
||||
auto guard = scope_guard([]() {
|
||||
FlushDeferredUpdateRoadCachedOneWayStates();
|
||||
});
|
||||
|
||||
/* Start tile is the first tile clicked by the user. */
|
||||
for (;;) {
|
||||
RoadBits bits = AxisToRoadBits(axis);
|
||||
@@ -1335,6 +1592,11 @@ CommandCost CmdRemoveLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32
|
||||
p2 ^= IsInsideMM(p2 & 3, 1, 3) ? 3 : 0;
|
||||
}
|
||||
|
||||
_defer_update_road_cache_one_way_state = true;
|
||||
auto guard = scope_guard([]() {
|
||||
FlushDeferredUpdateRoadCachedOneWayStates();
|
||||
});
|
||||
|
||||
Money money = GetAvailableMoneyForCommand();
|
||||
TileIndex tile = start_tile;
|
||||
CommandCost last_error = CMD_ERROR;
|
||||
@@ -2258,16 +2520,40 @@ static TrackStatus GetTileTrackStatus_Road(TileIndex tile, TransportType mode, u
|
||||
switch (GetRoadTileType(tile)) {
|
||||
case ROAD_TILE_NORMAL: {
|
||||
const uint drd_to_multiplier[DRD_END] = { 0x101, 0x100, 0x1, 0x0 };
|
||||
const TrackdirBits left_turns = TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_RIGHT_S;
|
||||
const TrackdirBits right_turns = TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_RIGHT_N;
|
||||
const TrackdirBits no_exit_turns[4] = {
|
||||
TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_E, // ROAD_NW
|
||||
TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_UPPER_E, // ROAD_SW
|
||||
TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_UPPER_W, // ROAD_SE
|
||||
TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_LOWER_W // ROAD_NE
|
||||
};
|
||||
|
||||
RoadBits bits = GetRoadBits(tile, rtt);
|
||||
|
||||
/* no roadbit at this side of tile, return 0 */
|
||||
if (side != INVALID_DIAGDIR && (DiagDirToRoadBits(side) & bits) == 0) break;
|
||||
|
||||
uint multiplier = drd_to_multiplier[(rtt == RTT_TRAM) ? DRD_NONE : GetDisallowedRoadDirections(tile)];
|
||||
if (!HasRoadWorks(tile)) trackdirbits = (TrackdirBits)(_road_trackbits[bits] * multiplier);
|
||||
if (!HasRoadWorks(tile)) {
|
||||
RoadCachedOneWayState rcows = (rtt == RTT_TRAM) ? RCOWS_NORMAL : GetRoadCachedOneWayState(tile);
|
||||
switch (rcows) {
|
||||
case RCOWS_NORMAL:
|
||||
case RCOWS_NON_JUNCTION_A:
|
||||
case RCOWS_NON_JUNCTION_B:
|
||||
case RCOWS_NO_ACCESS:
|
||||
trackdirbits = (TrackdirBits)(_road_trackbits[bits] * drd_to_multiplier[(DisallowedRoadDirections)rcows]);
|
||||
break;
|
||||
|
||||
extern TrackdirBits MaskOneWaySideJunctionRoad(TileIndex tile, RoadBits bits);
|
||||
if (rtt == RTT_ROAD && HasExactlyOneBit(bits ^ ROAD_ALL)) trackdirbits &= MaskOneWaySideJunctionRoad(tile, bits);
|
||||
case RCOWS_SIDE_JUNCTION:
|
||||
case RCOWS_SIDE_JUNCTION_NO_EXIT:
|
||||
trackdirbits = (TrackdirBits)((_road_trackbits[bits] * 0x101) & ~(_settings_game.vehicle.road_side ? left_turns : right_turns));
|
||||
if (rcows == RCOWS_SIDE_JUNCTION_NO_EXIT) trackdirbits &= ~no_exit_turns[FIND_FIRST_BIT(bits ^ ROAD_ALL) & 3];
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -156,6 +156,8 @@ RoadTypes AddDateIntroducedRoadTypes(RoadTypes current, Date date);
|
||||
|
||||
void UpdateLevelCrossing(TileIndex tile, bool sound = true, bool force_close = false);
|
||||
bool IsCrossingOccupiedByRoadVehicle(TileIndex t);
|
||||
|
||||
void UpdateRoadCachedOneWayStatesAroundTile(TileIndex tile);
|
||||
void UpdateCompanyRoadInfrastructure(RoadType rt, Owner o, int count);
|
||||
|
||||
struct TileInfo;
|
||||
|
@@ -288,8 +288,8 @@ static inline bool HasTownOwnedRoad(TileIndex t)
|
||||
/** Which directions are disallowed ? */
|
||||
enum DisallowedRoadDirections {
|
||||
DRD_NONE, ///< None of the directions are disallowed
|
||||
DRD_SOUTHBOUND, ///< All southbound traffic is disallowed
|
||||
DRD_NORTHBOUND, ///< All northbound traffic is disallowed
|
||||
DRD_SOUTHBOUND, ///< All southbound traffic is disallowed (Trackdir 8-13 is allowed)
|
||||
DRD_NORTHBOUND, ///< All northbound traffic is disallowed (Trackdir 0-5 is allowed)
|
||||
DRD_BOTH, ///< All directions are disallowed
|
||||
DRD_END, ///< Sentinel
|
||||
};
|
||||
@@ -320,6 +320,39 @@ static inline void SetDisallowedRoadDirections(TileIndex t, DisallowedRoadDirect
|
||||
SB(_m[t].m5, 4, 2, drd);
|
||||
}
|
||||
|
||||
enum RoadCachedOneWayState {
|
||||
RCOWS_NORMAL = 0, ///< Road is not one-way
|
||||
RCOWS_NON_JUNCTION_A, ///< Road is one-way in 'A' direction (Trackdir 8-13 is allowed, same as DRD_SOUTHBOUND for straight road pieces)
|
||||
RCOWS_NON_JUNCTION_B, ///< Road is one-way in 'B' direction (Trackdir 0-5 is allowed, same as DRD_NORTHBOUND for straight road pieces)
|
||||
RCOWS_NO_ACCESS, ///< Road is disallowed in both directions
|
||||
RCOWS_SIDE_JUNCTION, ///< Road is a one-way side junction
|
||||
RCOWS_SIDE_JUNCTION_NO_EXIT, ///< Road is a one-way side junction, with no side exit
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the road cached one-way state
|
||||
* @param t tile to get the state from
|
||||
* @pre MayHaveRoad(t)
|
||||
* @return road cached one way state
|
||||
*/
|
||||
static inline RoadCachedOneWayState GetRoadCachedOneWayState(TileIndex t)
|
||||
{
|
||||
assert(MayHaveRoad(t));
|
||||
return (RoadCachedOneWayState)GB(_me[t].m8, 12, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the road cached one-way state
|
||||
* @param t tile to set the state of
|
||||
* @param rcows road cached one way state
|
||||
* @pre MayHaveRoad(t)
|
||||
*/
|
||||
static inline void SetRoadCachedOneWayState(TileIndex t, RoadCachedOneWayState rcows)
|
||||
{
|
||||
assert(MayHaveRoad(t));
|
||||
SB(_me[t].m8, 12, 3, rcows);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the road axis of a level crossing.
|
||||
* @param t The tile to query.
|
||||
|
@@ -373,90 +373,20 @@ bool RoadVehicle::FindClosestDepot(TileIndex *location, DestinationID *destinati
|
||||
return true;
|
||||
}
|
||||
|
||||
static DisallowedRoadDirections GetOneWayRoadTileDisallowedRoadDirections(TileIndex tile)
|
||||
inline bool IsOneWayRoadTile(TileIndex tile)
|
||||
{
|
||||
if (IsNormalRoadTile(tile)) return GetDisallowedRoadDirections(tile);
|
||||
if (IsDriveThroughStopTile(tile)) return GetDriveThroughStopDisallowedRoadDirections(tile);
|
||||
return DRD_NONE;
|
||||
return MayHaveRoad(tile) && GetRoadCachedOneWayState(tile) != RCOWS_NORMAL;
|
||||
}
|
||||
|
||||
static DiagDirection OneWaySideJunctionRoadRoadBitsToDiagDir(RoadBits bits)
|
||||
inline bool IsOneWaySideJunctionRoadTile(TileIndex tile)
|
||||
{
|
||||
/*
|
||||
* Drive on left missing bit:
|
||||
* ROAD_SE (bit 2) -> DIAGDIR_NE (0)
|
||||
* ROAD_SW (bit 1) -> DIAGDIR_SE (1)
|
||||
* ROAD_NW (bit 0) -> DIAGDIR_SW (2)
|
||||
* ROAD_NE (bit 3) -> DIAGDIR_NW (3)
|
||||
*/
|
||||
uint8 bit = FIND_FIRST_BIT(bits ^ ROAD_ALL);
|
||||
bit ^= 3;
|
||||
return (DiagDirection)((bit + 3 + (_settings_game.vehicle.road_side * 2)) % 4);
|
||||
return MayHaveRoad(tile) && (GetRoadCachedOneWayState(tile) == RCOWS_SIDE_JUNCTION || GetRoadCachedOneWayState(tile) == RCOWS_SIDE_JUNCTION_NO_EXIT);
|
||||
}
|
||||
|
||||
inline bool IsOneWaySideJunctionRoadDRDsPresent(TileIndex tile, DiagDirection dir)
|
||||
static bool MayReverseOnOneWayRoadTile(TileIndex tile, DiagDirection dir)
|
||||
{
|
||||
const DisallowedRoadDirections diagdir_to_drd[DIAGDIR_END] = { DRD_NORTHBOUND, DRD_NORTHBOUND, DRD_SOUTHBOUND, DRD_SOUTHBOUND };
|
||||
|
||||
TileIndexDiffC ti = TileIndexDiffCByDiagDir(dir);
|
||||
TileIndex ahead = AddTileIndexDiffCWrap(tile, ti);
|
||||
if (ahead == INVALID_TILE || GetOneWayRoadTileDisallowedRoadDirections(ahead) != diagdir_to_drd[dir]) return false;
|
||||
TileIndex behind = AddTileIndexDiffCWrap(tile, { (int16)(-ti.x), (int16)(-ti.y) });
|
||||
if (behind == INVALID_TILE || GetOneWayRoadTileDisallowedRoadDirections(behind) != diagdir_to_drd[dir]) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsOneWaySideJunctionRoad(TileIndex tile)
|
||||
{
|
||||
RoadBits bits = GetRoadBits(tile, RTT_ROAD);
|
||||
if (!HasExactlyOneBit(bits ^ ROAD_ALL)) return false;
|
||||
DiagDirection dir = OneWaySideJunctionRoadRoadBitsToDiagDir(bits);
|
||||
return IsOneWaySideJunctionRoadDRDsPresent(tile, dir);
|
||||
}
|
||||
|
||||
TrackdirBits MaskOneWaySideJunctionRoad(TileIndex tile, RoadBits bits)
|
||||
{
|
||||
DiagDirection dir = OneWaySideJunctionRoadRoadBitsToDiagDir(bits);
|
||||
if (!IsOneWaySideJunctionRoadDRDsPresent(tile, dir)) return ~TRACKDIR_BIT_NONE;
|
||||
|
||||
const TrackdirBits left_turns = TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_RIGHT_S;
|
||||
const TrackdirBits right_turns = TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_RIGHT_N;
|
||||
TrackdirBits remove = (_settings_game.vehicle.road_side ? left_turns : right_turns);
|
||||
|
||||
DiagDirection side_dir = (DiagDirection)((dir + 3 + (_settings_game.vehicle.road_side * 2)) % 4);
|
||||
TileIndexDiffC ti = TileIndexDiffCByDiagDir(side_dir);
|
||||
TileIndex side = AddTileIndexDiffCWrap(tile, ti);
|
||||
|
||||
const DisallowedRoadDirections diagdir_to_drd[DIAGDIR_END] = { DRD_SOUTHBOUND, DRD_SOUTHBOUND, DRD_NORTHBOUND, DRD_NORTHBOUND };
|
||||
const TrackdirBits remove_side_trackdirs[] = {
|
||||
TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_UPPER_E, // DIAGDIR_NE
|
||||
TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_E, // DIAGDIR_SE
|
||||
TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_LOWER_W, // DIAGDIR_SW
|
||||
TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_UPPER_W // DIAGDIR_NW
|
||||
};
|
||||
if (side != INVALID_TILE && GetOneWayRoadTileDisallowedRoadDirections(side) & diagdir_to_drd[side_dir]) remove |= remove_side_trackdirs[side_dir];
|
||||
|
||||
return ~remove;
|
||||
}
|
||||
|
||||
static bool IsOneWayRoadTile(TileIndex tile)
|
||||
{
|
||||
if (IsNormalRoadTile(tile)) {
|
||||
if (GetDisallowedRoadDirections(tile) != DRD_NONE) return true;
|
||||
if (IsOneWaySideJunctionRoad(tile)) return true;
|
||||
}
|
||||
if (IsDriveThroughStopTile(tile) && GetDriveThroughStopDisallowedRoadDirections(tile) != DRD_NONE) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8 GetOneWayRoadTileType(TileIndex tile)
|
||||
{
|
||||
if (IsNormalRoadTile(tile)) {
|
||||
if (GetDisallowedRoadDirections(tile) != DRD_NONE) return 1;
|
||||
if (IsOneWaySideJunctionRoad(tile)) return 2;
|
||||
}
|
||||
if (IsDriveThroughStopTile(tile) && GetDriveThroughStopDisallowedRoadDirections(tile) != DRD_NONE) return 3;
|
||||
return 0;
|
||||
TrackdirBits bits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, RTT_ROAD));
|
||||
return bits & DiagdirReachesTrackdirs(ReverseDiagDir(dir));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -946,14 +876,15 @@ static bool CheckRoadInfraUnsuitableForOvertaking(OvertakeData *od)
|
||||
if (!HasBit(trackdirbits, od->trackdir) || (red_signals != TRACKDIR_BIT_NONE)) return true;
|
||||
/* Track has junction */
|
||||
if (trackbits & ~TRACK_BIT_CROSS) {
|
||||
if (IsNormalRoadTile(od->tile) && IsOneWaySideJunctionRoad(od->tile)) {
|
||||
RoadCachedOneWayState rcows = GetRoadCachedOneWayState(od->tile);
|
||||
if (rcows == RCOWS_SIDE_JUNCTION) {
|
||||
const RoadVehPathCache &pc = od->v->path;
|
||||
if (!pc.empty() && pc.tile.front() == od->tile && !IsStraightRoadTrackdir(pc.td.front())) {
|
||||
/* cached path indicates that we are turning here, do not overtake */
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
return rcows != RCOWS_SIDE_JUNCTION_NO_EXIT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1495,7 +1426,7 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
|
||||
} else if (v->HasArticulatedPart() && IsBridgeTile(v->tile) && (IsRoadCustomBridgeHeadTile(v->tile) || IsRoadCustomBridgeHeadTile(GetOtherBridgeEnd(v->tile)))) {
|
||||
/* Articulated RVs may not overtake on custom bridge heads */
|
||||
v->SetRoadVehicleOvertaking(0);
|
||||
} else if (v->state < RVSB_IN_ROAD_STOP && !IsStraightRoadTrackdir((Trackdir)v->state) && IsOneWaySideJunctionRoad(v->tile)) {
|
||||
} else if (v->state < RVSB_IN_ROAD_STOP && !IsStraightRoadTrackdir((Trackdir)v->state) && IsOneWaySideJunctionRoadTile(v->tile)) {
|
||||
/* No turning to/from overtaking lane on one way side road junctions */
|
||||
v->SetRoadVehicleOvertaking(0);
|
||||
} else if (++v->overtaking_ctr >= RV_OVERTAKE_TIMEOUT) {
|
||||
@@ -1649,7 +1580,7 @@ again:
|
||||
v->cur_speed = 0;
|
||||
return false;
|
||||
}
|
||||
} else if (IsOneWayRoadTile(v->tile)) {
|
||||
} else if (IsOneWayRoadTile(v->tile) && !MayReverseOnOneWayRoadTile(v->tile, (DiagDirection)(rd.x & 3))) {
|
||||
v->cur_speed = 0;
|
||||
return false;
|
||||
} else {
|
||||
|
@@ -3795,6 +3795,11 @@ bool AfterLoadGame()
|
||||
}
|
||||
}
|
||||
|
||||
if (SlXvIsFeatureMissing(XSLFI_ONE_WAY_ROAD_STATE)) {
|
||||
extern void RecalculateRoadCachedOneWayStates();
|
||||
RecalculateRoadCachedOneWayStates();
|
||||
}
|
||||
|
||||
InitializeRoadGUI();
|
||||
|
||||
/* This needs to be done after conversion. */
|
||||
|
@@ -137,6 +137,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
||||
{ 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_ONE_WAY_DT_ROAD_STOP, XSCF_NULL, 1, 1, "one_way_dt_road_stop", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_ONE_WAY_ROAD_STATE, XSCF_NULL, 1, 1, "one_way_road_state", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker
|
||||
};
|
||||
|
||||
|
@@ -91,6 +91,7 @@ enum SlXvFeatureIndex {
|
||||
XSLFI_MORE_VEHICLE_ORDERS, ///< More vehicle orders - VehicleOrderID is 16 bits instead of 8
|
||||
XSLFI_ORDER_FLAGS_EXTRA, ///< Order flags field extra size
|
||||
XSLFI_ONE_WAY_DT_ROAD_STOP, ///< One-way drive-through road stops
|
||||
XSLFI_ONE_WAY_ROAD_STATE, ///< One-way road state cache
|
||||
|
||||
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
|
||||
|
@@ -1412,7 +1412,11 @@ static bool MaxNoAIsChange(int32 i)
|
||||
static bool CheckRoadSide(int p1)
|
||||
{
|
||||
extern bool RoadVehiclesAreBuilt();
|
||||
return _game_mode == GM_MENU || !RoadVehiclesAreBuilt();
|
||||
if (_game_mode != GM_MENU && RoadVehiclesAreBuilt()) return false;
|
||||
|
||||
extern void RecalculateRoadCachedOneWayStates();
|
||||
RecalculateRoadCachedOneWayStates();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2032,6 +2036,8 @@ void LoadFromConfig(bool minimal)
|
||||
|
||||
ValidateSettings();
|
||||
|
||||
PostZoningModeChange();
|
||||
|
||||
/* Display scheduled errors */
|
||||
extern void ScheduleErrorMessage(ErrorList &datas);
|
||||
ScheduleErrorMessage(_settings_error_list);
|
||||
|
@@ -2082,6 +2082,7 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
|
||||
}
|
||||
ZoningMarkDirtyStationCoverageArea(st);
|
||||
NotifyRoadLayoutChanged(true);
|
||||
UpdateRoadCachedOneWayStatesAroundTile(tile);
|
||||
}
|
||||
|
||||
if (st != nullptr) {
|
||||
@@ -2275,6 +2276,7 @@ CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, ui
|
||||
UpdateCompanyRoadInfrastructure(road_type[RTT_ROAD], road_owner[RTT_ROAD], count);
|
||||
UpdateCompanyRoadInfrastructure(road_type[RTT_TRAM], road_owner[RTT_TRAM], count);
|
||||
}
|
||||
if (flags & DC_EXEC) UpdateRoadCachedOneWayStatesAroundTile(cur_tile);
|
||||
}
|
||||
|
||||
return had_success ? cost : last_error;
|
||||
@@ -4588,6 +4590,13 @@ static bool CanRemoveRoadWithStop(TileIndex tile, DoCommandFlag flags)
|
||||
return true;
|
||||
}
|
||||
|
||||
static CommandCost RemoveRoadStopAndUpdateRoadCachedOneWayState(TileIndex tile, DoCommandFlag flags)
|
||||
{
|
||||
CommandCost cost = RemoveRoadStop(tile, flags);
|
||||
if ((flags & DC_EXEC) && cost.Succeeded()) UpdateRoadCachedOneWayStatesAroundTile(tile);
|
||||
return cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a single tile of a station.
|
||||
* @param tile The tile to clear.
|
||||
@@ -4620,12 +4629,12 @@ CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags)
|
||||
if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags)) {
|
||||
return_cmd_error(STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST);
|
||||
}
|
||||
return RemoveRoadStop(tile, flags);
|
||||
return RemoveRoadStopAndUpdateRoadCachedOneWayState(tile, flags);
|
||||
case STATION_BUS:
|
||||
if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags)) {
|
||||
return_cmd_error(STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST);
|
||||
}
|
||||
return RemoveRoadStop(tile, flags);
|
||||
return RemoveRoadStopAndUpdateRoadCachedOneWayState(tile, flags);
|
||||
case STATION_BUOY: return RemoveBuoy(tile, flags);
|
||||
case STATION_DOCK: return RemoveDock(tile, flags);
|
||||
default: break;
|
||||
|
@@ -676,6 +676,8 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u
|
||||
NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(tile_start, tile_end, dir, GetRoadTramType(roadtype));
|
||||
}
|
||||
}
|
||||
UpdateRoadCachedOneWayStatesAroundTile(tile_start);
|
||||
UpdateRoadCachedOneWayStatesAroundTile(tile_end);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1039,6 +1041,8 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
|
||||
RoadType tram_rt = RoadTypeIsTram(roadtype) ? roadtype : INVALID_ROADTYPE;
|
||||
MakeRoadTunnel(start_tile, company, t->index, direction, road_rt, tram_rt);
|
||||
MakeRoadTunnel(end_tile, company, t->index, ReverseDiagDir(direction), road_rt, tram_rt);
|
||||
UpdateRoadCachedOneWayStatesAroundTile(start_tile);
|
||||
UpdateRoadCachedOneWayStatesAroundTile(end_tile);
|
||||
}
|
||||
DirtyCompanyInfrastructureWindows(company);
|
||||
}
|
||||
@@ -1180,6 +1184,9 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags)
|
||||
|
||||
DoClearSquare(tile);
|
||||
DoClearSquare(endtile);
|
||||
|
||||
UpdateRoadCachedOneWayStatesAroundTile(tile);
|
||||
UpdateRoadCachedOneWayStatesAroundTile(endtile);
|
||||
}
|
||||
ViewportMapInvalidateTunnelCacheByTile(tile < endtile ? tile : endtile, axis);
|
||||
}
|
||||
@@ -1265,6 +1272,7 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
|
||||
|
||||
bool removetile = false;
|
||||
bool removeendtile = false;
|
||||
bool update_road = false;
|
||||
|
||||
/* Update company infrastructure counts. */
|
||||
if (rail) {
|
||||
@@ -1279,6 +1287,7 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
|
||||
if (HasRoadTypeTram(tile)) NotifyRoadLayoutChangedIfSimpleTunnelBridgeNonLeaf(tile, endtile, direction, RTT_TRAM);
|
||||
}
|
||||
}
|
||||
update_road = true;
|
||||
} else { // Aqueduct
|
||||
if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.water -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||
removetile = IsDockingTile(tile);
|
||||
@@ -1325,6 +1334,11 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
|
||||
TryPathReserve(vehicles_affected[i], true);
|
||||
}
|
||||
}
|
||||
|
||||
if (update_road) {
|
||||
UpdateRoadCachedOneWayStatesAroundTile(tile);
|
||||
UpdateRoadCachedOneWayStatesAroundTile(endtile);
|
||||
}
|
||||
}
|
||||
|
||||
return cost;
|
||||
|
@@ -68,6 +68,7 @@ void ZoningStationWindowOpenClose(const Station *st);
|
||||
void ZoningTownAuthorityRatingChange();
|
||||
|
||||
void SetZoningMode(bool inner, ZoningEvaluationMode mode);
|
||||
void PostZoningModeChange();
|
||||
|
||||
void ClearZoningCaches();
|
||||
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include "window_func.h"
|
||||
#include "zoning.h"
|
||||
#include "viewport_func.h"
|
||||
#include "road_map.h"
|
||||
#include "3rdparty/cpp-btree/btree_set.h"
|
||||
|
||||
Zoning _zoning;
|
||||
@@ -282,18 +283,27 @@ inline SpriteID TileZoneCheckRoadGridEvaluation(TileIndex tile, uint grid_size)
|
||||
*/
|
||||
inline SpriteID TileZoneCheckOneWayRoadEvaluation(TileIndex tile)
|
||||
{
|
||||
extern uint8 GetOneWayRoadTileType(TileIndex tile);
|
||||
if (!MayHaveRoad(tile)) return ZONING_INVALID_SPRITE_ID;
|
||||
|
||||
uint8 type = GetOneWayRoadTileType(tile);
|
||||
switch (type) {
|
||||
RoadCachedOneWayState rcows = GetRoadCachedOneWayState(tile);
|
||||
switch (rcows) {
|
||||
default:
|
||||
return ZONING_INVALID_SPRITE_ID;
|
||||
case 1:
|
||||
return SPR_ZONING_INNER_HIGHLIGHT_LIGHT_BLUE;
|
||||
case 2:
|
||||
case RCOWS_NO_ACCESS:
|
||||
return SPR_ZONING_INNER_HIGHLIGHT_RED;
|
||||
case RCOWS_NON_JUNCTION_A:
|
||||
case RCOWS_NON_JUNCTION_B:
|
||||
if (IsTileType(tile, MP_STATION)) {
|
||||
return SPR_ZONING_INNER_HIGHLIGHT_GREEN;
|
||||
} else if (IsNormalRoadTile(tile) && GetDisallowedRoadDirections(tile) != DRD_NONE) {
|
||||
return SPR_ZONING_INNER_HIGHLIGHT_LIGHT_BLUE;
|
||||
} else {
|
||||
return SPR_ZONING_INNER_HIGHLIGHT_PURPLE;
|
||||
}
|
||||
case RCOWS_SIDE_JUNCTION:
|
||||
return SPR_ZONING_INNER_HIGHLIGHT_ORANGE;
|
||||
case 3:
|
||||
return SPR_ZONING_INNER_HIGHLIGHT_GREEN;
|
||||
case RCOWS_SIDE_JUNCTION_NO_EXIT:
|
||||
return SPR_ZONING_INNER_HIGHLIGHT_YELLOW;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,4 +496,11 @@ void SetZoningMode(bool inner, ZoningEvaluationMode mode)
|
||||
current_mode = mode;
|
||||
cache.clear();
|
||||
MarkWholeNonMapViewportsDirty();
|
||||
PostZoningModeChange();
|
||||
}
|
||||
|
||||
void PostZoningModeChange()
|
||||
{
|
||||
extern bool _mark_tile_dirty_on_road_cache_one_way_state_update;
|
||||
_mark_tile_dirty_on_road_cache_one_way_state_update = (_zoning.inner == ZEM_ONE_WAY_ROAD) || (_zoning.outer == ZEM_ONE_WAY_ROAD);
|
||||
}
|
||||
|
Reference in New Issue
Block a user