Custom bridge heads: Initial implementation
This commit is contained in:
@@ -180,4 +180,72 @@ static inline void MakeAqueductBridgeRamp(TileIndex t, Owner o, DiagDirection d)
|
|||||||
MakeBridgeRamp(t, o, 0, d, TRANSPORT_WATER, 0);
|
MakeBridgeRamp(t, o, 0, d, TRANSPORT_WATER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this road bridge head is a custom bridge head
|
||||||
|
* @param t The tile to analyze
|
||||||
|
* @pre IsBridgeTile(t) && GetTunnelBridgeTransportType(t) == TRANSPORT_ROAD
|
||||||
|
* @return true if it is a custom bridge head
|
||||||
|
*/
|
||||||
|
static inline bool IsRoadCustomBridgeHead(TileIndex t)
|
||||||
|
{
|
||||||
|
assert(IsBridgeTile(t) && (TransportType)GB(_m[t].m5, 2, 2) == TRANSPORT_ROAD);
|
||||||
|
return GB(_m[t].m2, 0, 8) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this tile is a road bridge head with a custom bridge head
|
||||||
|
* @param t The tile to analyze
|
||||||
|
* @return true if it is a road bridge head with a custom bridge head
|
||||||
|
*/
|
||||||
|
static inline bool IsRoadCustomBridgeHeadTile(TileIndex t)
|
||||||
|
{
|
||||||
|
return IsBridgeTile(t) && (TransportType)GB(_m[t].m5, 2, 2) == TRANSPORT_ROAD && IsRoadCustomBridgeHead(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the road bits for a (possibly custom) road bridge head
|
||||||
|
* @param t The tile to analyze
|
||||||
|
* @param rt Road type.
|
||||||
|
* @pre IsBridgeTile(t) && GetTunnelBridgeTransportType(t) == TRANSPORT_ROAD
|
||||||
|
* @return road bits for the bridge head
|
||||||
|
*/
|
||||||
|
static inline RoadBits GetCustomBridgeHeadRoadBits(TileIndex t, RoadType rt)
|
||||||
|
{
|
||||||
|
assert(IsBridgeTile(t));
|
||||||
|
if (!HasTileRoadType(t, rt)) return (RoadBits) 0;
|
||||||
|
RoadBits bits = (GB(_m[t].m5, 0, 1) ? ROAD_Y : ROAD_X) ^ (RoadBits) GB(_m[t].m2, rt == ROADTYPE_TRAM ? 4 : 0, 4);
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the road bits for a (possibly custom) road bridge head, for all road types
|
||||||
|
* @param t The tile to analyze
|
||||||
|
* @pre IsBridgeTile(t) && GetTunnelBridgeTransportType(t) == TRANSPORT_ROAD
|
||||||
|
* @return road bits for the bridge head
|
||||||
|
*/
|
||||||
|
static inline RoadBits GetCustomBridgeHeadAllRoadBits(TileIndex t)
|
||||||
|
{
|
||||||
|
return GetCustomBridgeHeadRoadBits(t, ROADTYPE_ROAD) | GetCustomBridgeHeadRoadBits(t, ROADTYPE_TRAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the road bits for a (possibly custom) road bridge head
|
||||||
|
* @param t The tile to modify
|
||||||
|
* @param rt Road type.
|
||||||
|
* @param bits The road bits.
|
||||||
|
* @pre IsBridgeTile(t) && GetTunnelBridgeTransportType(t) == TRANSPORT_ROAD
|
||||||
|
* @pre HasTileRoadType() must be set correctly before calling this
|
||||||
|
*/
|
||||||
|
static inline void SetCustomBridgeHeadRoadBits(TileIndex t, RoadType rt, RoadBits bits)
|
||||||
|
{
|
||||||
|
assert(IsBridgeTile(t));
|
||||||
|
if (HasTileRoadType(t, rt)) {
|
||||||
|
assert(bits != ROAD_NONE);
|
||||||
|
SB(_m[t].m2, rt == ROADTYPE_TRAM ? 4 : 0, 4, bits ^ (GB(_m[t].m5, 0, 1) ? ROAD_Y : ROAD_X));
|
||||||
|
} else {
|
||||||
|
assert(bits == ROAD_NONE);
|
||||||
|
SB(_m[t].m2, rt == ROADTYPE_TRAM ? 4 : 0, 4, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* BRIDGE_MAP_H */
|
#endif /* BRIDGE_MAP_H */
|
||||||
|
@@ -2474,6 +2474,15 @@ void DirtyCompanyInfrastructureWindows(CompanyID company)
|
|||||||
SetWindowDirty(WC_COMPANY_INFRASTRUCTURE, company);
|
SetWindowDirty(WC_COMPANY_INFRASTRUCTURE, company);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redraw all windows with all company infrastructure counts.
|
||||||
|
*/
|
||||||
|
void DirtyAllCompanyInfrastructureWindows()
|
||||||
|
{
|
||||||
|
SetWindowClassesDirty(WC_COMPANY);
|
||||||
|
SetWindowClassesDirty(WC_COMPANY_INFRASTRUCTURE);
|
||||||
|
}
|
||||||
|
|
||||||
struct BuyCompanyWindow : Window {
|
struct BuyCompanyWindow : Window {
|
||||||
BuyCompanyWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
|
BuyCompanyWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
|
||||||
{
|
{
|
||||||
|
@@ -25,5 +25,6 @@ void ShowCompany(CompanyID company);
|
|||||||
void InvalidateCompanyWindows(const Company *c);
|
void InvalidateCompanyWindows(const Company *c);
|
||||||
void DeleteCompanyWindows(CompanyID company);
|
void DeleteCompanyWindows(CompanyID company);
|
||||||
void DirtyCompanyInfrastructureWindows(CompanyID company);
|
void DirtyCompanyInfrastructureWindows(CompanyID company);
|
||||||
|
void DirtyAllCompanyInfrastructureWindows();
|
||||||
|
|
||||||
#endif /* COMPANY_GUI_H */
|
#endif /* COMPANY_GUI_H */
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include "core/random_func.hpp"
|
#include "core/random_func.hpp"
|
||||||
#include "object_base.h"
|
#include "object_base.h"
|
||||||
#include "company_func.h"
|
#include "company_func.h"
|
||||||
|
#include "tunnelbridge_map.h"
|
||||||
#include "pathfinder/npf/aystar.h"
|
#include "pathfinder/npf/aystar.h"
|
||||||
#include "saveload/saveload.h"
|
#include "saveload/saveload.h"
|
||||||
#include <list>
|
#include <list>
|
||||||
@@ -351,6 +352,8 @@ Slope GetFoundationSlope(TileIndex tile, int *z)
|
|||||||
|
|
||||||
bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
|
bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
|
||||||
{
|
{
|
||||||
|
if (IsRoadCustomBridgeHeadTile(tile) && GetTunnelBridgeDirection(tile) == DIAGDIR_NW) return false;
|
||||||
|
|
||||||
int z;
|
int z;
|
||||||
|
|
||||||
int z_W_here = z_here;
|
int z_W_here = z_here;
|
||||||
@@ -368,6 +371,8 @@ bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
|
|||||||
|
|
||||||
bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here)
|
bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here)
|
||||||
{
|
{
|
||||||
|
if (IsRoadCustomBridgeHeadTile(tile) && GetTunnelBridgeDirection(tile) == DIAGDIR_NE) return false;
|
||||||
|
|
||||||
int z;
|
int z;
|
||||||
|
|
||||||
int z_E_here = z_here;
|
int z_E_here = z_here;
|
||||||
|
@@ -101,8 +101,9 @@ struct CFollowTrackT
|
|||||||
{
|
{
|
||||||
assert(IsTram()); // this function shouldn't be called in other cases
|
assert(IsTram()); // this function shouldn't be called in other cases
|
||||||
|
|
||||||
if (IsNormalRoadTile(tile)) {
|
const bool is_bridge = IsRoadCustomBridgeHeadTile(tile);
|
||||||
RoadBits rb = GetRoadBits(tile, ROADTYPE_TRAM);
|
if (is_bridge || IsNormalRoadTile(tile)) {
|
||||||
|
RoadBits rb = is_bridge ? GetCustomBridgeHeadRoadBits(tile, ROADTYPE_TRAM) : GetRoadBits(tile, ROADTYPE_TRAM);
|
||||||
switch (rb) {
|
switch (rb) {
|
||||||
case ROAD_NW: return DIAGDIR_NW;
|
case ROAD_NW: return DIAGDIR_NW;
|
||||||
case ROAD_SW: return DIAGDIR_SW;
|
case ROAD_SW: return DIAGDIR_SW;
|
||||||
@@ -215,7 +216,7 @@ protected:
|
|||||||
m_tiles_skipped = GetTunnelBridgeLength(m_new_tile, m_old_tile);
|
m_tiles_skipped = GetTunnelBridgeLength(m_new_tile, m_old_tile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert(ReverseDiagDir(enterdir) == m_exitdir);
|
if (!IsRoadCustomBridgeHeadTile(m_old_tile)) assert(ReverseDiagDir(enterdir) == m_exitdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* normal or station tile, do one step */
|
/* normal or station tile, do one step */
|
||||||
@@ -364,7 +365,12 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // IsBridge(m_new_tile)
|
} else { // IsBridge(m_new_tile)
|
||||||
if (!m_is_bridge) {
|
if (!m_is_bridge && IsRoadTT() && IsRoadCustomBridgeHeadTile(m_new_tile)) {
|
||||||
|
if (!(DiagDirToRoadBits(ReverseDiagDir(m_exitdir)) & GetCustomBridgeHeadRoadBits(m_new_tile, IsTram() ? ROADTYPE_TRAM : ROADTYPE_ROAD))) {
|
||||||
|
m_err = EC_NO_WAY;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (!m_is_bridge) {
|
||||||
DiagDirection ramp_enderdir = GetTunnelBridgeDirection(m_new_tile);
|
DiagDirection ramp_enderdir = GetTunnelBridgeDirection(m_new_tile);
|
||||||
if (ramp_enderdir != m_exitdir) {
|
if (ramp_enderdir != m_exitdir) {
|
||||||
m_err = EC_NO_WAY;
|
m_err = EC_NO_WAY;
|
||||||
|
@@ -104,7 +104,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline bool PfCalcCost(Node &n, const TrackFollower *tf)
|
inline bool PfCalcCost(Node &n, const TrackFollower *tf)
|
||||||
{
|
{
|
||||||
int segment_cost = 0;
|
/* this is to handle the case where the starting tile is a junction custom bridge head,
|
||||||
|
* and we have advanced across the bridge in the initial step */
|
||||||
|
int segment_cost = tf->m_tiles_skipped * YAPF_TILE_LENGTH;
|
||||||
|
|
||||||
uint tiles = 0;
|
uint tiles = 0;
|
||||||
/* start at n.m_key.m_tile / n.m_key.m_td and walk to the end of segment */
|
/* start at n.m_key.m_tile / n.m_key.m_td and walk to the end of segment */
|
||||||
TileIndex tile = n.m_key.m_tile;
|
TileIndex tile = n.m_key.m_tile;
|
||||||
@@ -127,6 +130,11 @@ public:
|
|||||||
TrackFollower F(Yapf().GetVehicle());
|
TrackFollower F(Yapf().GetVehicle());
|
||||||
if (!F.Follow(tile, trackdir)) break;
|
if (!F.Follow(tile, trackdir)) break;
|
||||||
|
|
||||||
|
/* if we skipped some tunnel tiles, add their cost */
|
||||||
|
/* with custom bridge heads, this cost must be added before checking if the segment has ended */
|
||||||
|
segment_cost += F.m_tiles_skipped * YAPF_TILE_LENGTH;
|
||||||
|
tiles += F.m_tiles_skipped + 1;
|
||||||
|
|
||||||
/* if there are more trackdirs available & reachable, we are at the end of segment */
|
/* if there are more trackdirs available & reachable, we are at the end of segment */
|
||||||
if (KillFirstBit(F.m_new_td_bits) != TRACKDIR_BIT_NONE) break;
|
if (KillFirstBit(F.m_new_td_bits) != TRACKDIR_BIT_NONE) break;
|
||||||
|
|
||||||
@@ -135,10 +143,6 @@ public:
|
|||||||
/* stop if RV is on simple loop with no junctions */
|
/* stop if RV is on simple loop with no junctions */
|
||||||
if (F.m_new_tile == n.m_key.m_tile && new_td == n.m_key.m_td) return false;
|
if (F.m_new_tile == n.m_key.m_tile && new_td == n.m_key.m_td) return false;
|
||||||
|
|
||||||
/* if we skipped some tunnel tiles, add their cost */
|
|
||||||
segment_cost += F.m_tiles_skipped * YAPF_TILE_LENGTH;
|
|
||||||
tiles += F.m_tiles_skipped + 1;
|
|
||||||
|
|
||||||
/* add hilly terrain penalty */
|
/* add hilly terrain penalty */
|
||||||
segment_cost += Yapf().SlopeCost(tile, F.m_new_tile, trackdir);
|
segment_cost += Yapf().SlopeCost(tile, F.m_new_tile, trackdir);
|
||||||
|
|
||||||
|
241
src/road_cmd.cpp
241
src/road_cmd.cpp
@@ -53,7 +53,7 @@ bool RoadVehiclesAreBuilt()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Invalid RoadBits on slopes. */
|
/** Invalid RoadBits on slopes. */
|
||||||
static const RoadBits _invalid_tileh_slopes_road[2][15] = {
|
extern const RoadBits _invalid_tileh_slopes_road[2][15] = {
|
||||||
/* The inverse of the mixable RoadBits on a leveled slope */
|
/* The inverse of the mixable RoadBits on a leveled slope */
|
||||||
{
|
{
|
||||||
ROAD_NONE, // SLOPE_FLAT
|
ROAD_NONE, // SLOPE_FLAT
|
||||||
@@ -213,36 +213,75 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec
|
|||||||
if (ret.Failed()) return ret;
|
if (ret.Failed()) return ret;
|
||||||
|
|
||||||
if (!IsTileType(tile, MP_ROAD)) {
|
if (!IsTileType(tile, MP_ROAD)) {
|
||||||
|
const bool custom_bridge_head = IsBridgeTile(tile) &&
|
||||||
|
HasBridgeFlatRamp(GetTileSlope(tile), DiagDirToAxis(GetTunnelBridgeDirection(tile))) &&
|
||||||
|
(_settings_game.construction.road_custom_bridge_heads || IsRoadCustomBridgeHead(tile));
|
||||||
|
|
||||||
/* If it's the last roadtype, just clear the whole tile */
|
/* If it's the last roadtype, just clear the whole tile */
|
||||||
if (rts == RoadTypeToRoadTypes(rt)) return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
|
if (!custom_bridge_head && rts == RoadTypeToRoadTypes(rt)) return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
|
||||||
|
|
||||||
CommandCost cost(EXPENSES_CONSTRUCTION);
|
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||||
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
||||||
/* Removing any roadbit in the bridge axis removes the roadtype (that's the behaviour remove-long-roads needs) */
|
const RoadBits entrance_piece = DiagDirToRoadBits(GetTunnelBridgeDirection(tile));
|
||||||
if ((AxisToRoadBits(DiagDirToAxis(GetTunnelBridgeDirection(tile))) & pieces) == ROAD_NONE) return_cmd_error(rt == ROADTYPE_TRAM ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD);
|
const RoadBits axial_pieces = AxisToRoadBits(DiagDirToAxis(GetTunnelBridgeDirection(tile)));
|
||||||
|
const RoadBits existing = IsBridge(tile) ? GetCustomBridgeHeadRoadBits(tile, rt) : axial_pieces;
|
||||||
|
const RoadType other_rt = (rt == ROADTYPE_ROAD) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
|
||||||
|
|
||||||
TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
|
/* handle case where we would otherwise leave a single bridge entrance piece */
|
||||||
/* Pay for *every* tile of the bridge or tunnel */
|
if ((existing & ~pieces) == entrance_piece) {
|
||||||
uint len = GetTunnelBridgeLength(other_end, tile) + 2;
|
pieces |= entrance_piece;
|
||||||
cost.AddCost(len * _price[PR_CLEAR_ROAD]);
|
}
|
||||||
|
|
||||||
|
/* Removing any roadbit in the bridge axis removes the roadtype (that's the behaviour remove-long-roads needs) */
|
||||||
|
if ((existing & pieces) == ROAD_NONE) return_cmd_error(rt == ROADTYPE_TRAM ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD);
|
||||||
|
|
||||||
|
if (!custom_bridge_head) pieces |= axial_pieces;
|
||||||
|
|
||||||
|
const TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
|
||||||
|
const uint middle_len = GetTunnelBridgeLength(other_end, tile);
|
||||||
|
uint pieces_count = 0;
|
||||||
|
|
||||||
|
const RoadBits other_end_existing = IsBridge(other_end) ? GetCustomBridgeHeadRoadBits(other_end, rt) : axial_pieces;
|
||||||
|
RoadBits other_end_pieces = ROAD_NONE;
|
||||||
|
if (pieces & entrance_piece) {
|
||||||
|
other_end_pieces |= MirrorRoadBits(entrance_piece);
|
||||||
|
/* if removing the other end entrance would only leave one piece, remove that too */
|
||||||
|
if (CountBits(other_end_existing & ~other_end_pieces) == 1) {
|
||||||
|
other_end_pieces |= other_end_existing;
|
||||||
|
}
|
||||||
|
pieces_count += middle_len * 2;
|
||||||
|
if ((GetCustomBridgeHeadRoadBits(tile, other_rt) & entrance_piece) == ROAD_NONE) {
|
||||||
|
/* can't leave no entrance pieces for any road type */
|
||||||
|
return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pieces_count += CountBits(pieces & existing);
|
||||||
|
pieces_count += CountBits(other_end_pieces & other_end_existing);
|
||||||
|
|
||||||
|
cost.AddCost(pieces_count * _price[PR_CLEAR_ROAD]);
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
Company *c = Company::GetIfValid(GetRoadOwner(tile, rt));
|
SubtractRoadTunnelBridgeInfrastructure(tile, other_end);
|
||||||
if (c != NULL) {
|
|
||||||
/* A full diagonal road tile has two road bits. */
|
const RoadBits bits = existing & ~pieces;
|
||||||
c->infrastructure.road[rt] -= len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
const RoadBits other_bits = other_end_existing & ~other_end_pieces;
|
||||||
DirtyCompanyInfrastructureWindows(c->index);
|
|
||||||
|
if (bits == ROAD_NONE) SetRoadTypes(tile, GetRoadTypes(tile) & ~RoadTypeToRoadTypes(rt));
|
||||||
|
if (other_bits == ROAD_NONE) SetRoadTypes(other_end, GetRoadTypes(other_end) & ~RoadTypeToRoadTypes(rt));
|
||||||
|
|
||||||
|
if (IsBridge(tile)) {
|
||||||
|
SetCustomBridgeHeadRoadBits(tile, rt, bits);
|
||||||
|
SetCustomBridgeHeadRoadBits(other_end, rt, other_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetRoadTypes(other_end, GetRoadTypes(other_end) & ~RoadTypeToRoadTypes(rt));
|
if (bits == ROAD_NONE && other_bits == ROAD_NONE) {
|
||||||
SetRoadTypes(tile, GetRoadTypes(tile) & ~RoadTypeToRoadTypes(rt));
|
/* If the owner of the bridge sells all its road, also move the ownership
|
||||||
|
* to the owner of the other roadtype, unless the bridge owner is a town. */
|
||||||
|
|
||||||
/* If the owner of the bridge sells all its road, also move the ownership
|
Owner other_owner = GetRoadOwner(tile, other_rt);
|
||||||
* to the owner of the other roadtype, unless the bridge owner is a town. */
|
if (!IsTileOwner(tile, other_owner) && !IsTileOwner(tile, OWNER_TOWN)) {
|
||||||
RoadType other_rt = (rt == ROADTYPE_ROAD) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
|
SetTileOwner(tile, other_owner);
|
||||||
Owner other_owner = GetRoadOwner(tile, other_rt);
|
SetTileOwner(other_end, other_owner);
|
||||||
if (!IsTileOwner(tile, other_owner) && !IsTileOwner(tile, OWNER_TOWN)) {
|
}
|
||||||
SetTileOwner(tile, other_owner);
|
|
||||||
SetTileOwner(other_end, other_owner);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark tiles dirty that have been repaved */
|
/* Mark tiles dirty that have been repaved */
|
||||||
@@ -252,6 +291,9 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec
|
|||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
MarkTileDirtyByTile(other_end);
|
MarkTileDirtyByTile(other_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AddRoadTunnelBridgeInfrastructure(tile, other_end);
|
||||||
|
DirtyAllCompanyInfrastructureWindows();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(IsDriveThroughStopTile(tile));
|
assert(IsDriveThroughStopTile(tile));
|
||||||
@@ -670,12 +712,108 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
|||||||
|
|
||||||
case MP_TUNNELBRIDGE: {
|
case MP_TUNNELBRIDGE: {
|
||||||
if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) goto do_clear;
|
if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) goto do_clear;
|
||||||
/* Only allow building the outern roadbit, so building long roads stops at existing bridges */
|
|
||||||
if (MirrorRoadBits(DiagDirToRoadBits(GetTunnelBridgeDirection(tile))) != pieces) goto do_clear;
|
const TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
|
||||||
if (HasTileRoadType(tile, rt)) return_cmd_error(STR_ERROR_ALREADY_BUILT);
|
|
||||||
/* Don't allow adding roadtype to the bridge/tunnel when vehicles are already driving on it */
|
if (IsBridge(tile)) {
|
||||||
CommandCost ret = TunnelBridgeIsFree(tile, GetOtherTunnelBridgeEnd(tile));
|
const DiagDirection entrance_dir = GetTunnelBridgeDirection(tile);
|
||||||
if (ret.Failed()) return ret;
|
const RoadBits entrance_piece = DiagDirToRoadBits(entrance_dir);
|
||||||
|
const RoadBits axial_pieces = AxisToRoadBits(DiagDirToAxis(entrance_dir));
|
||||||
|
existing = GetCustomBridgeHeadRoadBits(tile, rt);
|
||||||
|
|
||||||
|
if (!(_settings_game.construction.road_custom_bridge_heads && HasBridgeFlatRamp(tileh, DiagDirToAxis(entrance_dir)))) {
|
||||||
|
/* Ordinary bridge heads only */
|
||||||
|
/* Only allow building the outer roadbit, so building long roads stops at existing bridges */
|
||||||
|
if (MirrorRoadBits(entrance_piece) != pieces) goto do_clear;
|
||||||
|
pieces = axial_pieces;
|
||||||
|
}
|
||||||
|
if ((existing & pieces) == pieces) return_cmd_error(STR_ERROR_ALREADY_BUILT);
|
||||||
|
if ((pieces & ~axial_pieces) && !_settings_game.construction.build_on_slopes) {
|
||||||
|
return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
|
||||||
|
}
|
||||||
|
if ((_invalid_tileh_slopes_road[0][tileh] & (pieces & ~entrance_piece)) != ROAD_NONE) {
|
||||||
|
return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't allow adding roadtype to the bridge/tunnel when vehicles are already driving on it */
|
||||||
|
CommandCost ret = TunnelBridgeIsFree(tile, other_end);
|
||||||
|
if (ret.Failed()) return ret;
|
||||||
|
|
||||||
|
/* check if this end is already owned by someone else */
|
||||||
|
const Owner owner = GetRoadOwner(tile, rt);
|
||||||
|
if (owner != OWNER_NONE) {
|
||||||
|
CommandCost ret = CheckOwnership(owner, tile);
|
||||||
|
if (ret.Failed()) return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((existing | pieces) == entrance_piece) {
|
||||||
|
/*
|
||||||
|
* Don't allow the custom bridge head bits to be only the entrance piece
|
||||||
|
* as this makes road vehicles go haywire
|
||||||
|
*/
|
||||||
|
pieces = axial_pieces;
|
||||||
|
}
|
||||||
|
|
||||||
|
RoadBits added_pieces = (existing | pieces) & ~existing;
|
||||||
|
uint added_pieces_count = CountBits(added_pieces);
|
||||||
|
RoadBits other_end_added_pieces = ROAD_NONE;
|
||||||
|
RoadBits other_end_existing = ROAD_NONE;
|
||||||
|
|
||||||
|
if (added_pieces & entrance_piece) {
|
||||||
|
/* adding road to whole bridge */
|
||||||
|
|
||||||
|
/* check if other end is already owned by someone else */
|
||||||
|
const Owner other_end_owner = GetRoadOwner(other_end, rt);
|
||||||
|
if (other_end_owner != OWNER_NONE) {
|
||||||
|
CommandCost ret = CheckOwnership(other_end_owner, other_end);
|
||||||
|
if (ret.Failed()) return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
other_end_added_pieces = MirrorRoadBits(entrance_piece);
|
||||||
|
added_pieces_count += 1 + (GetTunnelBridgeLength(tile, other_end) * 2);
|
||||||
|
|
||||||
|
other_end_existing = GetCustomBridgeHeadRoadBits(other_end, rt);
|
||||||
|
assert((other_end_added_pieces & other_end_existing) == ROAD_NONE);
|
||||||
|
|
||||||
|
if (other_end_existing == ROAD_NONE) {
|
||||||
|
/*
|
||||||
|
* Don't allow the other end custom bridge head bits to be only the entrance piece
|
||||||
|
* as this makes road vehicles go haywire
|
||||||
|
*/
|
||||||
|
other_end_added_pieces = axial_pieces;
|
||||||
|
added_pieces_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cost.AddCost(added_pieces_count * _price[PR_BUILD_ROAD]);
|
||||||
|
|
||||||
|
if (flags & DC_EXEC) {
|
||||||
|
SubtractRoadTunnelBridgeInfrastructure(tile, other_end);
|
||||||
|
|
||||||
|
SetRoadTypes(tile, GetRoadTypes(tile) | RoadTypeToRoadTypes(rt));
|
||||||
|
SetRoadOwner(tile, rt, company);
|
||||||
|
SetCustomBridgeHeadRoadBits(tile, rt, existing | pieces);
|
||||||
|
if (other_end_added_pieces) {
|
||||||
|
SetRoadTypes(other_end, GetRoadTypes(other_end) | RoadTypeToRoadTypes(rt));
|
||||||
|
SetRoadOwner(other_end, rt, company);
|
||||||
|
SetCustomBridgeHeadRoadBits(other_end, rt, other_end_existing | other_end_added_pieces);
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkBridgeDirty(tile);
|
||||||
|
|
||||||
|
AddRoadTunnelBridgeInfrastructure(tile, other_end);
|
||||||
|
DirtyAllCompanyInfrastructureWindows();
|
||||||
|
}
|
||||||
|
|
||||||
|
return cost;
|
||||||
|
} else { // IsTunnel(tile)
|
||||||
|
/* Only allow building the outer roadbit, so building long roads stops at existing bridges */
|
||||||
|
if (MirrorRoadBits(DiagDirToRoadBits(GetTunnelBridgeDirection(tile))) != pieces) goto do_clear;
|
||||||
|
if (HasTileRoadType(tile, rt)) return_cmd_error(STR_ERROR_ALREADY_BUILT);
|
||||||
|
/* Don't allow adding roadtype to the bridge/tunnel when vehicles are already driving on it */
|
||||||
|
CommandCost ret = TunnelBridgeIsFree(tile, other_end);
|
||||||
|
if (ret.Failed()) return ret;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -762,7 +900,7 @@ do_clear:;
|
|||||||
|
|
||||||
/* Mark tiles dirty that have been repaved */
|
/* Mark tiles dirty that have been repaved */
|
||||||
if (IsBridge(tile)) {
|
if (IsBridge(tile)) {
|
||||||
MarkBridgeDirty(tile);
|
NOT_REACHED();
|
||||||
} else {
|
} else {
|
||||||
MarkTileDirtyByTile(other_end);
|
MarkTileDirtyByTile(other_end);
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
@@ -864,8 +1002,6 @@ CommandCost CmdBuildLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 p
|
|||||||
CommandCost cost(EXPENSES_CONSTRUCTION);
|
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||||
CommandCost last_error = CMD_ERROR;
|
CommandCost last_error = CMD_ERROR;
|
||||||
TileIndex tile = start_tile;
|
TileIndex tile = start_tile;
|
||||||
bool had_bridge = false;
|
|
||||||
bool had_tunnel = false;
|
|
||||||
bool had_success = false;
|
bool had_success = false;
|
||||||
bool is_ai = HasBit(p2, 6);
|
bool is_ai = HasBit(p2, 6);
|
||||||
|
|
||||||
@@ -896,27 +1032,21 @@ CommandCost CmdBuildLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 p
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
had_success = true;
|
had_success = true;
|
||||||
/* Only pay for the upgrade on one side of the bridges and tunnels */
|
cost.AddCost(ret);
|
||||||
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
}
|
||||||
if (IsBridge(tile)) {
|
/* Do not run into or across bridges/tunnels */
|
||||||
if (!had_bridge || GetTunnelBridgeDirection(tile) == dir) {
|
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
||||||
cost.AddCost(ret);
|
if (GetTunnelBridgeDirection(tile) == dir) break;
|
||||||
}
|
|
||||||
had_bridge = true;
|
|
||||||
} else { // IsTunnel(tile)
|
|
||||||
if (!had_tunnel || GetTunnelBridgeDirection(tile) == dir) {
|
|
||||||
cost.AddCost(ret);
|
|
||||||
}
|
|
||||||
had_tunnel = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cost.AddCost(ret);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tile == end_tile) break;
|
if (tile == end_tile) break;
|
||||||
|
|
||||||
tile += TileOffsByDiagDir(dir);
|
tile += TileOffsByDiagDir(dir);
|
||||||
|
|
||||||
|
/* Do not run onto a bridge/tunnel tile from below/above */
|
||||||
|
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
||||||
|
if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(dir)) break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return had_success ? cost : last_error;
|
return had_success ? cost : last_error;
|
||||||
@@ -1239,16 +1369,17 @@ static void DrawRoadDetail(SpriteID img, const TileInfo *ti, int dx, int dy, int
|
|||||||
* Draw ground sprite and road pieces
|
* Draw ground sprite and road pieces
|
||||||
* @param ti TileInfo
|
* @param ti TileInfo
|
||||||
*/
|
*/
|
||||||
static void DrawRoadBits(TileInfo *ti)
|
void DrawRoadBits(TileInfo *ti)
|
||||||
{
|
{
|
||||||
RoadBits road = GetRoadBits(ti->tile, ROADTYPE_ROAD);
|
const bool is_bridge = IsTileType(ti->tile, MP_TUNNELBRIDGE);
|
||||||
RoadBits tram = GetRoadBits(ti->tile, ROADTYPE_TRAM);
|
RoadBits road = is_bridge ? GetCustomBridgeHeadRoadBits(ti->tile, ROADTYPE_ROAD) : GetRoadBits(ti->tile, ROADTYPE_ROAD);
|
||||||
|
RoadBits tram = is_bridge ? GetCustomBridgeHeadRoadBits(ti->tile, ROADTYPE_TRAM) : GetRoadBits(ti->tile, ROADTYPE_TRAM);
|
||||||
|
|
||||||
SpriteID image = 0;
|
SpriteID image = 0;
|
||||||
PaletteID pal = PAL_NONE;
|
PaletteID pal = PAL_NONE;
|
||||||
|
|
||||||
if (ti->tileh != SLOPE_FLAT) {
|
if (ti->tileh != SLOPE_FLAT) {
|
||||||
DrawFoundation(ti, GetRoadFoundation(ti->tileh, road | tram));
|
DrawFoundation(ti, is_bridge ? FOUNDATION_LEVELED : GetRoadFoundation(ti->tileh, road | tram));
|
||||||
|
|
||||||
/* DrawFoundation() modifies ti.
|
/* DrawFoundation() modifies ti.
|
||||||
* Default sloped sprites.. */
|
* Default sloped sprites.. */
|
||||||
@@ -1257,7 +1388,7 @@ static void DrawRoadBits(TileInfo *ti)
|
|||||||
|
|
||||||
if (image == 0) image = _road_tile_sprites_1[road != ROAD_NONE ? road : tram];
|
if (image == 0) image = _road_tile_sprites_1[road != ROAD_NONE ? road : tram];
|
||||||
|
|
||||||
Roadside roadside = GetRoadside(ti->tile);
|
Roadside roadside = is_bridge ? ROADSIDE_PAVED : GetRoadside(ti->tile);
|
||||||
|
|
||||||
if (DrawRoadAsSnowDesert(ti->tile, roadside)) {
|
if (DrawRoadAsSnowDesert(ti->tile, roadside)) {
|
||||||
image += 19;
|
image += 19;
|
||||||
@@ -1285,14 +1416,14 @@ static void DrawRoadBits(TileInfo *ti)
|
|||||||
DrawGroundSprite(image, pal);
|
DrawGroundSprite(image, pal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (road != ROAD_NONE) {
|
if (!is_bridge && road != ROAD_NONE) {
|
||||||
DisallowedRoadDirections drd = GetDisallowedRoadDirections(ti->tile);
|
DisallowedRoadDirections drd = GetDisallowedRoadDirections(ti->tile);
|
||||||
if (drd != DRD_NONE) {
|
if (drd != DRD_NONE) {
|
||||||
DrawGroundSpriteAt(SPR_ONEWAY_BASE + drd - 1 + ((road == ROAD_X) ? 0 : 3), PAL_NONE, 8, 8, GetPartialPixelZ(8, 8, ti->tileh));
|
DrawGroundSpriteAt(SPR_ONEWAY_BASE + drd - 1 + ((road == ROAD_X) ? 0 : 3), PAL_NONE, 8, 8, GetPartialPixelZ(8, 8, ti->tileh));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasRoadWorks(ti->tile)) {
|
if (!is_bridge && HasRoadWorks(ti->tile)) {
|
||||||
/* Road works */
|
/* Road works */
|
||||||
DrawGroundSprite((road | tram) & ROAD_X ? SPR_EXCAVATION_X : SPR_EXCAVATION_Y, PAL_NONE);
|
DrawGroundSprite((road | tram) & ROAD_X ? SPR_EXCAVATION_X : SPR_EXCAVATION_Y, PAL_NONE);
|
||||||
return;
|
return;
|
||||||
@@ -1587,7 +1718,7 @@ static bool ClickTile_Road(TileIndex tile)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Converts RoadBits to TrackBits */
|
/* Converts RoadBits to TrackBits */
|
||||||
static const TrackBits _road_trackbits[16] = {
|
extern const TrackBits _road_trackbits[16] = {
|
||||||
TRACK_BIT_NONE, // ROAD_NONE
|
TRACK_BIT_NONE, // ROAD_NONE
|
||||||
TRACK_BIT_NONE, // ROAD_NW
|
TRACK_BIT_NONE, // ROAD_NW
|
||||||
TRACK_BIT_NONE, // ROAD_SW
|
TRACK_BIT_NONE, // ROAD_SW
|
||||||
|
@@ -52,6 +52,7 @@ RoadBits GetAnyRoadBits(TileIndex tile, RoadType rt, bool straight_tunnel_bridge
|
|||||||
|
|
||||||
case MP_TUNNELBRIDGE:
|
case MP_TUNNELBRIDGE:
|
||||||
if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) return ROAD_NONE;
|
if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) return ROAD_NONE;
|
||||||
|
if (IsRoadCustomBridgeHeadTile(tile)) return GetCustomBridgeHeadRoadBits(tile, rt);
|
||||||
return straight_tunnel_bridge_entrance ?
|
return straight_tunnel_bridge_entrance ?
|
||||||
AxisToRoadBits(DiagDirToAxis(GetTunnelBridgeDirection(tile))) :
|
AxisToRoadBits(DiagDirToAxis(GetTunnelBridgeDirection(tile))) :
|
||||||
DiagDirToRoadBits(ReverseDiagDir(GetTunnelBridgeDirection(tile)));
|
DiagDirToRoadBits(ReverseDiagDir(GetTunnelBridgeDirection(tile)));
|
||||||
|
@@ -1143,6 +1143,8 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
|
|||||||
* by the previous vehicle in the chain when it gets to the right place. */
|
* by the previous vehicle in the chain when it gets to the right place. */
|
||||||
if (v->IsInDepot()) return true;
|
if (v->IsInDepot()) return true;
|
||||||
|
|
||||||
|
bool no_advance_tile = false;
|
||||||
|
|
||||||
if (v->state == RVSB_WORMHOLE) {
|
if (v->state == RVSB_WORMHOLE) {
|
||||||
/* Vehicle is entering a depot or is on a bridge or in a tunnel */
|
/* Vehicle is entering a depot or is on a bridge or in a tunnel */
|
||||||
GetNewVehiclePosResult gp = GetNewVehiclePos(v);
|
GetNewVehiclePosResult gp = GetNewVehiclePos(v);
|
||||||
@@ -1156,19 +1158,24 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
|
if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
|
||||||
/* Vehicle has just entered a bridge or tunnel */
|
if (IsRoadCustomBridgeHeadTile(gp.new_tile)) {
|
||||||
|
v->frame = 15;
|
||||||
|
no_advance_tile = true;
|
||||||
|
} else {
|
||||||
|
/* Vehicle has just entered a bridge or tunnel */
|
||||||
|
v->x_pos = gp.x;
|
||||||
|
v->y_pos = gp.y;
|
||||||
|
v->UpdatePosition();
|
||||||
|
v->UpdateInclination(true, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
v->x_pos = gp.x;
|
v->x_pos = gp.x;
|
||||||
v->y_pos = gp.y;
|
v->y_pos = gp.y;
|
||||||
v->UpdatePosition();
|
v->UpdatePosition();
|
||||||
v->UpdateInclination(true, true);
|
if ((v->vehstatus & VS_HIDDEN) == 0) v->Vehicle::UpdateViewport(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
v->x_pos = gp.x;
|
|
||||||
v->y_pos = gp.y;
|
|
||||||
v->UpdatePosition();
|
|
||||||
if ((v->vehstatus & VS_HIDDEN) == 0) v->Vehicle::UpdateViewport(true);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get move position data for next frame.
|
/* Get move position data for next frame.
|
||||||
@@ -1179,12 +1186,16 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
|
|||||||
(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking][v->frame + 1];
|
(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking][v->frame + 1];
|
||||||
|
|
||||||
if (rd.x & RDE_NEXT_TILE) {
|
if (rd.x & RDE_NEXT_TILE) {
|
||||||
TileIndex tile = v->tile + TileOffsByDiagDir((DiagDirection)(rd.x & 3));
|
TileIndex tile = v->tile;
|
||||||
|
if (!no_advance_tile) tile += TileOffsByDiagDir((DiagDirection)(rd.x & 3));
|
||||||
Trackdir dir;
|
Trackdir dir;
|
||||||
|
|
||||||
if (v->IsFrontEngine()) {
|
if (v->IsFrontEngine()) {
|
||||||
/* If this is the front engine, look for the right path. */
|
/* If this is the front engine, look for the right path. */
|
||||||
dir = RoadFindPathToDest(v, tile, (DiagDirection)(rd.x & 3));
|
dir = RoadFindPathToDest(v, tile, (DiagDirection)(rd.x & 3));
|
||||||
|
} else if (no_advance_tile) {
|
||||||
|
/* Follow previous vehicle out of custom bridge wormhole */
|
||||||
|
dir = (Trackdir) prev->state;
|
||||||
} else {
|
} else {
|
||||||
dir = FollowPreviousRoadVehicle(v, prev, tile, (DiagDirection)(rd.x & 3), false);
|
dir = FollowPreviousRoadVehicle(v, prev, tile, (DiagDirection)(rd.x & 3), false);
|
||||||
}
|
}
|
||||||
@@ -1201,6 +1212,10 @@ again:
|
|||||||
/* When turning around we can't be overtaking. */
|
/* When turning around we can't be overtaking. */
|
||||||
v->overtaking = 0;
|
v->overtaking = 0;
|
||||||
|
|
||||||
|
if (no_advance_tile) {
|
||||||
|
DEBUG(misc, 0, "Road vehicle attempted to turn around on a single road piece bridge head");
|
||||||
|
}
|
||||||
|
|
||||||
/* Turning around */
|
/* Turning around */
|
||||||
if (v->roadtype == ROADTYPE_TRAM) {
|
if (v->roadtype == ROADTYPE_TRAM) {
|
||||||
/* Determine the road bits the tram needs to be able to turn around
|
/* Determine the road bits the tram needs to be able to turn around
|
||||||
@@ -1213,9 +1228,16 @@ again:
|
|||||||
case TRACKDIR_RVREV_SW: needed = ROAD_NE; break;
|
case TRACKDIR_RVREV_SW: needed = ROAD_NE; break;
|
||||||
case TRACKDIR_RVREV_NW: needed = ROAD_SE; break;
|
case TRACKDIR_RVREV_NW: needed = ROAD_SE; break;
|
||||||
}
|
}
|
||||||
if ((v->Previous() != NULL && v->Previous()->tile == tile) ||
|
auto tile_turn_ok = [&]() -> bool {
|
||||||
(v->IsFrontEngine() && IsNormalRoadTile(tile) && !HasRoadWorks(tile) &&
|
if (IsNormalRoadTile(tile)) {
|
||||||
(needed & GetRoadBits(tile, ROADTYPE_TRAM)) != ROAD_NONE)) {
|
return !HasRoadWorks(tile) && (needed & GetRoadBits(tile, ROADTYPE_TRAM)) != ROAD_NONE;
|
||||||
|
} else if (IsRoadCustomBridgeHeadTile(tile)) {
|
||||||
|
return (needed & GetCustomBridgeHeadRoadBits(tile, ROADTYPE_TRAM)) != ROAD_NONE;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if ((v->Previous() != NULL && v->Previous()->tile == tile) || tile_turn_ok()) {
|
||||||
/*
|
/*
|
||||||
* Taking the 'big' corner for trams only happens when:
|
* Taking the 'big' corner for trams only happens when:
|
||||||
* - The previous vehicle in this (articulated) tram chain is
|
* - The previous vehicle in this (articulated) tram chain is
|
||||||
|
@@ -200,7 +200,8 @@ void AfterLoadCompanyStats()
|
|||||||
if (tile < other_end) {
|
if (tile < other_end) {
|
||||||
/* Count each tunnel/bridge TUNNELBRIDGE_TRACKBIT_FACTOR times to simulate
|
/* Count each tunnel/bridge TUNNELBRIDGE_TRACKBIT_FACTOR times to simulate
|
||||||
* the higher structural maintenance needs, and don't forget the end tiles. */
|
* the higher structural maintenance needs, and don't forget the end tiles. */
|
||||||
uint len = (GetTunnelBridgeLength(tile, other_end) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
const uint middle_len = GetTunnelBridgeLength(tile, other_end) * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||||
|
const uint len = middle_len + (2 * TUNNELBRIDGE_TRACKBIT_FACTOR);
|
||||||
|
|
||||||
switch (GetTunnelBridgeTransportType(tile)) {
|
switch (GetTunnelBridgeTransportType(tile)) {
|
||||||
case TRANSPORT_RAIL:
|
case TRANSPORT_RAIL:
|
||||||
@@ -209,12 +210,7 @@ void AfterLoadCompanyStats()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TRANSPORT_ROAD: {
|
case TRANSPORT_ROAD: {
|
||||||
/* Iterate all present road types as each can have a different owner. */
|
AddRoadTunnelBridgeInfrastructure(tile, other_end);
|
||||||
RoadType rt;
|
|
||||||
FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) {
|
|
||||||
c = Company::GetIfValid(GetRoadOwner(tile, rt));
|
|
||||||
if (c != NULL) c->infrastructure.road[rt] += len * 2; // A full diagonal road has two road bits.
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -52,6 +52,8 @@ TileIndex _build_tunnel_endtile; ///< The end of a tunnel; as hidden return from
|
|||||||
/** Z position of the bridge sprites relative to bridge height (downwards) */
|
/** Z position of the bridge sprites relative to bridge height (downwards) */
|
||||||
static const int BRIDGE_Z_START = 3;
|
static const int BRIDGE_Z_START = 3;
|
||||||
|
|
||||||
|
extern void DrawRoadBits(TileInfo *ti);
|
||||||
|
extern const RoadBits _invalid_tileh_slopes_road[2][15];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark bridge tiles dirty.
|
* Mark bridge tiles dirty.
|
||||||
@@ -925,19 +927,11 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
|
|||||||
if (rail) {
|
if (rail) {
|
||||||
if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||||
} else if (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD) {
|
} else if (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD) {
|
||||||
RoadType rt;
|
SubtractRoadTunnelBridgeInfrastructure(tile, endtile);
|
||||||
FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) {
|
|
||||||
Company *c = Company::GetIfValid(GetRoadOwner(tile, rt));
|
|
||||||
if (c != NULL) {
|
|
||||||
/* A full diagonal road tile has two road bits. */
|
|
||||||
c->infrastructure.road[rt] -= len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
|
||||||
DirtyCompanyInfrastructureWindows(c->index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else { // Aqueduct
|
} else { // Aqueduct
|
||||||
if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.water -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.water -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||||
}
|
}
|
||||||
DirtyCompanyInfrastructureWindows(owner);
|
DirtyAllCompanyInfrastructureWindows();
|
||||||
|
|
||||||
DoClearSquare(tile);
|
DoClearSquare(tile);
|
||||||
DoClearSquare(endtile);
|
DoClearSquare(endtile);
|
||||||
@@ -1241,6 +1235,12 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
|
|||||||
|
|
||||||
DrawBridgeMiddle(ti);
|
DrawBridgeMiddle(ti);
|
||||||
} else { // IsBridge(ti->tile)
|
} else { // IsBridge(ti->tile)
|
||||||
|
if (transport_type == TRANSPORT_ROAD && IsRoadCustomBridgeHead(ti->tile)) {
|
||||||
|
DrawRoadBits(ti);
|
||||||
|
DrawBridgeMiddle(ti);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const PalSpriteID *psid;
|
const PalSpriteID *psid;
|
||||||
int base_offset;
|
int base_offset;
|
||||||
bool ice = HasTunnelBridgeSnowOrDesert(ti->tile);
|
bool ice = HasTunnelBridgeSnowOrDesert(ti->tile);
|
||||||
@@ -1462,11 +1462,19 @@ void DrawBridgeMiddle(const TileInfo *ti)
|
|||||||
psid++;
|
psid++;
|
||||||
|
|
||||||
if (transport_type == TRANSPORT_ROAD) {
|
if (transport_type == TRANSPORT_ROAD) {
|
||||||
RoadTypes rts = GetRoadTypes(rampsouth);
|
const RoadTypes rts = GetRoadTypes(rampsouth);
|
||||||
|
|
||||||
if (HasBit(rts, ROADTYPE_TRAM)) {
|
bool has_tram = HasBit(rts, ROADTYPE_TRAM);
|
||||||
|
bool has_road = HasBit(rts, ROADTYPE_ROAD);
|
||||||
|
if (IsRoadCustomBridgeHeadTile(rampsouth)) {
|
||||||
|
RoadBits entrance_bit = DiagDirToRoadBits(GetTunnelBridgeDirection(rampsouth));
|
||||||
|
has_tram = has_tram && (GetCustomBridgeHeadRoadBits(rampsouth, ROADTYPE_TRAM) & entrance_bit);
|
||||||
|
has_road = has_road && (GetCustomBridgeHeadRoadBits(rampsouth, ROADTYPE_ROAD) & entrance_bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_tram) {
|
||||||
/* DrawBridgeTramBits() calls EndSpriteCombine() and StartSpriteCombine() */
|
/* DrawBridgeTramBits() calls EndSpriteCombine() and StartSpriteCombine() */
|
||||||
DrawBridgeTramBits(x, y, bridge_z, axis ^ 1, HasBit(rts, ROADTYPE_ROAD), false);
|
DrawBridgeTramBits(x, y, bridge_z, axis ^ 1, has_road, false);
|
||||||
} else {
|
} else {
|
||||||
EndSpriteCombine();
|
EndSpriteCombine();
|
||||||
StartSpriteCombine();
|
StartSpriteCombine();
|
||||||
@@ -1547,6 +1555,10 @@ static int GetSlopePixelZ_TunnelBridge(TileIndex tile, uint x, uint y)
|
|||||||
/* In the tunnel entrance? */
|
/* In the tunnel entrance? */
|
||||||
if (5 <= pos && pos <= 10) return z;
|
if (5 <= pos && pos <= 10) return z;
|
||||||
} else { // IsBridge(tile)
|
} else { // IsBridge(tile)
|
||||||
|
if (IsRoadCustomBridgeHeadTile(tile)) {
|
||||||
|
return z + TILE_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
DiagDirection dir = GetTunnelBridgeDirection(tile);
|
DiagDirection dir = GetTunnelBridgeDirection(tile);
|
||||||
uint pos = (DiagDirToAxis(dir) == AXIS_X ? y : x);
|
uint pos = (DiagDirToAxis(dir) == AXIS_X ? y : x);
|
||||||
|
|
||||||
@@ -1574,6 +1586,7 @@ static int GetSlopePixelZ_TunnelBridge(TileIndex tile, uint x, uint y)
|
|||||||
|
|
||||||
static Foundation GetFoundation_TunnelBridge(TileIndex tile, Slope tileh)
|
static Foundation GetFoundation_TunnelBridge(TileIndex tile, Slope tileh)
|
||||||
{
|
{
|
||||||
|
if (IsRoadCustomBridgeHeadTile(tile)) return FOUNDATION_LEVELED;
|
||||||
return IsTunnel(tile) ? FOUNDATION_NONE : GetBridgeFoundation(tileh, DiagDirToAxis(GetTunnelBridgeDirection(tile)));
|
return IsTunnel(tile) ? FOUNDATION_NONE : GetBridgeFoundation(tileh, DiagDirToAxis(GetTunnelBridgeDirection(tile)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1654,42 +1667,102 @@ static void TileLoop_TunnelBridge(TileIndex tile)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern const TrackBits _road_trackbits[16];
|
||||||
|
|
||||||
static TrackStatus GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
|
static TrackStatus GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
|
||||||
{
|
{
|
||||||
TransportType transport_type = GetTunnelBridgeTransportType(tile);
|
TransportType transport_type = GetTunnelBridgeTransportType(tile);
|
||||||
if (transport_type != mode || (transport_type == TRANSPORT_ROAD && (GetRoadTypes(tile) & sub_mode) == 0)) return 0;
|
if (transport_type != mode || (transport_type == TRANSPORT_ROAD && (GetRoadTypes(tile) & sub_mode) == 0)) return 0;
|
||||||
|
|
||||||
DiagDirection dir = GetTunnelBridgeDirection(tile);
|
DiagDirection dir = GetTunnelBridgeDirection(tile);
|
||||||
|
|
||||||
|
if (mode == TRANSPORT_ROAD && IsRoadCustomBridgeHeadTile(tile)) {
|
||||||
|
if (side != INVALID_DIAGDIR && side == dir) return 0;
|
||||||
|
TrackBits bits = TRACK_BIT_NONE;
|
||||||
|
if (sub_mode & ROADTYPES_TRAM) bits |= _road_trackbits[GetCustomBridgeHeadRoadBits(tile, ROADTYPE_TRAM)];
|
||||||
|
if (sub_mode & ROADTYPES_ROAD) bits |= _road_trackbits[GetCustomBridgeHeadRoadBits(tile, ROADTYPE_ROAD)];
|
||||||
|
return CombineTrackStatus(TrackBitsToTrackdirBits(bits), TRACKDIR_BIT_NONE);
|
||||||
|
}
|
||||||
if (side != INVALID_DIAGDIR && side != ReverseDiagDir(dir)) return 0;
|
if (side != INVALID_DIAGDIR && side != ReverseDiagDir(dir)) return 0;
|
||||||
return CombineTrackStatus(TrackBitsToTrackdirBits(DiagDirToDiagTrackBits(dir)), TRACKDIR_BIT_NONE);
|
return CombineTrackStatus(TrackBitsToTrackdirBits(DiagDirToDiagTrackBits(dir)), TRACKDIR_BIT_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void UpdateRoadTunnelBridgeInfrastructure(TileIndex begin, TileIndex end, bool add) {
|
||||||
|
/* A full diagonal road has two road bits. */
|
||||||
|
const uint middle_len = 2 * GetTunnelBridgeLength(begin, end) * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||||
|
const uint len = middle_len + (2 * TUNNELBRIDGE_TRACKBIT_FACTOR);
|
||||||
|
|
||||||
|
/* Iterate all present road types as each can have a different owner. */
|
||||||
|
RoadType rt;
|
||||||
|
FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(begin)) {
|
||||||
|
Company * const c = Company::GetIfValid(GetRoadOwner(begin, rt));
|
||||||
|
if (c != NULL) {
|
||||||
|
uint infra = 0;
|
||||||
|
if (IsBridge(begin)) {
|
||||||
|
const RoadBits bits = GetCustomBridgeHeadRoadBits(begin, rt);
|
||||||
|
infra += CountBits(bits) * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||||
|
if (bits & DiagDirToRoadBits(GetTunnelBridgeDirection(begin))) {
|
||||||
|
infra += middle_len;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
infra += len;
|
||||||
|
}
|
||||||
|
if (add) {
|
||||||
|
c->infrastructure.road[rt] += infra;
|
||||||
|
} else {
|
||||||
|
c->infrastructure.road[rt] -= infra;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(end)) {
|
||||||
|
Company * const c = Company::GetIfValid(GetRoadOwner(end, rt));
|
||||||
|
if (c != NULL) {
|
||||||
|
uint infra = 0;
|
||||||
|
if (IsBridge(end)) {
|
||||||
|
const RoadBits bits = GetCustomBridgeHeadRoadBits(end, rt);
|
||||||
|
infra += CountBits(bits) * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||||
|
}
|
||||||
|
if (add) {
|
||||||
|
c->infrastructure.road[rt] += infra;
|
||||||
|
} else {
|
||||||
|
c->infrastructure.road[rt] -= infra;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddRoadTunnelBridgeInfrastructure(TileIndex begin, TileIndex end) {
|
||||||
|
UpdateRoadTunnelBridgeInfrastructure(begin, end, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SubtractRoadTunnelBridgeInfrastructure(TileIndex begin, TileIndex end) {
|
||||||
|
UpdateRoadTunnelBridgeInfrastructure(begin, end, false);
|
||||||
|
}
|
||||||
|
|
||||||
static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner new_owner)
|
static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner new_owner)
|
||||||
{
|
{
|
||||||
TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
|
const TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
|
||||||
/* Set number of pieces to zero if it's the southern tile as we
|
/* Set number of pieces to zero if it's the southern tile as we
|
||||||
* don't want to update the infrastructure counts twice. */
|
* don't want to update the infrastructure counts twice. */
|
||||||
uint num_pieces = tile < other_end ? (GetTunnelBridgeLength(tile, other_end) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR : 0;
|
const uint num_pieces = tile < other_end ? (GetTunnelBridgeLength(tile, other_end) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR : 0;
|
||||||
|
const TransportType tt = GetTunnelBridgeTransportType(tile);
|
||||||
|
|
||||||
|
if (tt == TRANSPORT_ROAD) SubtractRoadTunnelBridgeInfrastructure(tile, other_end);
|
||||||
|
|
||||||
for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) {
|
for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) {
|
||||||
/* Update all roadtypes, no matter if they are present */
|
/* Update all roadtypes, no matter if they are present */
|
||||||
if (GetRoadOwner(tile, rt) == old_owner) {
|
if (GetRoadOwner(tile, rt) == old_owner) {
|
||||||
if (HasBit(GetRoadTypes(tile), rt)) {
|
|
||||||
/* Update company infrastructure counts. A full diagonal road tile has two road bits.
|
|
||||||
* No need to dirty windows here, we'll redraw the whole screen anyway. */
|
|
||||||
Company::Get(old_owner)->infrastructure.road[rt] -= num_pieces * 2;
|
|
||||||
if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += num_pieces * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetRoadOwner(tile, rt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner);
|
SetRoadOwner(tile, rt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tt == TRANSPORT_ROAD) AddRoadTunnelBridgeInfrastructure(tile, other_end);
|
||||||
|
|
||||||
if (!IsTileOwner(tile, old_owner)) return;
|
if (!IsTileOwner(tile, old_owner)) return;
|
||||||
|
|
||||||
/* Update company infrastructure counts for rail and water as well.
|
/* Update company infrastructure counts for rail and water as well.
|
||||||
* No need to dirty windows here, we'll redraw the whole screen anyway. */
|
* No need to dirty windows here, we'll redraw the whole screen anyway. */
|
||||||
TransportType tt = GetTunnelBridgeTransportType(tile);
|
|
||||||
Company *old = Company::Get(old_owner);
|
Company *old = Company::Get(old_owner);
|
||||||
if (tt == TRANSPORT_RAIL) {
|
if (tt == TRANSPORT_RAIL) {
|
||||||
old->infrastructure.rail[GetRailType(tile)] -= num_pieces;
|
old->infrastructure.rail[GetRailType(tile)] -= num_pieces;
|
||||||
@@ -1883,6 +1956,14 @@ static CommandCost TerraformTile_TunnelBridge(TileIndex tile, DoCommandFlag flag
|
|||||||
int z_old;
|
int z_old;
|
||||||
Slope tileh_old = GetTileSlope(tile, &z_old);
|
Slope tileh_old = GetTileSlope(tile, &z_old);
|
||||||
|
|
||||||
|
if (IsRoadCustomBridgeHeadTile(tile)) {
|
||||||
|
const RoadBits pieces = GetCustomBridgeHeadAllRoadBits(tile);
|
||||||
|
const RoadBits entrance_piece = DiagDirToRoadBits(direction);
|
||||||
|
if ((_invalid_tileh_slopes_road[0][tileh_new] & (pieces & ~entrance_piece)) != ROAD_NONE) {
|
||||||
|
return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if new slope is valid for bridges in general (so we can safely call GetBridgeFoundation()) */
|
/* Check if new slope is valid for bridges in general (so we can safely call GetBridgeFoundation()) */
|
||||||
if ((direction == DIAGDIR_NW) || (direction == DIAGDIR_NE)) {
|
if ((direction == DIAGDIR_NW) || (direction == DIAGDIR_NE)) {
|
||||||
CheckBridgeSlopeSouth(axis, &tileh_old, &z_old);
|
CheckBridgeSlopeSouth(axis, &tileh_old, &z_old);
|
||||||
|
@@ -121,4 +121,7 @@ static inline TrackBits GetTunnelBridgeReservationTrackBits(TileIndex t)
|
|||||||
return HasTunnelBridgeReservation(t) ? DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t)) : TRACK_BIT_NONE;
|
return HasTunnelBridgeReservation(t) ? DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t)) : TRACK_BIT_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddRoadTunnelBridgeInfrastructure(TileIndex begin, TileIndex end);
|
||||||
|
void SubtractRoadTunnelBridgeInfrastructure(TileIndex begin, TileIndex end);
|
||||||
|
|
||||||
#endif /* TUNNELBRIDGE_MAP_H */
|
#endif /* TUNNELBRIDGE_MAP_H */
|
||||||
|
Reference in New Issue
Block a user