1
0
Fork 0

(svn r5070) Merged the bridge branch

-Feature: Bridges can now be placed above:
	Any railway track combination (excluding depots and waypoints)
	Any road combination (excluding depots)
	Clear tiles (duh), including fields
	Tunnel entrances
	Bridge heads

Thanks to Tron for idea and implementation, KUDr for the yapf synchronization and many others for hours of testing

There are still a number of visual problems remaining, especially when electric railways are on or under the bridge.
DO NOT REPORT THOSE BUGS FOR THE TIME BEING please.
release/0.5
celestar 2006-06-02 13:05:41 +00:00
parent d680fcec77
commit 25a63ec7af
33 changed files with 776 additions and 981 deletions

7
BUGS
View File

@ -1,7 +1,12 @@
/* $Id */ /* $Id$ */
KNOWN BUGS / PROBLEMS: KNOWN BUGS / PROBLEMS:
bridges:
Graphical problems, especially in conjunction with signals and catenary
electrified rails:
Normal and elrail depots look the same. Use 'X' (transparent buildings) Normal and elrail depots look the same. Use 'X' (transparent buildings)
to distinguish between them to distinguish between them
Missing curors / icons for construction (currently using the conventional ones) Missing curors / icons for construction (currently using the conventional ones)

View File

@ -2158,9 +2158,7 @@ static bool AiRemoveTileAndGoForward(Player *p)
return false; return false;
p->ai.cur_tile_a = TILE_MASK(_build_tunnel_endtile - TileOffsByDir(p->ai.cur_dir_a)); p->ai.cur_tile_a = TILE_MASK(_build_tunnel_endtile - TileOffsByDir(p->ai.cur_dir_a));
return true; return true;
} } else {
if (IsBridgeRamp(tile)) {
// Check if the bridge points in the right direction. // Check if the bridge points in the right direction.
// This is not really needed the first place AiRemoveTileAndGoForward is called. // This is not really needed the first place AiRemoveTileAndGoForward is called.
if (DiagDirToAxis(GetBridgeRampDirection(tile)) != (p->ai.cur_dir_a & 1U)) return false; if (DiagDirToAxis(GetBridgeRampDirection(tile)) != (p->ai.cur_dir_a & 1U)) return false;
@ -3692,7 +3690,6 @@ pos_3:
} else if (IsTileType(tile, MP_TUNNELBRIDGE)) { } else if (IsTileType(tile, MP_TUNNELBRIDGE)) {
if (!IsTileOwner(tile, _current_player) || if (!IsTileOwner(tile, _current_player) ||
!IsBridge(tile) || !IsBridge(tile) ||
!IsBridgeRamp(tile) ||
GetBridgeTransportType(tile) != TRANSPORT_RAIL) { GetBridgeTransportType(tile) != TRANSPORT_RAIL) {
return; return;
} }

View File

@ -27,5 +27,6 @@ extern const Bridge orig_bridge[MAX_BRIDGES];
extern Bridge _bridge[MAX_BRIDGES]; extern Bridge _bridge[MAX_BRIDGES];
uint GetBridgeFoundation(Slope tileh, Axis axis); uint GetBridgeFoundation(Slope tileh, Axis axis);
uint SetSpeedLimitOnBridge(Vehicle *);
#endif /* BRIDGE_H */ #endif /* BRIDGE_H */

View File

@ -3,22 +3,25 @@
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "openttd.h"
#include "bridge_map.h" #include "bridge_map.h"
#include "variables.h"
TileIndex GetBridgeEnd(TileIndex tile, DiagDirection dir) TileIndex GetBridgeEnd(TileIndex tile, DiagDirection dir)
{ {
TileIndexDiff delta = TileOffsByDir(dir); TileIndexDiff delta = TileOffsByDir(dir);
assert(DiagDirToAxis(dir) == GetBridgeAxis(tile)); do { tile += delta; } while (IsBridgeAbove(tile) && IsBridgeOfAxis(tile, DiagDirToAxis(dir)));
do {
tile += delta;
} while (!IsBridgeRamp(tile));
return tile; return tile;
} }
TileIndex GetNorthernBridgeEnd(TileIndex t)
{
return GetBridgeEnd(t, ReverseDiagDir(AxisToDiagDir(GetBridgeAxis(t))));
}
TileIndex GetSouthernBridgeEnd(TileIndex t) TileIndex GetSouthernBridgeEnd(TileIndex t)
{ {
return GetBridgeEnd(t, AxisToDiagDir(GetBridgeAxis(t))); return GetBridgeEnd(t, AxisToDiagDir(GetBridgeAxis(t)));
@ -27,11 +30,25 @@ TileIndex GetSouthernBridgeEnd(TileIndex t)
TileIndex GetOtherBridgeEnd(TileIndex tile) TileIndex GetOtherBridgeEnd(TileIndex tile)
{ {
TileIndexDiff delta = TileOffsByDir(GetBridgeRampDirection(tile)); assert(IsBridgeTile(tile));
return GetBridgeEnd(tile, GetBridgeRampDirection(tile));
do { }
tile += delta;
} while (!IsBridgeRamp(tile)); uint GetBridgeHeight(TileIndex tile, Axis a)
{
return tile; uint h, f;
uint tileh = GetTileSlope(tile, &h);
f = GetBridgeFoundation(tileh, a);
if (f) {
if (f < 15) {
h += TILE_HEIGHT;
tileh = SLOPE_FLAT;
} else {
tileh = _inclined_tileh[f - 15];
}
}
return h + TILE_HEIGHT;
} }

View File

@ -11,6 +11,9 @@
#include "tile.h" #include "tile.h"
void DrawBridgeMiddle(const TileInfo* ti); // XXX
static inline bool IsBridge(TileIndex t) static inline bool IsBridge(TileIndex t)
{ {
assert(IsTileType(t, MP_TUNNELBRIDGE)); assert(IsTileType(t, MP_TUNNELBRIDGE));
@ -23,28 +26,38 @@ static inline bool IsBridgeTile(TileIndex t)
} }
static inline bool IsBridgeRamp(TileIndex t) static inline bool MayHaveBridgeAbove(TileIndex t)
{ {
assert(IsBridgeTile(t)); return
return !HASBIT(_m[t].m5, 6); IsTileType(t, MP_CLEAR) ||
} IsTileType(t, MP_RAILWAY) ||
IsTileType(t, MP_STREET) ||
static inline bool IsBridgeMiddle(TileIndex t) IsTileType(t, MP_WATER) ||
{ IsTileType(t, MP_TUNNELBRIDGE);
assert(IsBridgeTile(t));
return HASBIT(_m[t].m5, 6);
} }
/** static inline bool IsXBridgeAbove(TileIndex t)
* Determines which piece of a bridge is contained in the current tile
* @param tile The tile to analyze
* @return the piece
*/
static inline uint GetBridgePiece(TileIndex t)
{ {
assert(IsBridgeMiddle(t)); assert(MayHaveBridgeAbove(t));
return GB(_m[t].m2, 0, 4); return GB(_m[t].extra, 6, 1) != 0;
}
static inline bool IsYBridgeAbove(TileIndex t)
{
assert(MayHaveBridgeAbove(t));
return GB(_m[t].extra, 7, 1) != 0;
}
static inline bool IsBridgeOfAxis(TileIndex t, Axis a)
{
if (a == AXIS_X) return IsXBridgeAbove(t);
return IsYBridgeAbove(t);
}
static inline bool IsBridgeAbove(TileIndex t)
{
return (IsXBridgeAbove(t) || IsYBridgeAbove(t));
} }
@ -65,7 +78,6 @@ static inline uint GetBridgeType(TileIndex t)
*/ */
static inline DiagDirection GetBridgeRampDirection(TileIndex t) static inline DiagDirection GetBridgeRampDirection(TileIndex t)
{ {
assert(IsBridgeRamp(t));
/* Heavy wizardry to convert the X/Y (bit 0) + N/S (bit 5) encoding of /* Heavy wizardry to convert the X/Y (bit 0) + N/S (bit 5) encoding of
* bridges to a DiagDirection * bridges to a DiagDirection
*/ */
@ -75,8 +87,9 @@ static inline DiagDirection GetBridgeRampDirection(TileIndex t)
static inline Axis GetBridgeAxis(TileIndex t) static inline Axis GetBridgeAxis(TileIndex t)
{ {
assert(IsBridgeMiddle(t)); static const Axis BridgeAxis[] = {AXIS_END, AXIS_X, AXIS_Y, AXIS_END};
return (Axis)GB(_m[t].m5, 0, 1); assert(IsBridgeAbove(t));
return BridgeAxis[GB(_m[t].extra, 6, 2)];
} }
@ -87,49 +100,16 @@ static inline TransportType GetBridgeTransportType(TileIndex t)
} }
static inline bool IsClearUnderBridge(TileIndex t)
{
assert(IsBridgeMiddle(t));
return GB(_m[t].m5, 3, 3) == 0;
}
static inline bool IsWaterUnderBridge(TileIndex t)
{
assert(IsBridgeMiddle(t));
return GB(_m[t].m5, 3, 3) == 1;
}
static inline bool IsTransportUnderBridge(TileIndex t)
{
assert(IsBridgeMiddle(t));
return HASBIT(_m[t].m5, 5);
}
static inline TransportType GetTransportTypeUnderBridge(TileIndex t)
{
assert(IsTransportUnderBridge(t));
return (TransportType)GB(_m[t].m5, 3, 2);
}
static inline RoadBits GetRoadBitsUnderBridge(TileIndex t)
{
assert(GetTransportTypeUnderBridge(t) == TRANSPORT_ROAD);
return GetBridgeAxis(t) == AXIS_X ? ROAD_Y : ROAD_X;
}
static inline TrackBits GetRailBitsUnderBridge(TileIndex t)
{
assert(GetTransportTypeUnderBridge(t) == TRANSPORT_RAIL);
return GetBridgeAxis(t) == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X;
}
/** /**
* Finds the end of a bridge in the specified direction starting at a middle tile * Finds the end of a bridge in the specified direction starting at a middle tile
*/ */
TileIndex GetBridgeEnd(TileIndex, DiagDirection); TileIndex GetBridgeEnd(TileIndex, DiagDirection);
/**
* Finds the northern end of a bridge starting at a middle tile
*/
TileIndex GetNorthernBridgeEnd(TileIndex t);
/** /**
* Finds the southern end of a bridge starting at a middle tile * Finds the southern end of a bridge starting at a middle tile
*/ */
@ -141,38 +121,26 @@ TileIndex GetSouthernBridgeEnd(TileIndex t);
*/ */
TileIndex GetOtherBridgeEnd(TileIndex); TileIndex GetOtherBridgeEnd(TileIndex);
uint GetBridgeHeight(TileIndex t); uint GetBridgeHeight(TileIndex tile, Axis a);
uint GetBridgeFoundation(Slope tileh, Axis axis);
static inline void SetClearUnderBridge(TileIndex t) static inline void ClearSingleBridgeMiddle(TileIndex t, Axis a)
{ {
assert(IsBridgeMiddle(t)); assert(MayHaveBridgeAbove(t));
SetTileOwner(t, OWNER_NONE); CLRBIT(_m[t].extra, 6 + a);
SB(_m[t].m5, 3, 3, 0 << 2 | 0);
SB(_m[t].m3, 0, 4, 0);
} }
static inline void SetWaterUnderBridge(TileIndex t)
static inline void ClearBridgeMiddle(TileIndex t)
{ {
assert(IsBridgeMiddle(t)); ClearSingleBridgeMiddle(t, AXIS_X);
SetTileOwner(t, OWNER_WATER); ClearSingleBridgeMiddle(t, AXIS_Y);
SB(_m[t].m5, 3, 3, 0 << 2 | 1);
SB(_m[t].m3, 0, 4, 0);
} }
static inline void SetRailUnderBridge(TileIndex t, Owner o, RailType r) static inline void SetBridgeMiddle(TileIndex t, Axis a)
{ {
assert(IsBridgeMiddle(t)); assert(MayHaveBridgeAbove(t));
SetTileOwner(t, o); SETBIT(_m[t].extra, 6 + a);
SB(_m[t].m5, 3, 3, 1 << 2 | TRANSPORT_RAIL);
SB(_m[t].m3, 0, 4, r);
}
static inline void SetRoadUnderBridge(TileIndex t, Owner o)
{
assert(IsBridgeMiddle(t));
SetTileOwner(t, o);
SB(_m[t].m5, 3, 3, 1 << 2 | TRANSPORT_ROAD);
SB(_m[t].m3, 0, 4, 0);
} }
@ -200,26 +168,4 @@ static inline void MakeRailBridgeRamp(TileIndex t, Owner o, uint bridgetype, Dia
} }
static inline void MakeBridgeMiddle(TileIndex t, uint bridgetype, uint piece, Axis a, TransportType tt)
{
SetTileType(t, MP_TUNNELBRIDGE);
SetTileOwner(t, OWNER_NONE);
_m[t].m2 = bridgetype << 4 | piece;
_m[t].m3 = 0;
_m[t].m4 = 0;
_m[t].m5 = 1 << 7 | 1 << 6 | 0 << 5 | 0 << 3 | tt << 1 | a;
}
static inline void MakeRoadBridgeMiddle(TileIndex t, uint bridgetype, uint piece, Axis a)
{
MakeBridgeMiddle(t, bridgetype, piece, a, TRANSPORT_ROAD);
}
static inline void MakeRailBridgeMiddle(TileIndex t, uint bridgetype, uint piece, Axis a, RailType r)
{
MakeBridgeMiddle(t, bridgetype, piece, a, TRANSPORT_RAIL);
SB(_m[t].m3, 4, 4, r);
}
#endif #endif

View File

@ -11,6 +11,7 @@
#include "viewport.h" #include "viewport.h"
#include "command.h" #include "command.h"
#include "tunnel_map.h" #include "tunnel_map.h"
#include "bridge_map.h"
#include "variables.h" #include "variables.h"
#include "table/sprites.h" #include "table/sprites.h"
#include "unmovable_map.h" #include "unmovable_map.h"
@ -259,6 +260,14 @@ int32 CmdTerraformLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
} else return_cmd_error(STR_5800_OBJECT_IN_THE_WAY); } else return_cmd_error(STR_5800_OBJECT_IN_THE_WAY);
} }
if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) {
byte height = GetBridgeHeight(GetNorthernBridgeEnd(tile), GetBridgeAxis(tile));
height /= TILE_HEIGHT;
if (a >= height || b >= height || c >= height || d >= height) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
}
if (direction == -1 && IsTunnelInWay(tile, min)) return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE); if (direction == -1 && IsTunnelInWay(tile, min)) return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
_terraform_err_tile = 0; _terraform_err_tile = 0;
@ -501,6 +510,7 @@ static void DrawTile_Clear(TileInfo *ti)
} }
DrawClearLandFence(ti); DrawClearLandFence(ti);
DrawBridgeMiddle(ti);
} }
static uint GetSlopeZ_Clear(const TileInfo* ti) static uint GetSlopeZ_Clear(const TileInfo* ti)

View File

@ -91,18 +91,10 @@ static TrackBits GetRailTrackBitsUniversal(TileIndex t, byte *override)
return DiagDirToAxis(GetTunnelDirection(t)) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y; return DiagDirToAxis(GetTunnelDirection(t)) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y;
} else { } else {
if (GetRailType(t) != RAILTYPE_ELECTRIC) return 0; if (GetRailType(t) != RAILTYPE_ELECTRIC) return 0;
if (IsBridgeMiddle(t)) { if (override != NULL && DistanceMax(t, GetOtherBridgeEnd(t)) > 1) {
if (IsTransportUnderBridge(t) && *override = 1 << GetBridgeRampDirection(t);
GetTransportTypeUnderBridge(t) == TRANSPORT_RAIL) {
return GetRailBitsUnderBridge(t);
} else {
return 0;
}
} else {
if (override != NULL && DistanceMax(t, GetOtherBridgeEnd(t)) > 1) *override = 1 << GetBridgeRampDirection(t);
return DiagDirToAxis(GetBridgeRampDirection(t)) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y;
} }
return DiagDirToAxis(GetBridgeRampDirection(t)) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y;
} }
case MP_STREET: case MP_STREET:
if (GetRoadTileType(t) != ROAD_TILE_CROSSING) return 0; if (GetRoadTileType(t) != ROAD_TILE_CROSSING) return 0;
@ -125,7 +117,7 @@ static TrackBits GetRailTrackBitsUniversal(TileIndex t, byte *override)
static void AdjustTileh(TileIndex tile, Slope* tileh) static void AdjustTileh(TileIndex tile, Slope* tileh)
{ {
if (IsTunnelTile(tile)) *tileh = SLOPE_FLAT; if (IsTunnelTile(tile)) *tileh = SLOPE_FLAT;
if (IsBridgeTile(tile) && IsBridgeRamp(tile)) { if (IsBridgeTile(tile)) {
if (*tileh != SLOPE_FLAT) { if (*tileh != SLOPE_FLAT) {
*tileh = SLOPE_FLAT; *tileh = SLOPE_FLAT;
} else { } else {
@ -193,9 +185,10 @@ static void DrawCatenaryRailway(const TileInfo *ti)
for (k = 0; k < NUM_TRACKS_AT_PCP; k++) { for (k = 0; k < NUM_TRACKS_AT_PCP; k++) {
/* Next to us, we have a bridge head, don't worry about that one, if it shows away from us */ /* Next to us, we have a bridge head, don't worry about that one, if it shows away from us */
if (TrackSourceTile[i][k] == TS_NEIGHBOUR && if (TrackSourceTile[i][k] == TS_NEIGHBOUR &&
IsBridgeTile(neighbour) && IsBridgeRamp(neighbour) && IsBridgeTile(neighbour) &&
GetBridgeRampDirection(neighbour) == ReverseDiagDir(i) GetBridgeRampDirection(neighbour) == ReverseDiagDir(i)) {
) continue; continue;
}
/* We check whether the track in question (k) is present in the tile /* We check whether the track in question (k) is present in the tile
(TrackSourceTile) */ (TrackSourceTile) */
@ -219,7 +212,7 @@ static void DrawCatenaryRailway(const TileInfo *ti)
/* Read the foundataions if they are present, and adjust the tileh */ /* Read the foundataions if they are present, and adjust the tileh */
if (IsTileType(neighbour, MP_RAILWAY)) foundation = GetRailFoundation(tileh[TS_NEIGHBOUR], trackconfig[TS_NEIGHBOUR]); if (IsTileType(neighbour, MP_RAILWAY)) foundation = GetRailFoundation(tileh[TS_NEIGHBOUR], trackconfig[TS_NEIGHBOUR]);
if (IsBridgeTile(neighbour) && IsBridgeRamp(neighbour)) { if (IsBridgeTile(neighbour)) {
foundation = GetBridgeFoundation(tileh[TS_NEIGHBOUR], DiagDirToAxis(GetBridgeRampDirection(neighbour))); foundation = GetBridgeFoundation(tileh[TS_NEIGHBOUR], DiagDirToAxis(GetBridgeRampDirection(neighbour)));
} }
@ -247,6 +240,14 @@ static void DrawCatenaryRailway(const TileInfo *ti)
Remove those (simply by ANDing with allowed, since these markers are never allowed) */ Remove those (simply by ANDing with allowed, since these markers are never allowed) */
if ( (PPPallowed[i] & PPPpreferred[i]) != 0) PPPallowed[i] &= PPPpreferred[i]; if ( (PPPallowed[i] & PPPpreferred[i]) != 0) PPPallowed[i] &= PPPpreferred[i];
if (MayHaveBridgeAbove(ti->tile) && IsBridgeAbove(ti->tile)) {
Track bridgetrack = GetBridgeAxis(ti->tile) == AXIS_X ? TRACK_X : TRACK_Y;
uint height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile), GetBridgeAxis(ti->tile));
if ((height <= TilePixelHeight(ti->tile) + TILE_HEIGHT) &&
(i == PCPpositions[bridgetrack][0] || i == PCPpositions[bridgetrack][1])) SETBIT(OverridePCP, i);
}
if (PPPallowed[i] != 0 && HASBIT(PCPstatus, i) && !HASBIT(OverridePCP, i)) { if (PPPallowed[i] != 0 && HASBIT(PCPstatus, i) && !HASBIT(OverridePCP, i)) {
for (k = 0; k < DIR_END; k++) { for (k = 0; k < DIR_END; k++) {
byte temp = PPPorder[i][GetTLG(ti->tile)][k]; byte temp = PPPorder[i][GetTLG(ti->tile)][k];
@ -279,12 +280,11 @@ static void DrawCatenaryRailway(const TileInfo *ti)
const SortableSpriteStruct *sss; const SortableSpriteStruct *sss;
int tileh_selector = !(tileh[TS_HOME] % 3) * tileh[TS_HOME] / 3; /* tileh for the slopes, 0 otherwise */ int tileh_selector = !(tileh[TS_HOME] % 3) * tileh[TS_HOME] / 3; /* tileh for the slopes, 0 otherwise */
if ( /* We are not drawing a wire under a low bridge */ if (MayHaveBridgeAbove(ti->tile) && IsBridgeAbove(ti->tile) && !(_display_opt & DO_TRANS_BUILDINGS)) {
IsBridgeTile(ti->tile) && uint height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile), GetBridgeAxis(ti->tile));
IsBridgeMiddle(ti->tile) &&
!(_display_opt & DO_TRANS_BUILDINGS) && if (height <= TilePixelHeight(ti->tile) + TILE_HEIGHT) return;
GetBridgeHeight(ti->tile) <= TilePixelHeight(ti->tile) }
) return;
assert(PCPconfig != 0); /* We have a pylon on neither end of the wire, that doesn't work (since we have no sprites for that) */ assert(PCPconfig != 0); /* We have a pylon on neither end of the wire, that doesn't work (since we have no sprites for that) */
assert(!IsSteepSlope(tileh[TS_HOME])); assert(!IsSteepSlope(tileh[TS_HOME]));
@ -320,30 +320,37 @@ static void DrawCatenaryOnBridge(const TileInfo *ti)
} }
AddSortableSpriteToDraw( sss->image, ti->x + sss->x_offset, ti->y + sss->y_offset, AddSortableSpriteToDraw( sss->image, ti->x + sss->x_offset, ti->y + sss->y_offset,
sss->x_size, sss->y_size, sss->z_size, GetBridgeHeight(ti->tile) + sss->z_offset + 8); sss->x_size, sss->y_size, sss->z_size, GetBridgeHeight(end, axis) + sss->z_offset);
/* Finished with wires, draw pylons */ /* Finished with wires, draw pylons */
/* every other tile needs a pylon on the northern end */ /* every other tile needs a pylon on the northern end */
if (num % 2) { if (num % 2) {
if (axis == AXIS_X) { if (axis == AXIS_X) {
AddSortableSpriteToDraw( pylons_bridge[0 + HASBIT(tlg, 0)], ti->x, ti->y + 4 + 8 * HASBIT(tlg, 0), 1, 1, 10, GetBridgeHeight(ti->tile) + TILE_HEIGHT); AddSortableSpriteToDraw( pylons_bridge[0 + HASBIT(tlg, 0)], ti->x, ti->y + 4 + 8 * HASBIT(tlg, 0), 1, 1, 10, GetBridgeHeight(end, axis));
} else { } else {
AddSortableSpriteToDraw( pylons_bridge[2 + HASBIT(tlg, 1)], ti->x + 4 + 8 * HASBIT(tlg, 1), ti->y, 1, 1, 10, GetBridgeHeight(ti->tile) + TILE_HEIGHT); AddSortableSpriteToDraw( pylons_bridge[2 + HASBIT(tlg, 1)], ti->x + 4 + 8 * HASBIT(tlg, 1), ti->y, 1, 1, 10, GetBridgeHeight(end, axis));
} }
} }
/* need a pylon on the southern end of the bridge */ /* need a pylon on the southern end of the bridge */
if (DistanceMax(ti->tile, start) == length) { if (DistanceMax(ti->tile, start) == length) {
if (axis == AXIS_X) { if (axis == AXIS_X) {
AddSortableSpriteToDraw( pylons_bridge[0 + HASBIT(tlg, 0)], ti->x + 16, ti->y + 4 + 8 * HASBIT(tlg, 0), 1, 1, 10, GetBridgeHeight(ti->tile) + TILE_HEIGHT); AddSortableSpriteToDraw( pylons_bridge[0 + HASBIT(tlg, 0)], ti->x + 16, ti->y + 4 + 8 * HASBIT(tlg, 0), 1, 1, 10, GetBridgeHeight(end, axis));
} else { } else {
AddSortableSpriteToDraw( pylons_bridge[2 + HASBIT(tlg, 1)], ti->x + 4 + 8 * HASBIT(tlg, 1), ti->y + 16, 1, 1, 10, GetBridgeHeight(ti->tile) + TILE_HEIGHT); AddSortableSpriteToDraw( pylons_bridge[2 + HASBIT(tlg, 1)], ti->x + 4 + 8 * HASBIT(tlg, 1), ti->y + 16, 1, 1, 10, GetBridgeHeight(end, axis));
} }
} }
} }
void DrawCatenary(const TileInfo *ti) void DrawCatenary(const TileInfo *ti)
{ {
if (MayHaveBridgeAbove(ti->tile) && IsBridgeAbove(ti->tile)) {
TileIndex head = GetNorthernBridgeEnd(ti->tile);
if (GetBridgeTransportType(head) == TRANSPORT_RAIL && GetRailType(head) == RAILTYPE_ELECTRIC) {
DrawCatenaryOnBridge(ti);
}
}
switch (GetTileType(ti->tile)) { switch (GetTileType(ti->tile)) {
case MP_RAILWAY: case MP_RAILWAY:
if (GetRailTileType(ti->tile) == RAIL_TILE_DEPOT_WAYPOINT && GetRailTileSubtype(ti->tile) == RAIL_SUBTYPE_DEPOT) { if (GetRailTileType(ti->tile) == RAIL_TILE_DEPOT_WAYPOINT && GetRailTileSubtype(ti->tile) == RAIL_SUBTYPE_DEPOT) {
@ -354,9 +361,8 @@ void DrawCatenary(const TileInfo *ti)
} }
/* Fall through */ /* Fall through */
case MP_TUNNELBRIDGE: case MP_TUNNELBRIDGE:
if (IsBridgeTile(ti->tile) && IsBridgeMiddle(ti->tile) && GetRailTypeOnBridge(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenaryOnBridge(ti); case MP_STREET:
/* Fall further */ case MP_STATION:
case MP_STREET: case MP_STATION:
DrawCatenaryRailway(ti); DrawCatenaryRailway(ti);
break; break;
default: default:

View File

@ -2,6 +2,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "openttd.h"
#include "bridge_map.h"
#include "clear_map.h" #include "clear_map.h"
#include "functions.h" #include "functions.h"
#include "map.h" #include "map.h"
@ -387,6 +388,8 @@ void InitializeLandscape(void)
for (x = 0; x < maxx; x++) { for (x = 0; x < maxx; x++) {
MakeClear(sizex * y + x, CLEAR_GRASS, 3); MakeClear(sizex * y + x, CLEAR_GRASS, 3);
SetTileHeight(sizex * y + x, 0); SetTileHeight(sizex * y + x, 0);
_m[sizex * y + x].extra = 0;
ClearBridgeMiddle(sizex * y + x);
} }
MakeVoid(sizex * y + x); MakeVoid(sizex * y + x);
} }

39
misc.c
View File

@ -859,16 +859,26 @@ static void Load_MAPE(void)
uint size = MapSize(); uint size = MapSize();
uint i; uint i;
for (i = 0; i != size;) { if (CheckSavegameVersion(29)) {
uint8 buf[1024]; for (i = 0; i != size;) {
uint j; uint8 buf[1024];
uint j;
SlArray(buf, lengthof(buf), SLE_UINT8); SlArray(buf, lengthof(buf), SLE_UINT8);
for (j = 0; j != lengthof(buf); j++) { for (j = 0; j != lengthof(buf); j++) {
_m[i++].extra = GB(buf[j], 0, 2); _m[i++].extra = GB(buf[j], 0, 2);
_m[i++].extra = GB(buf[j], 2, 2); _m[i++].extra = GB(buf[j], 2, 2);
_m[i++].extra = GB(buf[j], 4, 2); _m[i++].extra = GB(buf[j], 4, 2);
_m[i++].extra = GB(buf[j], 6, 2); _m[i++].extra = GB(buf[j], 6, 2);
}
}
} else {
for (i = 0; i != size;) {
byte buf[4096];
uint j;
SlArray(buf, lengthof(buf), SLE_UINT8);
for (j = 0; j != lengthof(buf); j++) _m[i++].extra = buf[j];
} }
} }
} }
@ -878,17 +888,12 @@ static void Save_MAPE(void)
uint size = MapSize(); uint size = MapSize();
uint i; uint i;
SlSetLength(size / 4); SlSetLength(size);
for (i = 0; i != size;) { for (i = 0; i != size;) {
uint8 buf[1024]; uint8 buf[4096];
uint j; uint j;
for (j = 0; j != lengthof(buf); j++) { for (j = 0; j != lengthof(buf); j++) buf[j] = _m[i++].extra;
buf[j] = _m[i++].extra << 0;
buf[j] |= _m[i++].extra << 2;
buf[j] |= _m[i++].extra << 4;
buf[j] |= _m[i++].extra << 6;
}
SlArray(buf, lengthof(buf), SLE_UINT8); SlArray(buf, lengthof(buf), SLE_UINT8);
} }
} }

27
npf.c
View File

@ -479,17 +479,7 @@ static bool VehicleMayEnterTile(Owner owner, TileIndex tile, DiagDirection enter
case MP_TUNNELBRIDGE: case MP_TUNNELBRIDGE:
if ((IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_RAIL) || if ((IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_RAIL) ||
(IsBridge(tile) && ( (IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_RAIL)) {
(
IsBridgeRamp(tile) &&
GetBridgeTransportType(tile) == TRANSPORT_RAIL
) || (
IsBridgeMiddle(tile) &&
IsTransportUnderBridge(tile) &&
GetTransportTypeUnderBridge(tile) == TRANSPORT_RAIL &&
GetBridgeAxis(tile) != DiagDirToAxis(enterdir)
)
))) {
return IsTileOwner(tile, owner); return IsTileOwner(tile, owner);
} }
break; break;
@ -516,6 +506,7 @@ static void NPFFollowTrack(AyStar* aystar, OpenListNode* current)
int i; int i;
TrackdirBits trackdirbits, ts; TrackdirBits trackdirbits, ts;
TransportType type = aystar->user_data[NPF_TYPE]; TransportType type = aystar->user_data[NPF_TYPE];
bool override_dst_check = false;
/* Initialize to 0, so we can jump out (return) somewhere an have no neighbours */ /* Initialize to 0, so we can jump out (return) somewhere an have no neighbours */
aystar->num_neighbours = 0; aystar->num_neighbours = 0;
DEBUG(npf, 4)("Expanding: (%d, %d, %d) [%d]", TileX(src_tile), TileY(src_tile), src_trackdir, src_tile); DEBUG(npf, 4)("Expanding: (%d, %d, %d) [%d]", TileX(src_tile), TileY(src_tile), src_trackdir, src_tile);
@ -526,6 +517,10 @@ static void NPFFollowTrack(AyStar* aystar, OpenListNode* current)
* otherwise we wouldn't have got here. It is also facing us, * otherwise we wouldn't have got here. It is also facing us,
* so we should skip it's body */ * so we should skip it's body */
dst_tile = GetOtherTunnelEnd(src_tile); dst_tile = GetOtherTunnelEnd(src_tile);
override_dst_check = true;
} else if (IsBridgeTile(src_tile) && GetBridgeRampDirection(src_tile) == src_exitdir) {
dst_tile = GetOtherBridgeEnd(src_tile);
override_dst_check = true;
} else if (type != TRANSPORT_WATER && (IsRoadStopTile(src_tile) || IsTileDepotType(src_tile, type))) { } else if (type != TRANSPORT_WATER && (IsRoadStopTile(src_tile) || IsTileDepotType(src_tile, type))) {
/* This is a road station or a train or road depot. We can enter and exit /* This is a road station or a train or road depot. We can enter and exit
* those from one side only. Trackdirs don't support that (yet), so we'll * those from one side only. Trackdirs don't support that (yet), so we'll
@ -573,8 +568,14 @@ static void NPFFollowTrack(AyStar* aystar, OpenListNode* current)
/* I can't enter a tunnel entry/exit tile from a tile above the tunnel. Note /* I can't enter a tunnel entry/exit tile from a tile above the tunnel. Note
* that I can enter the tunnel from a tile below the tunnel entrance. This * that I can enter the tunnel from a tile below the tunnel entrance. This
* solves the problem of vehicles wanting to drive off a tunnel entrance */ * solves the problem of vehicles wanting to drive off a tunnel entrance */
if (IsTunnelTile(dst_tile) && GetTileZ(dst_tile) < GetTileZ(src_tile)) { if (!override_dst_check) {
return; if (IsTileType(dst_tile, MP_TUNNELBRIDGE)) {
if (IsTunnel(dst_tile)) {
if (GetTunnelDirection(dst_tile) != src_exitdir) return;
} else {
if (GetBridgeRampDirection(dst_tile) != src_exitdir) return;
}
}
} }
/* check correct rail type (mono, maglev, etc) */ /* check correct rail type (mono, maglev, etc) */

View File

@ -49,6 +49,12 @@
#include "yapf/yapf.h" #include "yapf/yapf.h"
#include "settings.h" #include "settings.h"
#include "bridge_map.h"
#include "clear_map.h"
#include "rail_map.h"
#include "road_map.h"
#include "water_map.h"
#include <stdarg.h> #include <stdarg.h>
void GenerateWorld(int mode, uint size_x, uint size_y); void GenerateWorld(int mode, uint size_x, uint size_y);
@ -1256,6 +1262,72 @@ bool AfterLoadGame(void)
} }
} }
if (CheckSavegameVersion(29)) {
TileIndex map_end = MapSize();
TileIndex tile;
Vehicle* v;
for (tile = 0; tile != map_end; tile++) {
if (MayHaveBridgeAbove(tile)) ClearBridgeMiddle(tile);
if (IsTileType(tile, MP_TUNNELBRIDGE) &&
_m[tile].m5 & 0x80 && // bridge
_m[tile].m5 & 0x40) { // middle part
Axis axis = (Axis)GB(_m[tile].m5, 0, 1);
if (_m[tile].m5 & 0x20) { // transport route under bridge?
if (GB(_m[tile].m5, 3, 2) == TRANSPORT_RAIL) {
MakeRailNormal(
tile,
GetTileOwner(tile),
axis == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X,
GetRailType(tile)
);
} else {
uint town = IsTileOwner(tile, OWNER_TOWN) ? ClosestTownFromTile(tile, (uint)-1)->index : 0;
MakeRoadNormal(
tile,
GetTileOwner(tile),
axis == AXIS_X ? ROAD_Y : ROAD_X,
town
);
}
} else {
if (GB(_m[tile].m5, 3, 2) == 0) {
MakeClear(tile, CLEAR_GRASS, 3);
} else {
MakeWater(tile);
}
}
SetBridgeMiddle(tile, axis);
}
}
FOR_ALL_VEHICLES(v) {
if (v->type != VEH_Train && v->type != VEH_Road) continue;
if (IsBridgeTile(v->tile)) {
DiagDirection dir = GetBridgeRampDirection(v->tile);
if (dir != DirToDiagDir(v->direction)) continue;
switch (dir) {
default:
case DIAGDIR_NE: if ((v->x_pos & 0xF) != 0) continue;
case DIAGDIR_SE: if ((v->y_pos & 0xF) != 15) continue;
case DIAGDIR_SW: if ((v->x_pos & 0xF) != 15) continue;
case DIAGDIR_NW: if ((v->y_pos & 0xF) != 0) continue;
}
} else if (v->z_pos <= GetSlopeZ(v->x_pos, v->y_pos)) {
continue;
}
if (!IsBridgeTile(v->tile)) v->tile = GetNorthernBridgeEnd(v->tile);
if (v->type == VEH_Train) {
v->u.rail.track = 0x40;
} else {
v->u.road.state = 0xFF;
}
}
}
/* Elrails got added in rev 24 */ /* Elrails got added in rev 24 */
if (CheckSavegameVersion(24)) { if (CheckSavegameVersion(24)) {
Vehicle* v; Vehicle* v;
@ -1306,15 +1378,6 @@ bool AfterLoadGame(void)
} }
} else { } else {
if (GetBridgeTransportType(t) == TRANSPORT_RAIL) { if (GetBridgeTransportType(t) == TRANSPORT_RAIL) {
if (IsBridgeRamp(t)) {
SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
} else {
SetRailTypeOnBridge(t, UpdateRailType(GetRailTypeOnBridge(t), min_rail));
}
}
if (IsBridgeMiddle(t) &&
IsTransportUnderBridge(t) &&
GetTransportTypeUnderBridge(t) == TRANSPORT_RAIL) {
SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
} }
} }

View File

@ -256,21 +256,27 @@ static void TPFMode1(TrackPathFinder* tpf, TileIndex tile, DiagDirection directi
RememberData rd; RememberData rd;
TileIndex tile_org = tile; TileIndex tile_org = tile;
// check if the old tile can be left at that direction if (IsTileType(tile, MP_TUNNELBRIDGE)) {
if (tpf->tracktype == TRANSPORT_ROAD) { if (IsTunnel(tile)) {
// road stops and depots now have a track (r4419) if (GetTunnelDirection(tile) != direction ||
// don't enter road stop from the back GetTunnelTransportType(tile) != tpf->tracktype) {
if (IsRoadStopTile(tile) && GetRoadStopDir(tile) != direction) return; return;
// don't enter road depot from the back }
if (IsTileDepotType(tile, TRANSPORT_ROAD) && GetRoadDepotDirection(tile) != direction) return; tile = SkipToEndOfTunnel(tpf, tile, direction);
} } else {
TileIndex tile_end;
if (IsTunnelTile(tile)) { if (GetBridgeRampDirection(tile) != direction ||
if (GetTunnelDirection(tile) != direction || GetBridgeTransportType(tile) != tpf->tracktype) {
GetTunnelTransportType(tile) != tpf->tracktype) { return;
return; }
//fprintf(stderr, "%s: Planning over bridge\n", __func__);
// TODO doesn't work - WHAT doesn't work?
TPFSetTileBit(tpf, tile, 14);
tile_end = GetOtherBridgeEnd(tile);
tpf->rd.cur_length += DistanceManhattan(tile, tile_end);
tile = tile_end;
TPFSetTileBit(tpf, tile, 14);
} }
tile = SkipToEndOfTunnel(tpf, tile, direction);
} }
tile += TileOffsByDir(direction); tile += TileOffsByDir(direction);
@ -281,11 +287,7 @@ static void TPFMode1(TrackPathFinder* tpf, TileIndex tile, DiagDirection directi
if (IsTileType(tile_org, MP_RAILWAY) || IsTileType(tile_org, MP_STATION) || IsTileType(tile_org, MP_TUNNELBRIDGE)) if (IsTileType(tile_org, MP_RAILWAY) || IsTileType(tile_org, MP_STATION) || IsTileType(tile_org, MP_TUNNELBRIDGE))
if (IsTileType(tile, MP_RAILWAY) || IsTileType(tile, MP_STATION) || IsTileType(tile, MP_TUNNELBRIDGE)) if (IsTileType(tile, MP_RAILWAY) || IsTileType(tile, MP_STATION) || IsTileType(tile, MP_TUNNELBRIDGE))
/* Check if we are on a bridge (middle parts don't have an owner */ if (GetTileOwner(tile_org) != GetTileOwner(tile)) return;
if (!IsBridgeTile(tile) || !IsBridgeMiddle(tile))
if (!IsBridgeTile(tile_org) || !IsBridgeMiddle(tile_org))
if (GetTileOwner(tile_org) != GetTileOwner(tile))
return;
} }
// check if the new tile can be entered from that direction // check if the new tile can be entered from that direction
@ -673,7 +675,6 @@ static void NTPEnum(NewTrackPathFinder* tpf, TileIndex tile, DiagDirection direc
uint track; uint track;
TileIndex tile_org; TileIndex tile_org;
StackedItem si; StackedItem si;
FindLengthOfTunnelResult flotr;
int estimation; int estimation;
@ -711,22 +712,40 @@ callback_and_continue:
start_at: start_at:
// If the tile is the entry tile of a tunnel, and we're not going out of the tunnel, // If the tile is the entry tile of a tunnel, and we're not going out of the tunnel,
// need to find the exit of the tunnel. // need to find the exit of the tunnel.
if (IsTunnelTile(tile) && if (IsTileType(tile, MP_TUNNELBRIDGE)) {
GetTunnelDirection(tile) != ReverseDiagDir(direction)) { if (IsTunnel(tile)) {
/* We are not just driving out of the tunnel */ if (GetTunnelDirection(tile) != ReverseDiagDir(direction)) {
if (GetTunnelDirection(tile) != direction || FindLengthOfTunnelResult flotr;
GetTunnelTransportType(tile) != tpf->tracktype) {
// We are not driving into the tunnel, or it is an invalid tunnel /* We are not just driving out of the tunnel */
continue; if (GetTunnelDirection(tile) != direction ||
GetTunnelTransportType(tile) != tpf->tracktype) {
// We are not driving into the tunnel, or it is an invalid tunnel
continue;
}
if (!HASBIT(tpf->railtypes, GetRailType(tile))) {
bits = 0;
break;
}
flotr = FindLengthOfTunnel(tile, direction);
si.cur_length += flotr.length * DIAG_FACTOR;
tile = flotr.tile;
// tile now points to the exit tile of the tunnel
}
} else {
TileIndex tile_end;
if (GetBridgeRampDirection(tile) != ReverseDiagDir(direction)) {
// We are not just leaving the bridge
if (GetBridgeRampDirection(tile) != direction ||
GetBridgeTransportType(tile) != tpf->tracktype) {
// Not entering the bridge or not compatible
continue;
}
}
tile_end = GetOtherBridgeEnd(tile);
si.cur_length += DistanceManhattan(tile, tile_end) * DIAG_FACTOR;
tile = tile_end;
} }
if (!HASBIT(tpf->railtypes, GetRailType(tile))) {
bits = 0;
break;
}
flotr = FindLengthOfTunnel(tile, direction);
si.cur_length += flotr.length * DIAG_FACTOR;
tile = flotr.tile;
// tile now points to the exit tile of the tunnel
} }
// This is a special loop used to go through // This is a special loop used to go through
@ -754,13 +773,9 @@ start_at:
// Check that the tile contains exactly one track // Check that the tile contains exactly one track
if (bits == 0 || KILL_FIRST_BIT(bits) != 0) break; if (bits == 0 || KILL_FIRST_BIT(bits) != 0) break;
/* Check the rail type only if the train is *NOT* on top of if (IsTileType(tile, MP_STREET) ? !HASBIT(tpf->railtypes, GetRailTypeCrossing(tile)) : !HASBIT(tpf->railtypes, GetRailType(tile))) {
* a bridge. */ bits = 0;
if (!(IsBridgeTile(tile) && IsBridgeMiddle(tile) && GetBridgeAxis(tile) == DiagDirToAxis(direction))) { break;
if (IsTileType(tile, MP_STREET) ? !HASBIT(tpf->railtypes, GetRailTypeCrossing(tile)) : !HASBIT(tpf->railtypes, GetRailType(tile))) {
bits = 0;
break;
}
} }
/////////////////// ///////////////////

18
rail.c
View File

@ -104,7 +104,6 @@ const Trackdir _dir_to_diag_trackdir[] = {
RailType GetTileRailType(TileIndex tile, Trackdir trackdir) RailType GetTileRailType(TileIndex tile, Trackdir trackdir)
{ {
DiagDirection exitdir = TrackdirToExitdir(trackdir);
switch (GetTileType(tile)) { switch (GetTileType(tile)) {
case MP_RAILWAY: case MP_RAILWAY:
return GetRailType(tile); return GetRailType(tile);
@ -124,21 +123,8 @@ RailType GetTileRailType(TileIndex tile, Trackdir trackdir)
return GetRailType(tile); return GetRailType(tile);
} }
} else { } else {
if (IsBridgeRamp(tile)) { if (GetBridgeTransportType(tile) == TRANSPORT_RAIL) {
if (GetBridgeTransportType(tile) == TRANSPORT_RAIL) { return GetRailType(tile);
return GetRailType(tile);
}
} else {
if (GetBridgeAxis(tile) == DiagDirToAxis(exitdir)) {
if (GetBridgeTransportType(tile) == TRANSPORT_RAIL) {
return GetRailTypeOnBridge(tile);
}
} else {
if (IsTransportUnderBridge(tile) &&
GetTransportTypeUnderBridge(tile) == TRANSPORT_RAIL) {
return GetRailType(tile);
}
}
} }
} }
break; break;

View File

@ -231,29 +231,6 @@ int32 CmdBuildSingleRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
switch (GetTileType(tile)) { switch (GetTileType(tile)) {
case MP_TUNNELBRIDGE:
if (!IsBridge(tile) ||
!IsBridgeMiddle(tile) ||
(GetBridgeAxis(tile) == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X) != trackbit) {
// Get detailed error message
return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
}
if (IsClearUnderBridge(tile)) {
ret = CheckRailSlope(tileh, trackbit, 0, tile);
if (CmdFailed(ret)) return ret;
cost += ret;
if (flags & DC_EXEC) SetRailUnderBridge(tile, _current_player, p1);
} else if (IsTransportUnderBridge(tile) &&
GetTransportTypeUnderBridge(tile) == TRANSPORT_RAIL) {
return_cmd_error(STR_1007_ALREADY_BUILT);
} else {
// Get detailed error message
return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
}
break;
case MP_RAILWAY: case MP_RAILWAY:
if (!CheckTrackCombination(tile, trackbit, flags) || if (!CheckTrackCombination(tile, trackbit, flags) ||
!EnsureNoVehicle(tile)) { !EnsureNoVehicle(tile)) {
@ -341,20 +318,6 @@ int32 CmdRemoveSingleRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
switch (GetTileType(tile)) { switch (GetTileType(tile)) {
case MP_TUNNELBRIDGE:
if (!IsBridge(tile) ||
!IsBridgeMiddle(tile) ||
!IsTransportUnderBridge(tile) ||
GetTransportTypeUnderBridge(tile) != TRANSPORT_RAIL ||
GetRailBitsUnderBridge(tile) != trackbit ||
(_current_player != OWNER_WATER && !CheckTileOwnership(tile)) ||
!EnsureNoVehicleOnGround(tile)) {
return CMD_ERROR;
}
if (flags & DC_EXEC) SetClearUnderBridge(tile);
break;
case MP_STREET: { case MP_STREET: {
if (!IsLevelCrossing(tile) || if (!IsLevelCrossing(tile) ||
GetCrossingRailBits(tile) != trackbit || GetCrossingRailBits(tile) != trackbit ||
@ -591,6 +554,8 @@ int32 CmdBuildTrainDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
if (CmdFailed(ret)) return CMD_ERROR; if (CmdFailed(ret)) return CMD_ERROR;
cost = ret; cost = ret;
if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
d = AllocateDepot(); d = AllocateDepot();
if (d == NULL) return CMD_ERROR; if (d == NULL) return CMD_ERROR;
@ -1416,6 +1381,7 @@ static void DrawTile_Track(TileInfo *ti)
); );
} }
} }
DrawBridgeMiddle(ti);
} }
void DrawTrainDepotSprite(int x, int y, int image, RailType railtype) void DrawTrainDepotSprite(int x, int y, int image, RailType railtype)
@ -1525,19 +1491,11 @@ typedef struct SignalVehicleCheckStruct {
static void *SignalVehicleCheckProc(Vehicle *v, void *data) static void *SignalVehicleCheckProc(Vehicle *v, void *data)
{ {
const SignalVehicleCheckStruct* dest = data; const SignalVehicleCheckStruct* dest = data;
TileIndex tile;
if (v->type != VEH_Train) return NULL; if (v->type != VEH_Train) return NULL;
/* Find the tile outside the tunnel, for signalling */
if (v->u.rail.track == 0x40) {
tile = GetVehicleOutOfTunnelTile(v);
} else {
tile = v->tile;
}
/* Wrong tile, or no train? Not a match */ /* Wrong tile, or no train? Not a match */
if (tile != dest->tile) return NULL; if (v->tile != dest->tile) return NULL;
/* Are we on the same piece of track? */ /* Are we on the same piece of track? */
if (dest->track & (v->u.rail.track + (v->u.rail.track << 8))) return v; if (dest->track & (v->u.rail.track + (v->u.rail.track << 8))) return v;
@ -1553,15 +1511,18 @@ static bool SignalVehicleCheck(TileIndex tile, uint track)
dest.tile = tile; dest.tile = tile;
dest.track = track; dest.track = track;
/** @todo "Hackish" fix for the tunnel problems. This is needed because a tunnel /* Locate vehicles in tunnels or on bridges */
* is some kind of invisible black hole, and there is some special magic going if (IsTunnelTile(tile) || IsBridgeTile(tile)) {
* on in there. This 'workaround' can be removed once the maprewrite is done. TileIndex end;
*/ DiagDirection direction;
if (IsTunnelTile(tile)) {
// It is a tunnel we're checking, we need to do some special stuff if (IsTunnelTile(tile)) {
// because VehicleFromPos will not find the vihicle otherwise end = GetOtherTunnelEnd(tile);
TileIndex end = GetOtherTunnelEnd(tile); direction = GetTunnelDirection(tile);
DiagDirection direction = GetTunnelDirection(tile); } else {
end = GetOtherBridgeEnd(tile);
direction = GetBridgeRampDirection(tile);
}
dest.track = 1 << (direction & 1); // get the trackbit the vehicle would have if it has not entered the tunnel yet (ie is still visible) dest.track = 1 << (direction & 1); // get the trackbit the vehicle would have if it has not entered the tunnel yet (ie is still visible)
@ -1571,9 +1532,9 @@ static bool SignalVehicleCheck(TileIndex tile, uint track)
// check for a vehicle with that trackdir on the end tile of the tunnel // check for a vehicle with that trackdir on the end tile of the tunnel
if (VehicleFromPos(end, &dest, SignalVehicleCheckProc) != NULL) return true; if (VehicleFromPos(end, &dest, SignalVehicleCheckProc) != NULL) return true;
// now check all tiles from start to end for a "hidden" vehicle // now check all tiles from start to end for a warping vehicle
// NOTE: the hashes for tiles may overlap, so this could maybe be optimised a bit by not checking every tile? // NOTE: the hashes for tiles may overlap, so this could maybe be optimised a bit by not checking every tile?
dest.track = 0x40; // trackbit for vehicles "hidden" inside a tunnel dest.track = 0x40;
for (; tile != end; tile += TileOffsByDir(direction)) { for (; tile != end; tile += TileOffsByDir(direction)) {
if (VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL) if (VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL)
return true; return true;

View File

@ -81,11 +81,6 @@ static inline RailType GetRailTypeCrossing(TileIndex t)
return (RailType)GB(_m[t].m4, 0, 4); return (RailType)GB(_m[t].m4, 0, 4);
} }
static inline RailType GetRailTypeOnBridge(TileIndex t)
{
return (RailType)GB(_m[t].m3, 4, 4);
}
static inline void SetRailType(TileIndex t, RailType r) static inline void SetRailType(TileIndex t, RailType r)
{ {
SB(_m[t].m3, 0, 4, r); SB(_m[t].m3, 0, 4, r);
@ -97,11 +92,6 @@ static inline void SetRailTypeCrossing(TileIndex t, RailType r)
SB(_m[t].m4, 0, 4, r); SB(_m[t].m4, 0, 4, r);
} }
static inline void SetRailTypeOnBridge(TileIndex t, RailType r)
{
SB(_m[t].m3, 4, 4, r);
}
/** These are used to specify a single track. /** These are used to specify a single track.
* Can be translated to a trackbit with TrackToTrackbit */ * Can be translated to a trackbit with TrackToTrackbit */

View File

@ -108,97 +108,70 @@ int32 CmdRemoveRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
if (p1 >> 4) return CMD_ERROR; if (p1 >> 4) return CMD_ERROR;
pieces = p1; pieces = p1;
if (!IsTileType(tile, MP_STREET) && !IsTileType(tile, MP_TUNNELBRIDGE)) return CMD_ERROR; if (!IsTileType(tile, MP_STREET)) return CMD_ERROR;
owner = IsLevelCrossingTile(tile) ? GetCrossingRoadOwner(tile) : GetTileOwner(tile); owner = IsLevelCrossingTile(tile) ? GetCrossingRoadOwner(tile) : GetTileOwner(tile);
if (owner == OWNER_TOWN && _game_mode != GM_EDITOR) { if (owner == OWNER_TOWN && _game_mode != GM_EDITOR) {
if (IsTileType(tile, MP_TUNNELBRIDGE)) { // index of town is not saved for bridge (no space) t = GetTownByTile(tile);
t = ClosestTownFromTile(tile, _patches.dist_local_authority);
} else {
t = GetTownByTile(tile);
}
} else { } else {
t = NULL; t = NULL;
} }
if (!CheckAllowRemoveRoad(tile, pieces, &edge_road)) return CMD_ERROR; if (!CheckAllowRemoveRoad(tile, pieces, &edge_road)) return CMD_ERROR;
switch (GetTileType(tile)) { if (!EnsureNoVehicle(tile)) return CMD_ERROR;
case MP_TUNNELBRIDGE:
if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
if (!IsBridge(tile) || // check if you're allowed to remove the street owned by a town
!IsBridgeMiddle(tile) || // removal allowance depends on difficulty setting
!IsTransportUnderBridge(tile) || if (!CheckforTownRating(flags, t, ROAD_REMOVE)) return CMD_ERROR;
GetTransportTypeUnderBridge(tile) != TRANSPORT_ROAD ||
(pieces & ComplementRoadBits(GetRoadBitsUnderBridge(tile))) != 0) { switch (GetRoadTileType(tile)) {
case ROAD_TILE_NORMAL: {
RoadBits present = GetRoadBits(tile);
RoadBits c = pieces;
if (GetTileSlope(tile, NULL) != SLOPE_FLAT &&
(present == ROAD_Y || present == ROAD_X)) {
c |= (c & 0xC) >> 2;
c |= (c & 0x3) << 2;
}
// limit the bits to delete to the existing bits.
c &= present;
if (c == 0) return CMD_ERROR;
if (flags & DC_EXEC) {
ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
present ^= c;
if (present == 0) {
DoClearSquare(tile);
} else {
SetRoadBits(tile, present);
MarkTileDirtyByTile(tile);
}
}
return CountRoadBits(c) * _price.remove_road;
}
case ROAD_TILE_CROSSING: {
if (pieces & ComplementRoadBits(GetCrossingRoadBits(tile))) {
return CMD_ERROR; return CMD_ERROR;
} }
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM); ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
SetClearUnderBridge(tile);
MakeRailNormal(tile, GetTileOwner(tile), GetCrossingRailBits(tile), GetRailTypeCrossing(tile));
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
} }
return _price.remove_road * 2; return _price.remove_road * 2;
}
case MP_STREET: case ROAD_TILE_DEPOT:
if (!EnsureNoVehicle(tile)) return CMD_ERROR; default:
return CMD_ERROR;
// check if you're allowed to remove the street owned by a town
// removal allowance depends on difficulty setting
if (!CheckforTownRating(flags, t, ROAD_REMOVE)) return CMD_ERROR;
switch (GetRoadTileType(tile)) {
case ROAD_TILE_NORMAL: {
RoadBits present = GetRoadBits(tile);
RoadBits c = pieces;
if (GetTileSlope(tile, NULL) != SLOPE_FLAT &&
(present == ROAD_Y || present == ROAD_X)) {
c |= (c & 0xC) >> 2;
c |= (c & 0x3) << 2;
}
// limit the bits to delete to the existing bits.
c &= present;
if (c == 0) return CMD_ERROR;
if (flags & DC_EXEC) {
ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
present ^= c;
if (present == 0) {
DoClearSquare(tile);
} else {
SetRoadBits(tile, present);
MarkTileDirtyByTile(tile);
}
}
return CountRoadBits(c) * _price.remove_road;
}
case ROAD_TILE_CROSSING: {
if (pieces & ComplementRoadBits(GetCrossingRoadBits(tile))) {
return CMD_ERROR;
}
if (flags & DC_EXEC) {
ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
MakeRailNormal(tile, GetTileOwner(tile), GetCrossingRailBits(tile), GetRailTypeCrossing(tile));
MarkTileDirtyByTile(tile);
}
return _price.remove_road * 2;
}
default:
case ROAD_TILE_DEPOT:
return CMD_ERROR;
}
default: return CMD_ERROR;
} }
} }
@ -348,37 +321,6 @@ int32 CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
return _price.build_road * 2; return _price.build_road * 2;
} }
case MP_TUNNELBRIDGE:
/* check for flat land */
if (IsSteepSlope(tileh)) {
return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
}
if (!IsBridge(tile) || !IsBridgeMiddle(tile)) goto do_clear;
/* only allow roads pertendicular to bridge */
if ((pieces & (GetBridgeAxis(tile) == AXIS_X ? ROAD_X : ROAD_Y)) != 0) {
goto do_clear;
}
/* check if clear land under bridge */
if (IsTransportUnderBridge(tile)) {
switch (GetTransportTypeUnderBridge(tile)) {
case TRANSPORT_ROAD: return_cmd_error(STR_1007_ALREADY_BUILT);
default: return_cmd_error(STR_1008_MUST_REMOVE_RAILROAD_TRACK);
}
} else {
if (IsWaterUnderBridge(tile)) {
return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER);
}
}
if (flags & DC_EXEC) {
SetRoadUnderBridge(tile, _current_player);
MarkTileDirtyByTile(tile);
}
return _price.build_road * 2;
default: default:
do_clear:; do_clear:;
ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
@ -575,6 +517,8 @@ int32 CmdBuildRoadDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
if (CmdFailed(cost)) return CMD_ERROR; if (CmdFailed(cost)) return CMD_ERROR;
if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
dep = AllocateDepot(); dep = AllocateDepot();
if (dep == NULL) return CMD_ERROR; if (dep == NULL) return CMD_ERROR;
@ -798,6 +742,7 @@ static void DrawTile_Road(TileInfo *ti)
break; break;
} }
} }
DrawBridgeMiddle(ti);
} }
void DrawRoadDepotSprite(int x, int y, int image) void DrawRoadDepotSprite(int x, int y, int image)

View File

@ -27,22 +27,12 @@ RoadBits GetAnyRoadBits(TileIndex tile)
return DiagDirToRoadBits(GetRoadStopDir(tile)); return DiagDirToRoadBits(GetRoadStopDir(tile));
case MP_TUNNELBRIDGE: case MP_TUNNELBRIDGE:
if (IsBridge(tile)) { if (IsTunnel(tile)) {
if (IsBridgeMiddle(tile)) {
if (!IsTransportUnderBridge(tile) ||
GetBridgeTransportType(tile) != TRANSPORT_ROAD) {
return 0;
}
return GetRoadBitsUnderBridge(tile);
} else {
// ending
if (GetBridgeTransportType(tile) != TRANSPORT_ROAD) return 0;
return DiagDirToRoadBits(ReverseDiagDir(GetBridgeRampDirection(tile)));
}
} else {
// tunnel
if (GetTunnelTransportType(tile) != TRANSPORT_ROAD) return 0; if (GetTunnelTransportType(tile) != TRANSPORT_ROAD) return 0;
return DiagDirToRoadBits(ReverseDiagDir(GetTunnelDirection(tile))); return DiagDirToRoadBits(ReverseDiagDir(GetTunnelDirection(tile)));
} else {
if (GetBridgeTransportType(tile) != TRANSPORT_ROAD) return 0;
return DiagDirToRoadBits(ReverseDiagDir(GetBridgeRampDirection(tile)));
} }
default: return 0; default: return 0;

View File

@ -20,7 +20,9 @@
#include "player.h" #include "player.h"
#include "sound.h" #include "sound.h"
#include "depot.h" #include "depot.h"
#include "bridge.h"
#include "tunnel_map.h" #include "tunnel_map.h"
#include "bridge_map.h"
#include "vehicle_gui.h" #include "vehicle_gui.h"
#include "newgrf_engine.h" #include "newgrf_engine.h"
#include "yapf/yapf.h" #include "yapf/yapf.h"
@ -313,8 +315,6 @@ static const Depot* FindClosestRoadDepot(const Vehicle* v)
{ {
TileIndex tile = v->tile; TileIndex tile = v->tile;
if (v->u.road.state == 255) tile = GetVehicleOutOfTunnelTile(v);
if (_patches.yapf.road_use_yapf) { if (_patches.yapf.road_use_yapf) {
Depot* ret = YapfFindNearestRoadDepot(v); Depot* ret = YapfFindNearestRoadDepot(v);
return ret; return ret;
@ -411,14 +411,19 @@ int32 CmdTurnRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
if (v->type != VEH_Road || !CheckOwnership(v->owner)) return CMD_ERROR; if (v->type != VEH_Road || !CheckOwnership(v->owner)) return CMD_ERROR;
if (v->vehstatus & (VS_HIDDEN | VS_STOPPED) || if (v->vehstatus & VS_STOPPED ||
v->u.road.crashed_ctr != 0 || v->u.road.crashed_ctr != 0 ||
v->breakdown_ctr != 0 || v->breakdown_ctr != 0 ||
v->u.road.overtaking != 0 || v->u.road.overtaking != 0 ||
v->u.road.state == 255 ||
v->u.road.state == 254 ||
v->cur_speed < 5) { v->cur_speed < 5) {
return CMD_ERROR; return CMD_ERROR;
} }
if (IsTunnelTile(v->tile) && DirToDiagDir(v->direction) == GetTunnelDirection(v->tile)) return CMD_ERROR;
if (IsBridgeTile(v->tile) && DirToDiagDir(v->direction) == GetBridgeRampDirection(v->tile)) return CMD_ERROR;
if (flags & DC_EXEC) v->u.road.reverse_ctr = 180; if (flags & DC_EXEC) v->u.road.reverse_ctr = 180;
return 0; return 0;
@ -485,11 +490,9 @@ static byte SetRoadVehPosition(Vehicle *v, int x, int y)
byte new_z, old_z; byte new_z, old_z;
// need this hint so it returns the right z coordinate on bridges. // need this hint so it returns the right z coordinate on bridges.
_get_z_hint = v->z_pos;
v->x_pos = x; v->x_pos = x;
v->y_pos = y; v->y_pos = y;
new_z = GetSlopeZ(x, y); new_z = GetSlopeZ(x, y);
_get_z_hint = 0;
old_z = v->z_pos; old_z = v->z_pos;
v->z_pos = new_z; v->z_pos = new_z;
@ -824,6 +827,7 @@ static bool RoadVehAccelerate(Vehicle *v)
// Clamp // Clamp
spd = min(spd, v->max_speed); spd = min(spd, v->max_speed);
if (v->u.road.state == 255) spd = min(spd, SetSpeedLimitOnBridge(v));
//updates statusbar only if speed have changed to save CPU time //updates statusbar only if speed have changed to save CPU time
if (spd != v->cur_speed) { if (spd != v->cur_speed) {
@ -1285,8 +1289,7 @@ static void RoadVehController(Vehicle *v)
return; return;
} }
if (IsTunnelTile(gp.new_tile) && if ((IsTunnelTile(gp.new_tile) || IsBridgeTile(gp.new_tile)) && VehicleEnterTile(v, gp.new_tile, gp.x, gp.y) & 4) {
VehicleEnterTile(v, gp.new_tile, gp.x, gp.y) & 4) {
//new_dir = RoadGetNewDirection(v, gp.x, gp.y) //new_dir = RoadGetNewDirection(v, gp.x, gp.y)
v->cur_image = GetRoadVehImage(v, v->direction); v->cur_image = GetRoadVehImage(v, v->direction);
UpdateRoadVehDeltaXY(v); UpdateRoadVehDeltaXY(v);
@ -1297,6 +1300,7 @@ static void RoadVehController(Vehicle *v)
v->x_pos = gp.x; v->x_pos = gp.x;
v->y_pos = gp.y; v->y_pos = gp.y;
VehiclePositionChanged(v); VehiclePositionChanged(v);
if (!(v->vehstatus & VS_HIDDEN)) EndVehicleMove(v);
return; return;
} }

View File

@ -30,7 +30,7 @@
#include "variables.h" #include "variables.h"
#include <setjmp.h> #include <setjmp.h>
const uint16 SAVEGAME_VERSION = 28; const uint16 SAVEGAME_VERSION = 29;
uint16 _sl_version; /// the major savegame version identifier uint16 _sl_version; /// the major savegame version identifier
byte _sl_minor_version; /// the minor savegame version, DO NOT USE! byte _sl_minor_version; /// the minor savegame version, DO NOT USE!

View File

@ -5,6 +5,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "openttd.h"
#include "bridge_map.h"
#include "debug.h" #include "debug.h"
#include "functions.h" #include "functions.h"
#include "station_map.h" #include "station_map.h"
@ -782,6 +783,10 @@ int32 CheckFlatLandBelow(TileIndex tile, uint w, uint h, uint flags, uint invali
int flat_z; int flat_z;
BEGIN_TILE_LOOP(tile_cur, w, h, tile) BEGIN_TILE_LOOP(tile_cur, w, h, tile)
if (MayHaveBridgeAbove(tile_cur) && IsBridgeAbove(tile_cur)) {
return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
}
if (!EnsureNoVehicle(tile_cur)) return CMD_ERROR; if (!EnsureNoVehicle(tile_cur)) return CMD_ERROR;
tileh = GetTileSlope(tile_cur, &z); tileh = GetTileSlope(tile_cur, &z);

View File

@ -708,6 +708,27 @@ enum Sprites {
SPR_BTTUB_X_RAIL_REAR_BEG = 2569, SPR_BTTUB_X_RAIL_REAR_BEG = 2569,
SPR_BTTUB_X_RAIL_REAR_MID = 2570, SPR_BTTUB_X_RAIL_REAR_MID = 2570,
SPR_BTTUB_X_RAIL_REAR_END = 2571, SPR_BTTUB_X_RAIL_REAR_END = 2571,
SPR_BTTUB_Y_RAIL_REAR_BEG = 2572,
SPR_BTTUB_Y_RAIL_REAR_MID = 2573,
SPR_BTTUB_Y_RAIL_REAR_END = 2574,
SPR_BTTUB_X_ROAD_REAR_BEG = 2575,
SPR_BTTUB_X_ROAD_REAR_MID = 2576,
SPR_BTTUB_X_ROAD_REAR_END = 2577,
SPR_BTTUB_Y_ROAD_REAR_BEG = 2578,
SPR_BTTUB_Y_ROAD_REAR_MID = 2579,
SPR_BTTUB_Y_ROAD_REAR_END = 2580,
SPR_BTTUB_X_MONO_REAR_BEG = 2581,
SPR_BTTUB_X_MONO_REAR_MID = 2582,
SPR_BTTUB_X_MONO_REAR_END = 2583,
SPR_BTTUB_Y_MONO_REAR_BEG = 2584,
SPR_BTTUB_Y_MONO_REAR_MID = 2585,
SPR_BTTUB_Y_MONO_REAR_END = 2586,
SPR_BTTUB_X_MGLV_REAR_BEG = 2587,
SPR_BTTUB_X_MGLV_REAR_MID = 2588,
SPR_BTTUB_X_MGLV_REAR_END = 2589,
SPR_BTTUB_Y_MGLV_REAR_BEG = 2590,
SPR_BTTUB_Y_MGLV_REAR_MID = 2591,
SPR_BTTUB_Y_MGLV_REAR_END = 2592,
/* ramps (for all bridges except wood and tubular?)*/ /* ramps (for all bridges except wood and tubular?)*/

View File

@ -2,6 +2,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "openttd.h"
#include "bridge_map.h"
#include "clear_map.h" #include "clear_map.h"
#include "table/sprites.h" #include "table/sprites.h"
#include "table/strings.h" #include "table/strings.h"
@ -81,11 +82,20 @@ static void GenerateRockyArea(TileIndex end, TileIndex start)
size_y = (ey - sy) + 1; size_y = (ey - sy) + 1;
BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) { BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) {
if (IsTileType(tile, MP_CLEAR) || IsTileType(tile, MP_TREES)) { switch (GetTileType(tile)) {
MakeClear(tile, CLEAR_ROCKS, 3); case MP_CLEAR:
MarkTileDirtyByTile(tile); MakeClear(tile, CLEAR_ROCKS, 3);
success = true; break;
case MP_TREES:
MakeClear(tile, CLEAR_ROCKS, 3);
ClearBridgeMiddle(tile);
break;
default: continue;
} }
MarkTileDirtyByTile(tile);
success = true;
} END_TILE_LOOP(tile, size_x, size_y, 0); } END_TILE_LOOP(tile, size_x, size_y, 0);
if (success) SndPlayTileFx(SND_1F_SPLAT, end); if (success) SndPlayTileFx(SND_1F_SPLAT, end);

View File

@ -26,6 +26,7 @@
#include "water_map.h" #include "water_map.h"
#include "variables.h" #include "variables.h"
#include "bridge.h" #include "bridge.h"
#include "bridge_map.h"
#include "table/town_land.h" #include "table/town_land.h"
enum { enum {
@ -1093,6 +1094,8 @@ static bool CheckBuildHouseMode(TileIndex tile, Slope tileh, int mode)
slope = GetTileSlope(tile, NULL); slope = GetTileSlope(tile, NULL);
if (IsSteepSlope(slope)) return false; if (IsSteepSlope(slope)) return false;
if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
b = 0; b = 0;
if ((slope != SLOPE_FLAT && ~slope & _masks[mode])) b = ~b; if ((slope != SLOPE_FLAT && ~slope & _masks[mode])) b = ~b;
if ((tileh != SLOPE_FLAT && ~tileh & _masks[mode+4])) b = ~b; if ((tileh != SLOPE_FLAT && ~tileh & _masks[mode+4])) b = ~b;
@ -1136,6 +1139,8 @@ static bool CheckFree2x2Area(TileIndex tile)
if (GetTileSlope(tile, NULL) != SLOPE_FLAT) return false; if (GetTileSlope(tile, NULL) != SLOPE_FLAT) return false;
if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
if (CmdFailed(DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER | DC_FORCETEST, CMD_LANDSCAPE_CLEAR))) if (CmdFailed(DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER | DC_FORCETEST, CMD_LANDSCAPE_CLEAR)))
return false; return false;
} }
@ -1270,6 +1275,7 @@ static bool BuildTownHouse(Town *t, TileIndex tile)
// make sure it's possible // make sure it's possible
if (!EnsureNoVehicle(tile)) return false; if (!EnsureNoVehicle(tile)) return false;
if (IsSteepSlope(GetTileSlope(tile, NULL))) return false; if (IsSteepSlope(GetTileSlope(tile, NULL))) return false;
if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
r = DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR); r = DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR);
if (CmdFailed(r)) return false; if (CmdFailed(r)) return false;

View File

@ -25,6 +25,7 @@
#include "waypoint.h" #include "waypoint.h"
#include "vehicle_gui.h" #include "vehicle_gui.h"
#include "train.h" #include "train.h"
#include "bridge.h"
#include "newgrf_callbacks.h" #include "newgrf_callbacks.h"
#include "newgrf_engine.h" #include "newgrf_engine.h"
#include "newgrf_text.h" #include "newgrf_text.h"
@ -91,10 +92,7 @@ void TrainPowerChanged(Vehicle* v)
/* Power is not added for articulated parts */ /* Power is not added for articulated parts */
if (IsArticulatedPart(u)) continue; if (IsArticulatedPart(u)) continue;
if (IsBridgeTile(u->tile) && IsBridgeMiddle(u->tile) && DiagDirToAxis(DirToDiagDir(u->direction)) == GetBridgeAxis(u->tile)) { if (IsLevelCrossingTile(u->tile)) {
if (!HasPowerOnRail(u->u.rail.railtype, GetRailTypeOnBridge(u->tile))) engine_has_power = false;
if (!HasPowerOnRail(v->u.rail.railtype, GetRailTypeOnBridge(u->tile))) wagon_has_power = false;
} else if (IsLevelCrossingTile(u->tile)) {
if (!HasPowerOnRail(u->u.rail.railtype, GetRailTypeCrossing(u->tile))) engine_has_power = false; if (!HasPowerOnRail(u->u.rail.railtype, GetRailTypeCrossing(u->tile))) engine_has_power = false;
if (!HasPowerOnRail(v->u.rail.railtype, GetRailTypeCrossing(u->tile))) wagon_has_power = false; if (!HasPowerOnRail(v->u.rail.railtype, GetRailTypeCrossing(u->tile))) wagon_has_power = false;
} else { } else {
@ -1529,13 +1527,14 @@ static void ReverseTrainSwapVeh(Vehicle *v, int l, int r)
UpdateVarsAfterSwap(a); UpdateVarsAfterSwap(a);
UpdateVarsAfterSwap(b); UpdateVarsAfterSwap(b);
VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos); /* call the proper EnterTile function unless we are in a wormhole */
VehicleEnterTile(b, b->tile, b->x_pos, b->y_pos); if (!(a->u.rail.track & 0x40)) VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos);
if (!(b->u.rail.track & 0x40)) VehicleEnterTile(b, b->tile, b->x_pos, b->y_pos);
} else { } else {
if (!(a->u.rail.track & 0x80)) a->direction = ReverseDir(a->direction); if (!(a->u.rail.track & 0x80)) a->direction = ReverseDir(a->direction);
UpdateVarsAfterSwap(a); UpdateVarsAfterSwap(a);
VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos); if (!(a->u.rail.track & 0x40)) VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos);
} }
/* Update train's power incase tiles were different rail type */ /* Update train's power incase tiles were different rail type */
@ -1848,8 +1847,6 @@ static TrainFindDepotData FindClosestTrainDepot(Vehicle *v, int max_distance)
return tfdd; return tfdd;
} }
if (v->u.rail.track == 0x40) tile = GetVehicleOutOfTunnelTile(v);
if (_patches.yapf.rail_use_yapf) { if (_patches.yapf.rail_use_yapf) {
bool found = YapfFindNearestRailDepotTwoWay(v, max_distance, NPF_INFINITE_PENALTY, &tfdd.tile, &tfdd.reverse); bool found = YapfFindNearestRailDepotTwoWay(v, max_distance, NPF_INFINITE_PENALTY, &tfdd.tile, &tfdd.reverse);
tfdd.best_length = found ? max_distance / 2 : -1; // some fake distance or NOT_FOUND tfdd.best_length = found ? max_distance / 2 : -1; // some fake distance or NOT_FOUND
@ -2567,9 +2564,7 @@ static byte AfterSetTrainPos(Vehicle *v, bool new_tile)
byte new_z, old_z; byte new_z, old_z;
// need this hint so it returns the right z coordinate on bridges. // need this hint so it returns the right z coordinate on bridges.
_get_z_hint = v->z_pos;
new_z = GetSlopeZ(v->x_pos, v->y_pos); new_z = GetSlopeZ(v->x_pos, v->y_pos);
_get_z_hint = 0;
old_z = v->z_pos; old_z = v->z_pos;
v->z_pos = new_z; v->z_pos = new_z;
@ -2645,13 +2640,6 @@ static bool CheckCompatibleRail(const Vehicle *v, TileIndex tile)
// normal tracks, jump to owner check // normal tracks, jump to owner check
break; break;
case MP_TUNNELBRIDGE:
if (IsBridge(tile) && IsBridgeMiddle(tile)) {
// is train going over the bridge?
if (v->z_pos > GetTileMaxZ(tile)) return true;
}
break;
case MP_STREET: case MP_STREET:
// tracks over roads, do owner check of tracks // tracks over roads, do owner check of tracks
return return
@ -2992,15 +2980,16 @@ static void TrainController(Vehicle *v)
v->direction = chosen_dir; v->direction = chosen_dir;
} }
} else { } else {
/* in tunnel */ /* in tunnel on on a bridge */
GetNewVehiclePos(v, &gp); GetNewVehiclePos(v, &gp);
// Check if to exit the tunnel... SetSpeedLimitOnBridge(v);
if (!IsTunnelTile(gp.new_tile) ||
!(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y)&0x4) ) { if (!(IsTunnelTile(gp.new_tile) || IsBridgeTile(gp.new_tile)) || !(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y) & 0x4)) {
v->x_pos = gp.x; v->x_pos = gp.x;
v->y_pos = gp.y; v->y_pos = gp.y;
VehiclePositionChanged(v); VehiclePositionChanged(v);
if (!(v->vehstatus & VS_HIDDEN)) EndVehicleMove(v);
continue; continue;
} }
} }
@ -3097,7 +3086,7 @@ static void DeleteLastWagon(Vehicle *v)
* others are on it */ * others are on it */
DisableTrainCrossing(v->tile); DisableTrainCrossing(v->tile);
if (v->u.rail.track == 0x40) { // inside a tunnel if ( (v->u.rail.track == 0x40 && v->vehstatus & VS_HIDDEN) ) { // inside a tunnel
TileIndex endtile = CheckTunnelBusy(v->tile, NULL); TileIndex endtile = CheckTunnelBusy(v->tile, NULL);
if (endtile == INVALID_TILE) return; // tunnel is busy (error returned) if (endtile == INVALID_TILE) return; // tunnel is busy (error returned)
@ -3128,15 +3117,16 @@ static void ChangeTrainDirRandomly(Vehicle *v)
}; };
do { do {
//I need to buffer the train direction /* We don't need to twist around vehicles if they're not visible */
if (!(v->u.rail.track & 0x40)) {
v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]);
}
if (!(v->vehstatus & VS_HIDDEN)) { if (!(v->vehstatus & VS_HIDDEN)) {
v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]);
BeginVehicleMove(v); BeginVehicleMove(v);
UpdateTrainDeltaXY(v, v->direction); UpdateTrainDeltaXY(v, v->direction);
v->cur_image = GetTrainImage(v, v->direction); v->cur_image = GetTrainImage(v, v->direction);
AfterSetTrainPos(v, false); /* Refrain from updating the z position of the vehicle when on
a bridge, because AfterSetTrainPos will put the vehicle under
the bridge in that case */
if (!(v->u.rail.track & 0x40)) AfterSetTrainPos(v, false);
} }
} while ((v = v->next) != NULL); } while ((v = v->next) != NULL);
} }
@ -3147,7 +3137,7 @@ static void HandleCrashedTrain(Vehicle *v)
uint32 r; uint32 r;
Vehicle *u; Vehicle *u;
if (state == 4 && v->u.rail.track != 0x40) { if (state == 4 && !(v->u.rail.track & VS_HIDDEN)) {
CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE); CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
} }
@ -3234,10 +3224,15 @@ static bool TrainCheckIfLineEnds(Vehicle *v)
tile = v->tile; tile = v->tile;
// tunnel entrance? if (IsTileType(tile, MP_TUNNELBRIDGE)) {
if (IsTunnelTile(tile) && DiagDirection dir;
DiagDirToDir(GetTunnelDirection(tile)) == v->direction) {
return true; if (IsTunnel(tile)) {
dir = GetTunnelDirection(tile);
} else {
dir = GetBridgeRampDirection(tile);
}
if (DiagDirToDir(dir) == v->direction) return true;
} }
// depot? // depot?

View File

@ -2,6 +2,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "openttd.h"
#include "bridge_map.h"
#include "clear_map.h" #include "clear_map.h"
#include "table/strings.h" #include "table/strings.h"
#include "table/sprites.h" #include "table/sprites.h"
@ -68,6 +69,7 @@ static void DoPlaceMoreTrees(TileIndex tile)
if (dist <= 13 && if (dist <= 13 &&
IsTileType(cur_tile, MP_CLEAR) && IsTileType(cur_tile, MP_CLEAR) &&
!IsBridgeAbove(cur_tile) &&
!IsClearGround(cur_tile, CLEAR_FIELDS) && !IsClearGround(cur_tile, CLEAR_FIELDS) &&
!IsClearGround(cur_tile, CLEAR_ROCKS)) { !IsClearGround(cur_tile, CLEAR_ROCKS)) {
PlaceTree(cur_tile, r); PlaceTree(cur_tile, r);
@ -92,6 +94,7 @@ void PlaceTreesRandomly(void)
uint32 r = Random(); uint32 r = Random();
TileIndex tile = RandomTileSeed(r); TileIndex tile = RandomTileSeed(r);
if (IsTileType(tile, MP_CLEAR) && if (IsTileType(tile, MP_CLEAR) &&
!IsBridgeAbove(tile) &&
!IsClearGround(tile, CLEAR_FIELDS) && !IsClearGround(tile, CLEAR_FIELDS) &&
!IsClearGround(tile, CLEAR_ROCKS)) { !IsClearGround(tile, CLEAR_ROCKS)) {
PlaceTree(tile, r); PlaceTree(tile, r);
@ -105,7 +108,9 @@ void PlaceTreesRandomly(void)
do { do {
uint32 r = Random(); uint32 r = Random();
TileIndex tile = RandomTileSeed(r); TileIndex tile = RandomTileSeed(r);
if (IsTileType(tile, MP_CLEAR) && GetTropicZone(tile) == TROPICZONE_RAINFOREST) { if (IsTileType(tile, MP_CLEAR) &&
!IsBridgeAbove(tile) &&
GetTropicZone(tile) == TROPICZONE_RAINFOREST) {
PlaceTree(tile, r); PlaceTree(tile, r);
} }
} while (--i); } while (--i);
@ -175,7 +180,8 @@ int32 CmdPlantTree(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
break; break;
case MP_CLEAR: case MP_CLEAR:
if (!IsTileOwner(tile, OWNER_NONE)) { if (!IsTileOwner(tile, OWNER_NONE) ||
IsBridgeAbove(tile)) {
msg = STR_2804_SITE_UNSUITABLE; msg = STR_2804_SITE_UNSUITABLE;
continue; continue;
} }
@ -480,7 +486,7 @@ static void TileLoop_Trees(TileIndex tile)
tile += ToTileIndexDiff(_tileloop_trees_dir[Random() & 7]); tile += ToTileIndexDiff(_tileloop_trees_dir[Random() & 7]);
if (!IsTileType(tile, MP_CLEAR)) return; if (!IsTileType(tile, MP_CLEAR) || IsBridgeAbove(tile)) return;
switch (GetClearGround(tile)) { switch (GetClearGround(tile)) {
case CLEAR_GRASS: case CLEAR_GRASS:
@ -513,6 +519,7 @@ static void TileLoop_Trees(TileIndex tile)
case TREE_GROUND_ROUGH: MakeClear(tile, CLEAR_ROUGH, 3); break; case TREE_GROUND_ROUGH: MakeClear(tile, CLEAR_ROUGH, 3); break;
default: MakeClear(tile, CLEAR_SNOW, GetTreeDensity(tile)); break; default: MakeClear(tile, CLEAR_SNOW, GetTreeDensity(tile)); break;
} }
ClearBridgeMiddle(tile);
} }
break; break;
@ -535,6 +542,7 @@ void OnTick_Trees(void)
if (_opt.landscape == LT_DESERT && if (_opt.landscape == LT_DESERT &&
(r = Random(), tile = RandomTileSeed(r), GetTropicZone(tile) == TROPICZONE_RAINFOREST) && (r = Random(), tile = RandomTileSeed(r), GetTropicZone(tile) == TROPICZONE_RAINFOREST) &&
IsTileType(tile, MP_CLEAR) && IsTileType(tile, MP_CLEAR) &&
!IsBridgeAbove(tile) &&
(ct = GetClearGround(tile), ct == CLEAR_GRASS || ct == CLEAR_ROUGH) && (ct = GetClearGround(tile), ct == CLEAR_GRASS || ct == CLEAR_ROUGH) &&
(tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) { (tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) {
MakeTree(tile, tree, 0, 0, ct == CLEAR_ROUGH ? TREE_GROUND_ROUGH : TREE_GROUND_GRASS, 0); MakeTree(tile, tree, 0, 0, ct == CLEAR_ROUGH ? TREE_GROUND_ROUGH : TREE_GROUND_GRASS, 0);
@ -547,6 +555,7 @@ void OnTick_Trees(void)
r = Random(); r = Random();
tile = TILE_MASK(r); tile = TILE_MASK(r);
if (IsTileType(tile, MP_CLEAR) && if (IsTileType(tile, MP_CLEAR) &&
!IsBridgeAbove(tile) &&
(ct = GetClearGround(tile), ct == CLEAR_GRASS || ct == CLEAR_ROUGH || ct == CLEAR_SNOW) && (ct = GetClearGround(tile), ct == CLEAR_GRASS || ct == CLEAR_ROUGH || ct == CLEAR_SNOW) &&
(tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) { (tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) {
switch (ct) { switch (ct) {

View File

@ -30,11 +30,6 @@
#include "table/bridge_land.h" #include "table/bridge_land.h"
extern const byte _track_sloped_sprites[14];
extern const SpriteID _water_shore_sprites[15];
extern void DrawCanalWater(TileIndex tile);
const Bridge orig_bridge[] = { const Bridge orig_bridge[] = {
/* /*
year of availablity year of availablity
@ -197,7 +192,6 @@ int32 CmdBuildBridge(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2)
TileIndex tile; TileIndex tile;
TileIndexDiff delta; TileIndexDiff delta;
uint bridge_len; uint bridge_len;
uint odd_middle_part;
Axis direction; Axis direction;
uint i; uint i;
int32 cost, terraformcost, ret; int32 cost, terraformcost, ret;
@ -289,6 +283,26 @@ int32 CmdBuildBridge(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2)
return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION); return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
cost += terraformcost; cost += terraformcost;
{
TileIndex Heads[] = {tile_start, tile_end};
int i;
for (i = 0; i < 2; i++) {
if (MayHaveBridgeAbove(Heads[i])) {
if (IsBridgeAbove(Heads[i])) {
TileIndex north_head = GetNorthernBridgeEnd(Heads[i]);
int z1, z2;
if (direction == GetBridgeAxis(Heads[i])) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
z1 = GetBridgeHeight(north_head, GetBridgeAxis(Heads[i]));
z2 = GetBridgeHeight(Heads[i], direction);
if (z1 == z2) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
}
}
}
}
/* do the drill? */ /* do the drill? */
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
@ -305,47 +319,42 @@ int32 CmdBuildBridge(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2)
MarkTileDirtyByTile(tile_end); MarkTileDirtyByTile(tile_end);
} }
// position of middle part of the odd bridge (larger than MAX(i) otherwise)
odd_middle_part = (bridge_len % 2) ? (bridge_len / 2) : bridge_len;
tile = tile_start; tile = tile_start;
delta = (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1)); delta = (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
for (i = 0; i != bridge_len; i++) { for (i = 0; i != bridge_len; i++) {
TransportType transport_under;
Owner owner_under = OWNER_NONE;
RailType rail_under = INVALID_RAILTYPE;
uint z; uint z;
tile += delta; tile += delta;
if (GetTileSlope(tile, &z) != SLOPE_FLAT && z >= z_start) { if (GetTileSlope(tile, &z) != SLOPE_FLAT && z >= z_start) return_cmd_error(STR_5009_LEVEL_LAND_OR_WATER_REQUIRED);
return_cmd_error(STR_5009_LEVEL_LAND_OR_WATER_REQUIRED);
if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) {
/* Disallow crossing bridges for the time being */
return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
} }
switch (GetTileType(tile)) { switch (GetTileType(tile)) {
case MP_WATER: case MP_WATER:
if (!EnsureNoVehicle(tile)) return_cmd_error(STR_980E_SHIP_IN_THE_WAY); if (!EnsureNoVehicle(tile)) return_cmd_error(STR_980E_SHIP_IN_THE_WAY);
if (!(IsWater(tile) || IsCoast(tile))) goto not_valid_below; if (!(IsWater(tile) || IsCoast(tile))) goto not_valid_below;
transport_under = TRANSPORT_WATER;
break; break;
case MP_RAILWAY: case MP_RAILWAY:
if (GetRailTileType(tile) != RAIL_TILE_NORMAL || if (!IsPlainRailTile(tile)) goto not_valid_below;
GetTrackBits(tile) != (direction == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X)) {
goto not_valid_below;
}
transport_under = TRANSPORT_RAIL;
owner_under = GetTileOwner(tile);
rail_under = GetRailType(tile);
break; break;
case MP_STREET: case MP_STREET:
if (GetRoadTileType(tile) != ROAD_TILE_NORMAL || if (GetRoadTileType(tile) != ROAD_TILE_NORMAL) goto not_valid_below;
GetRoadBits(tile) != (direction == AXIS_X ? ROAD_Y : ROAD_X)) { break;
goto not_valid_below;
} case MP_TUNNELBRIDGE:
transport_under = TRANSPORT_ROAD; if (IsTunnel(tile)) break;
owner_under = GetTileOwner(tile); if (direction == DiagDirToAxis(GetBridgeRampDirection(tile))) goto not_valid_below;
if (GetBridgeHeight(tile_start, direction) == GetBridgeHeight(tile, DiagDirToAxis(GetBridgeRampDirection(tile)))) goto not_valid_below;
break;
case MP_CLEAR:
if (IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
break; break;
default: default:
@ -354,50 +363,11 @@ not_valid_below:;
ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
if (CmdFailed(ret)) return ret; if (CmdFailed(ret)) return ret;
cost += ret; cost += ret;
transport_under = INVALID_TRANSPORT;
break; break;
} }
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
uint piece; SetBridgeMiddle(tile, direction);
//bridges pieces sequence (middle parts)
// bridge len 1: 0
// bridge len 2: 0 1
// bridge len 3: 0 4 1
// bridge len 4: 0 2 3 1
// bridge len 5: 0 2 5 3 1
// bridge len 6: 0 2 3 2 3 1
// bridge len 7: 0 2 3 4 2 3 1
// #0 - always as first, #1 - always as last (if len>1)
// #2,#3 are to pair in order
// for odd bridges: #5 is going in the bridge middle if on even position, #4 on odd (counting from 0)
if (i == 0) { // first tile
piece = 0;
} else if (i == bridge_len - 1) { // last tile
piece = 1;
} else if (i == odd_middle_part) { // we are on the middle of odd bridge: #5 on even pos, #4 on odd
piece = 5 - (i % 2);
} else {
// generate #2 and #3 in turns [i%2==0], after the middle of odd bridge
// this sequence swaps [... XOR (i>odd_middle_part)],
// for even bridges XOR does not apply as odd_middle_part==bridge_len
piece = 2 + ((i % 2 == 0) ^ (i > odd_middle_part));
}
if (transport == TRANSPORT_RAIL) {
MakeRailBridgeMiddle(tile, bridge_type, piece, direction, railtype);
} else {
MakeRoadBridgeMiddle(tile, bridge_type, piece, direction);
}
switch (transport_under) {
case TRANSPORT_RAIL: SetRailUnderBridge(tile, owner_under, rail_under); break;
case TRANSPORT_ROAD: SetRoadUnderBridge(tile, owner_under); break;
case TRANSPORT_WATER: SetWaterUnderBridge(tile); break;
default: SetClearUnderBridge(tile); break;
}
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
} }
} }
@ -582,7 +552,7 @@ static int32 DoClearTunnel(TileIndex tile, uint32 flags)
return _price.clear_tunnel * (length + 1); return _price.clear_tunnel * (length + 1);
} }
#if 0
static uint GetBridgeHeightRamp(TileIndex t) static uint GetBridgeHeightRamp(TileIndex t)
{ {
/* Return the height there (the height of the NORTH CORNER) /* Return the height there (the height of the NORTH CORNER)
@ -590,6 +560,7 @@ static uint GetBridgeHeightRamp(TileIndex t)
* the z coordinate is 1 height level too low. Compensate for that */ * the z coordinate is 1 height level too low. Compensate for that */
return TilePixelHeight(t) + (GetTileSlope(t, NULL) == SLOPE_WSE ? TILE_HEIGHT : 0); return TilePixelHeight(t) + (GetTileSlope(t, NULL) == SLOPE_WSE ? TILE_HEIGHT : 0);
} }
#endif
static int32 DoClearBridge(TileIndex tile, uint32 flags) static int32 DoClearBridge(TileIndex tile, uint32 flags)
@ -597,47 +568,10 @@ static int32 DoClearBridge(TileIndex tile, uint32 flags)
DiagDirection direction; DiagDirection direction;
TileIndexDiff delta; TileIndexDiff delta;
TileIndex endtile; TileIndex endtile;
Vehicle *v;
Town *t; Town *t;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
if (IsBridgeMiddle(tile)) {
if (IsTransportUnderBridge(tile)) {
/* delete transport route under the bridge */
int32 cost;
// check if we own the tile below the bridge..
if (_current_player != OWNER_WATER && (!CheckTileOwnership(tile) || !EnsureNoVehicleOnGround(tile)))
return CMD_ERROR;
if (GetTransportTypeUnderBridge(tile) == TRANSPORT_RAIL) {
cost = _price.remove_rail;
} else {
cost = _price.remove_road * 2;
}
if (flags & DC_EXEC) {
SetClearUnderBridge(tile);
MarkTileDirtyByTile(tile);
}
return cost;
} else if (IsWaterUnderBridge(tile) && TilePixelHeight(tile) != 0) {
/* delete canal under bridge */
// check for vehicles under bridge
if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
if (flags & DC_EXEC) {
SetClearUnderBridge(tile);
MarkTileDirtyByTile(tile);
}
return _price.clear_water;
}
tile = GetSouthernBridgeEnd(tile);
}
// floods, scenario editor can always destroy bridges // floods, scenario editor can always destroy bridges
if (_current_player != OWNER_WATER && _game_mode != GM_EDITOR && !CheckTileOwnership(tile)) { if (_current_player != OWNER_WATER && _game_mode != GM_EDITOR && !CheckTileOwnership(tile)) {
if (!(_patches.extra_dynamite || _cheats.magic_bulldozer.value) || !IsTileOwner(tile, OWNER_TOWN)) if (!(_patches.extra_dynamite || _cheats.magic_bulldozer.value) || !IsTileOwner(tile, OWNER_TOWN))
@ -651,18 +585,6 @@ static int32 DoClearBridge(TileIndex tile, uint32 flags)
direction = GetBridgeRampDirection(tile); direction = GetBridgeRampDirection(tile);
delta = TileOffsByDir(direction); delta = TileOffsByDir(direction);
/* Make sure there's no vehicle on the bridge
Omit tile and endtile, since these are already checked, thus solving the problem
of bridges over water, or higher bridges, where z is not increased, eg level bridge
*/
/* Bridges on slopes might have their Z-value offset..correct this */
v = FindVehicleBetween(
tile + delta,
endtile - delta,
GetBridgeHeightRamp(tile) + TILE_HEIGHT
);
if (v != NULL) return_cmd_error(VehicleInTheWayErrMsg(v));
t = ClosestTownFromTile(tile, (uint)-1); //needed for town rating penalty t = ClosestTownFromTile(tile, (uint)-1); //needed for town rating penalty
// check if you're allowed to remove the bridge owned by a town. // check if you're allowed to remove the bridge owned by a town.
// removal allowal depends on difficulty settings // removal allowal depends on difficulty settings
@ -681,26 +603,8 @@ static int32 DoClearBridge(TileIndex tile, uint32 flags)
DoClearSquare(tile); DoClearSquare(tile);
DoClearSquare(endtile); DoClearSquare(endtile);
for (c = tile + delta; c != endtile; c += delta) { for (c = tile + delta; c != endtile; c += delta) {
if (IsTransportUnderBridge(c)) { ClearBridgeMiddle(c);
if (GetTransportTypeUnderBridge(c) == TRANSPORT_RAIL) { MarkTileDirtyByTile(c);
MakeRailNormal(c, GetTileOwner(c), GetRailBitsUnderBridge(c), GetRailType(c));
} else {
uint town = IsTileOwner(c, OWNER_TOWN) ? ClosestTownFromTile(c, (uint)-1)->index : 0;
MakeRoadNormal(c, GetTileOwner(c), GetRoadBitsUnderBridge(c), town);
}
MarkTileDirtyByTile(c);
} else {
if (IsClearUnderBridge(c)) {
DoClearSquare(c);
} else {
if (GetTileSlope(c, NULL) == SLOPE_FLAT) {
MakeWater(c);
} else {
MakeShore(c);
}
MarkTileDirtyByTile(c);
}
}
} }
UpdateSignalsOnSegment(tile, ReverseDiagDir(direction)); UpdateSignalsOnSegment(tile, ReverseDiagDir(direction));
@ -753,29 +657,7 @@ int32 DoConvertTunnelBridgeRail(TileIndex tile, RailType totype, bool exec)
YapfNotifyTrackLayoutChange(endtile, endtrack); YapfNotifyTrackLayoutChange(endtile, endtrack);
} }
return (length + 1) * (_price.build_rail >> 1); return (length + 1) * (_price.build_rail >> 1);
} else if (IsBridge(tile) && } else if (IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_RAIL) {
IsBridgeMiddle(tile) &&
IsTransportUnderBridge(tile) &&
GetTransportTypeUnderBridge(tile) == TRANSPORT_RAIL) {
// only check for train under bridge
if (!CheckTileOwnership(tile) || !EnsureNoVehicleOnGround(tile))
return CMD_ERROR;
if (GetRailType(tile) == totype) return CMD_ERROR;
if (exec) {
TrackBits tracks;
SetRailType(tile, totype);
MarkTileDirtyByTile(tile);
// notify YAPF about the track layout change
for (tracks = GetRailBitsUnderBridge(tile); tracks != TRACK_BIT_NONE; tracks = KILL_FIRST_BIT(tracks))
YapfNotifyTrackLayoutChange(tile, FIND_FIRST_BIT(tracks));
}
return _price.build_rail >> 1;
} else if (IsBridge(tile) && IsBridgeRamp(tile) && GetBridgeTransportType(tile) == TRANSPORT_RAIL) {
TileIndexDiff delta;
int32 cost;
uint z = TilePixelHeight(tile); uint z = TilePixelHeight(tile);
z += TILE_HEIGHT; z += TILE_HEIGHT;
@ -796,53 +678,29 @@ int32 DoConvertTunnelBridgeRail(TileIndex tile, RailType totype, bool exec)
if (GetRailType(tile) == totype) return CMD_ERROR; if (GetRailType(tile) == totype) return CMD_ERROR;
if (exec) { if (exec) {
Track track, endtrack; TileIndexDiff delta;
SetRailType(tile, totype); SetRailType(tile, totype);
SetRailType(endtile, totype); SetRailType(endtile, totype);
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
MarkTileDirtyByTile(endtile); MarkTileDirtyByTile(endtile);
// notify YAPF about the track layout change delta = TileOffsByDir(GetBridgeRampDirection(tile));
track = TrackdirToTrack(DiagdirToDiagTrackdir(GetBridgeRampDirection(tile))); for (tile += delta; tile != endtile; tile += delta) {
endtrack = TrackdirToTrack(DiagdirToDiagTrackdir(GetBridgeRampDirection(endtile))); MarkTileDirtyByTile(tile); // TODO encapsulate this into a function
YapfNotifyTrackLayoutChange(tile, track);
YapfNotifyTrackLayoutChange(endtile, endtrack);
}
cost = 2 * (_price.build_rail >> 1);
delta = TileOffsByDir(GetBridgeRampDirection(tile));
for (tile += delta; tile != endtile; tile += delta) {
if (exec) {
SetRailTypeOnBridge(tile, totype);
MarkTileDirtyByTile(tile);
} }
cost += _price.build_rail >> 1;
} }
return cost; return (DistanceManhattan(tile, endtile) + 1) * (_price.build_rail >> 1);
} else } else
return CMD_ERROR; return CMD_ERROR;
} }
// fast routine for getting the height of a middle bridge tile. 'tile' MUST be a middle bridge tile. static void DrawBridgePillars(PalSpriteID image, const TileInfo* ti, Axis axis, uint type, int x, int y, int z)
uint GetBridgeHeight(TileIndex t)
{
return GetBridgeHeightRamp(GetSouthernBridgeEnd(t));
}
static const byte _bridge_foundations[2][16] = {
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
{0,16,18,3,20,5,0,7,22,0,10,11,12,13,14},
{0,15,17,0,19,5,6,7,21,9,10,11, 0,13,14},
};
extern const byte _road_sloped_sprites[14];
static void DrawBridgePillars(PalSpriteID image, const TileInfo *ti, int x, int y, int z)
{ {
if (image != 0) { if (image != 0) {
Axis axis = GetBridgeAxis(ti->tile); bool drawfarpillar = !HASBIT(GetBridgeFlags(type), 0);
bool drawfarpillar = !HASBIT(GetBridgeFlags(GetBridgeType(ti->tile)), 0);
int back_height, front_height; int back_height, front_height;
int i = z; int i = z;
const byte *p; const byte *p;
@ -905,17 +763,11 @@ uint GetBridgeFoundation(Slope tileh, Axis axis)
* <li>Bit 2: Set if the bridge head is sloped</li> * <li>Bit 2: Set if the bridge head is sloped</li>
* <li>Bit 3 and more: Railtype Specific subset</li> * <li>Bit 3 and more: Railtype Specific subset</li>
* </ul> * </ul>
* For middle parts:
* <ul><li>Bits 0-1: need to be 0</li>
* <li>Bit 2: direction</li>
* <li>Bit 3 and above: Railtype Specific subset</li>
* </ul>
* Please note that in this code, "roads" are treated as railtype 1, whilst the real railtypes are 0, 2 and 3 * Please note that in this code, "roads" are treated as railtype 1, whilst the real railtypes are 0, 2 and 3
*/ */
static void DrawTile_TunnelBridge(TileInfo *ti) static void DrawTile_TunnelBridge(TileInfo *ti)
{ {
uint32 image; uint32 image;
const PalSpriteID *b;
bool ice = _m[ti->tile].m4 & 0x80; bool ice = _m[ti->tile].m4 & 0x80;
if (IsTunnel(ti->tile)) { if (IsTunnel(ti->tile)) {
@ -932,19 +784,12 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti); if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
AddSortableSpriteToDraw(image+1, ti->x + TILE_SIZE - 1, ti->y + TILE_SIZE - 1, 1, 1, 8, (byte)ti->z); AddSortableSpriteToDraw(image+1, ti->x + TILE_SIZE - 1, ti->y + TILE_SIZE - 1, 1, 1, 8, (byte)ti->z);
DrawBridgeMiddle(ti);
} else if (IsBridge(ti->tile)) { // XXX is this necessary? } else if (IsBridge(ti->tile)) { // XXX is this necessary?
int base_offset; int base_offset;
if (GetBridgeTransportType(ti->tile) == TRANSPORT_RAIL) { if (GetBridgeTransportType(ti->tile) == TRANSPORT_RAIL) {
RailType rt; base_offset = GetRailTypeInfo(GetRailType(ti->tile))->bridge_offset;
if (IsBridgeRamp(ti->tile)) {
rt = GetRailType(ti->tile);
} else {
rt = GetRailTypeOnBridge(ti->tile);
}
base_offset = GetRailTypeInfo(rt)->bridge_offset;
assert(base_offset != 8); /* This one is used for roads */ assert(base_offset != 8); /* This one is used for roads */
} else { } else {
base_offset = 8; base_offset = 8;
@ -953,124 +798,152 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
/* as the lower 3 bits are used for other stuff, make sure they are clear */ /* as the lower 3 bits are used for other stuff, make sure they are clear */
assert( (base_offset & 0x07) == 0x00); assert( (base_offset & 0x07) == 0x00);
if (IsBridgeRamp(ti->tile)) { if (!HASBIT(BRIDGE_NO_FOUNDATION, ti->tileh)) {
if (!HASBIT(BRIDGE_NO_FOUNDATION, ti->tileh)) { int f = GetBridgeFoundation(ti->tileh, DiagDirToAxis(GetBridgeRampDirection(ti->tile)));
int f = GetBridgeFoundation(ti->tileh, DiagDirToAxis(GetBridgeRampDirection(ti->tile))); if (f) DrawFoundation(ti, f);
if (f) DrawFoundation(ti, f);
}
// HACK Wizardry to convert the bridge ramp direction into a sprite offset
base_offset += (6 - GetBridgeRampDirection(ti->tile)) % 4;
if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
/* Table number 6 always refers to the bridge heads for any bridge type */
image = GetBridgeSpriteTable(GetBridgeType(ti->tile), 6)[base_offset];
if (!ice) {
DrawClearLandTile(ti, 3);
} else {
DrawGroundSprite(SPR_FLAT_SNOWY_TILE + _tileh_to_sprite[ti->tileh]);
}
if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
// draw ramp
if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
AddSortableSpriteToDraw(image, ti->x, ti->y, 16, 16, 7, ti->z);
} else {
// bridge middle part.
Axis axis = GetBridgeAxis(ti->tile);
uint z;
int x,y;
if (IsTransportUnderBridge(ti->tile)) {
uint f = _bridge_foundations[axis][ti->tileh];
if (f != 0) DrawFoundation(ti, f);
if (GetTransportTypeUnderBridge(ti->tile) == TRANSPORT_RAIL) {
const RailtypeInfo* rti = GetRailTypeInfo(GetRailType(ti->tile));
if (ti->tileh == SLOPE_FLAT) {
image = (axis == AXIS_X ? SPR_RAIL_TRACK_Y : SPR_RAIL_TRACK_X);
} else {
image = SPR_RAIL_TRACK_Y + _track_sloped_sprites[ti->tileh - 1];
}
image += rti->total_offset;
if (ice) image += rti->snow_offset;
} else {
if (ti->tileh == SLOPE_FLAT) {
image = (axis == AXIS_X ? SPR_ROAD_Y : SPR_ROAD_X);
} else {
image = _road_sloped_sprites[ti->tileh - 1] + 0x53F;
}
if (ice) image += 19;
}
DrawGroundSprite(image);
} else {
if (IsClearUnderBridge(ti->tile)) {
image = (ice ? SPR_FLAT_SNOWY_TILE : SPR_FLAT_GRASS_TILE);
DrawGroundSprite(image + _tileh_to_sprite[ti->tileh]);
} else {
if (ti->tileh == SLOPE_FLAT) {
DrawGroundSprite(SPR_FLAT_WATER_TILE);
if (ti->z != 0) DrawCanalWater(ti->tile);
} else {
DrawGroundSprite(_water_shore_sprites[ti->tileh]);
}
}
}
if (axis != AXIS_X) base_offset += 4;
/* base_offset needs to be 0 due to the structure of the sprite table see table/bridge_land.h */
assert( (base_offset & 0x03) == 0x00);
// get bridge sprites
b = GetBridgeSpriteTable(GetBridgeType(ti->tile), GetBridgePiece(ti->tile)) + base_offset;
z = GetBridgeHeight(ti->tile) + 5;
// draw rail or road component
image = b[0];
if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
if (axis == AXIS_X) {
AddSortableSpriteToDraw(image, ti->x, ti->y, 16, 11, 1, z);
} else {
AddSortableSpriteToDraw(image, ti->x, ti->y, 11, 16, 1, z);
}
x = ti->x;
y = ti->y;
image = b[1];
if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
// draw roof, the component of the bridge which is logically between the vehicle and the camera
if (axis == AXIS_X) {
y += 12;
if (image & SPRITE_MASK) AddSortableSpriteToDraw(image, x, y, 16, 1, 0x28, z);
} else {
x += 12;
if (image & SPRITE_MASK) AddSortableSpriteToDraw(image, x, y, 1, 16, 0x28, z);
}
if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC || GetRailTypeOnBridge(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
if (ti->z + 5 == z) {
// draw poles below for small bridges
image = b[2];
if (image != 0) {
if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
DrawGroundSpriteAt(image, x, y, z);
}
} else if (_patches.bridge_pillars) {
// draw pillars below for high bridges
DrawBridgePillars(b[2], ti, x, y, z);
}
} }
// HACK Wizardry to convert the bridge ramp direction into a sprite offset
base_offset += (6 - GetBridgeRampDirection(ti->tile)) % 4;
if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
/* Table number 6 always refers to the bridge heads for any bridge type */
image = GetBridgeSpriteTable(GetBridgeType(ti->tile), 6)[base_offset];
if (!ice) {
DrawClearLandTile(ti, 3);
} else {
DrawGroundSprite(SPR_FLAT_SNOWY_TILE + _tileh_to_sprite[ti->tileh]);
}
if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
// draw ramp
if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
AddSortableSpriteToDraw(image, ti->x, ti->y, 16, 16, 7, ti->z);
DrawBridgeMiddle(ti);
} }
} }
//bridges pieces sequence (middle parts)
// bridge len 1: 0
// bridge len 2: 0 1
// bridge len 3: 0 4 1
// bridge len 4: 0 2 3 1
// bridge len 5: 0 2 5 3 1
// bridge len 6: 0 2 3 2 3 1
// bridge len 7: 0 2 3 4 2 3 1
// #0 - always as first, #1 - always as last (if len>1)
// #2,#3 are to pair in order
// for odd bridges: #5 is going in the bridge middle if on even position, #4 on odd (counting from 0)
static uint CalcBridgePiece(uint north, uint south)
{
if (north == 1) {
return 0;
} else if (south == 1) {
return 1;
} else if (north < south) {
return north & 1 ? 3 : 2;
} else if (north > south) {
return south & 1 ? 2 : 3;
} else {
return north & 1 ? 5 : 4;
}
}
void DrawBridgeMiddle(const TileInfo* ti)
{
const PalSpriteID* b;
PalSpriteID image;
uint base_offset;
TileIndex rampnorth;
TileIndex rampsouth;
Axis axis;
uint piece;
uint type;
int x;
int y;
uint z;
if (!IsBridgeAbove(ti->tile)) return;
rampnorth = GetNorthernBridgeEnd(ti->tile);
rampsouth = GetSouthernBridgeEnd(ti->tile);
axis = GetBridgeAxis(ti->tile);
piece = CalcBridgePiece(
DistanceManhattan(ti->tile, rampnorth),
DistanceManhattan(ti->tile, rampsouth)
);
type = GetBridgeType(rampsouth);
if (GetBridgeTransportType(rampsouth) == TRANSPORT_RAIL) {
base_offset = GetRailTypeInfo(GetRailType(rampsouth))->bridge_offset;
} else {
base_offset = 8;
}
b = base_offset + GetBridgeSpriteTable(type, piece);
if (axis != AXIS_X) b += 4;
x = ti->x;
y = ti->y;
z = GetBridgeHeight(rampsouth, axis) - 3;
image = b[0];
if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
if (axis == AXIS_X) {
AddSortableSpriteToDraw(image, x, y, 16, 11, 1, z);
} else {
AddSortableSpriteToDraw(image, x, y, 11, 16, 1, z);
}
image = b[1];
if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
// draw roof, the component of the bridge which is logically between the vehicle and the camera
if (axis == AXIS_X) {
y += 12;
if (image & SPRITE_MASK) AddSortableSpriteToDraw(image, x, y, 16, 1, 0x28, z);
} else {
x += 12;
if (image & SPRITE_MASK) AddSortableSpriteToDraw(image, x, y, 1, 16, 0x28, z);
}
if (GetRailType(rampsouth) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
if (ti->z + 5 == z) {
// draw poles below for small bridges
image = b[2];
if (image != 0) {
if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
DrawGroundSpriteAt(image, x, y, z);
}
} else if (_patches.bridge_pillars) {
// draw pillars below for high bridges
DrawBridgePillars(b[2], ti, axis, type, x, y, z);
}
}
uint SetSpeedLimitOnBridge(Vehicle *v)
{
uint bridge_speed;
if (v->vehstatus & VS_HIDDEN) return v->max_speed; /* in tunnel */
bridge_speed = _bridge[GetBridgeType(v->tile)].speed;
if (v->type == VEH_Road) bridge_speed *= 2; /* XXX give vehicles proper speeds */
if (v->cur_speed > bridge_speed) v->cur_speed = bridge_speed;
return bridge_speed;
}
static uint GetSlopeZ_TunnelBridge(const TileInfo* ti) static uint GetSlopeZ_TunnelBridge(const TileInfo* ti)
{ {
TileIndex tile = ti->tile; TileIndex tile = ti->tile;
@ -1085,44 +958,30 @@ static uint GetSlopeZ_TunnelBridge(const TileInfo* ti)
// In the tunnel entrance? // In the tunnel entrance?
if (5 <= pos && pos <= 10) return z; if (5 <= pos && pos <= 10) return z;
} else { } else {
if (IsBridgeRamp(tile)) { DiagDirection dir = GetBridgeRampDirection(tile);
DiagDirection dir = GetBridgeRampDirection(tile); uint pos = (DiagDirToAxis(dir) == AXIS_X ? y : x);
uint pos = (DiagDirToAxis(dir) == AXIS_X ? y : x);
// On the bridge ramp? // On the bridge ramp?
if (5 <= pos && pos <= 10) { if (5 <= pos && pos <= 10) {
uint delta; uint delta;
if (HASBIT(BRIDGE_HORZ_RAMP, tileh)) return z + TILE_HEIGHT; if (HASBIT(BRIDGE_HORZ_RAMP, tileh)) return z + TILE_HEIGHT;
if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh)) z += TILE_HEIGHT; if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh)) z += TILE_HEIGHT;
switch (dir) { switch (dir) {
default: default:
case DIAGDIR_NE: delta = (TILE_SIZE - 1 - x) / 2; break; case DIAGDIR_NE: delta = (TILE_SIZE - 1 - x) / 2; break;
case DIAGDIR_SE: delta = y / 2; break; case DIAGDIR_SE: delta = y / 2; break;
case DIAGDIR_SW: delta = x / 2; break; case DIAGDIR_SW: delta = x / 2; break;
case DIAGDIR_NW: delta = (TILE_SIZE - 1 - y) / 2; break; case DIAGDIR_NW: delta = (TILE_SIZE - 1 - y) / 2; break;
}
return z + 1 + delta;
} else {
uint f = GetBridgeFoundation(tileh, DiagDirToAxis(dir));
if (f != 0) {
if (f < 15) return z + TILE_HEIGHT;
tileh = _inclined_tileh[f - 15];
}
} }
return z + 1 + delta;
} else { } else {
// HACK on the bridge? uint f = GetBridgeFoundation(tileh, DiagDirToAxis(dir));
if (_get_z_hint >= z + TILE_HEIGHT + (tileh == SLOPE_FLAT ? 0 : TILE_HEIGHT)) return _get_z_hint;
if (IsTransportUnderBridge(tile)) { if (f != 0) {
uint f = _bridge_foundations[GetBridgeAxis(tile)][tileh]; if (f < 15) return z + TILE_HEIGHT;
tileh = _inclined_tileh[f - 15];
if (f != 0) {
if (f < 15) return z + TILE_HEIGHT;
tileh = _inclined_tileh[f - 15];
}
} }
} }
} }
@ -1181,9 +1040,6 @@ static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td)
STR_5017_RAILROAD_TUNNEL : STR_5018_ROAD_TUNNEL; STR_5017_RAILROAD_TUNNEL : STR_5018_ROAD_TUNNEL;
} else { } else {
td->str = _bridge_tile_str[GetBridgeTransportType(tile) << 4 | GetBridgeType(tile)]; td->str = _bridge_tile_str[GetBridgeTransportType(tile) << 4 | GetBridgeType(tile)];
// the owner is stored at the end of the bridge
if (IsBridgeMiddle(tile)) tile = GetSouthernBridgeEnd(tile);
} }
td->owner = GetTileOwner(tile); td->owner = GetTileOwner(tile);
} }
@ -1218,10 +1074,6 @@ static void TileLoop_TunnelBridge(TileIndex tile)
} }
break; break;
} }
if (IsBridge(tile) && IsBridgeMiddle(tile) && IsWaterUnderBridge(tile)) {
TileLoop_Water(tile);
}
} }
static void ClickTile_TunnelBridge(TileIndex tile) static void ClickTile_TunnelBridge(TileIndex tile)
@ -1232,37 +1084,13 @@ static void ClickTile_TunnelBridge(TileIndex tile)
static uint32 GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType mode) static uint32 GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType mode)
{ {
uint32 result;
if (IsTunnel(tile)) { if (IsTunnel(tile)) {
if (GetTunnelTransportType(tile) == mode) { if (GetTunnelTransportType(tile) == mode) {
return DiagDirToAxis(GetTunnelDirection(tile)) == AXIS_X ? 0x101 : 0x202; return DiagDirToAxis(GetTunnelDirection(tile)) == AXIS_X ? 0x101 : 0x202;
} }
} else if (IsBridge(tile)) { // XXX is this necessary? } else if (IsBridge(tile)) { // XXX is this necessary?
if (IsBridgeRamp(tile)) { if (GetBridgeTransportType(tile) != mode) return 0;
if (GetBridgeTransportType(tile) != mode) return 0; return (DiagDirToAxis(GetBridgeRampDirection(tile)) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y) * 0x101;
return (DiagDirToAxis(GetBridgeRampDirection(tile)) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y) * 0x101;
} else {
result = 0;
if (GetBridgeTransportType(tile) == mode) {
result = (GetBridgeAxis(tile) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y) * 0x101;
}
if (IsTransportUnderBridge(tile)) {
if (GetTransportTypeUnderBridge(tile) != mode) return result;
} else {
if (IsClearUnderBridge(tile)) {
return result;
} else {
if (mode != TRANSPORT_WATER) return result;
}
}
/* If we've not returned yet, there is a compatible
* transport or water beneath, so we can add it to
* result */
/* Why is this xor'd ? Can't it just be or'd? */
result ^= (GetBridgeAxis(tile) == AXIS_X ? 0x202 : 0x101);
}
return result;
} else { } else {
assert(0); /* This should never occur */ assert(0); /* This should never occur */
} }
@ -1276,16 +1104,7 @@ static void ChangeTileOwner_TunnelBridge(TileIndex tile, PlayerID old_player, Pl
if (new_player != OWNER_SPECTATOR) { if (new_player != OWNER_SPECTATOR) {
SetTileOwner(tile, new_player); SetTileOwner(tile, new_player);
} else { } else {
if (IsBridge(tile) && IsBridgeMiddle(tile) && IsTransportUnderBridge(tile)) { DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
// the stuff BELOW the middle part is owned by the deleted player.
if (GetTransportTypeUnderBridge(tile) == TRANSPORT_RAIL) {
SetClearUnderBridge(tile);
} else {
SetTileOwner(tile, OWNER_NONE);
}
} else {
DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
}
} }
} }
@ -1305,14 +1124,15 @@ static const byte _tunnel_fractcoord_7[4] = {0x52, 0x85, 0x96, 0x49};
static uint32 VehicleEnter_TunnelBridge(Vehicle *v, TileIndex tile, int x, int y) static uint32 VehicleEnter_TunnelBridge(Vehicle *v, TileIndex tile, int x, int y)
{ {
int z = GetSlopeZ(x, y) - v->z_pos;
if (myabs(z) > 2) return 8;
if (IsTunnel(tile)) { if (IsTunnel(tile)) {
int z = GetSlopeZ(x, y) - v->z_pos;
byte fc; byte fc;
DiagDirection dir; DiagDirection dir;
DiagDirection vdir; DiagDirection vdir;
if (myabs(z) > 2) return 8;
if (v->type == VEH_Train) { if (v->type == VEH_Train) {
fc = (x & 0xF) + (y << 4); fc = (x & 0xF) + (y << 4);
@ -1373,30 +1193,53 @@ static uint32 VehicleEnter_TunnelBridge(Vehicle *v, TileIndex tile, int x, int y
} }
} }
} else if (IsBridge(tile)) { // XXX is this necessary? } else if (IsBridge(tile)) { // XXX is this necessary?
DiagDirection dir;
if (v->type == VEH_Road || (v->type == VEH_Train && IsFrontEngine(v))) { if (v->type == VEH_Road || (v->type == VEH_Train && IsFrontEngine(v))) {
if (IsBridgeRamp(tile) || v->z_pos > GetTileMaxZ(tile)) { /* modify speed of vehicle */
/* modify speed of vehicle */ uint16 spd = _bridge[GetBridgeType(tile)].speed;
uint16 spd = _bridge[GetBridgeType(tile)].speed;
if (v->type == VEH_Road) spd *= 2; if (v->type == VEH_Road) spd *= 2;
if (v->cur_speed > spd) v->cur_speed = spd; if (v->cur_speed > spd) v->cur_speed = spd;
}
dir = GetBridgeRampDirection(tile);
if (DirToDiagDir(v->direction) == dir) {
switch (dir) {
default:
case DIAGDIR_NE: if ((x & 0xF) != 0) return 0; break;
case DIAGDIR_SE: if ((y & 0xF) != TILE_SIZE - 1) return 0; break;
case DIAGDIR_SW: if ((x & 0xF) != TILE_SIZE - 1) return 0; break;
case DIAGDIR_NW: if ((y & 0xF) != 0) return 0; break;
} }
if (v->type == VEH_Train) {
v->u.rail.track = 0x40;
CLRBIT(v->u.rail.flags, VRF_GOINGUP);
CLRBIT(v->u.rail.flags, VRF_GOINGDOWN);
} else {
v->u.road.state = 0xFF;
}
return 4;
} else if (DirToDiagDir(v->direction) == ReverseDiagDir(dir)) {
v->tile = tile;
if (v->type == VEH_Train) {
if (v->u.rail.track == 0x40) {
v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? 1 : 2);
return 4;
}
} else {
if (v->u.road.state == 0xFF) {
v->u.road.state = _road_exit_tunnel_state[dir];
v->u.road.frame = 0;
return 4;
}
}
return 0;
} }
} }
return 0; return 0;
} }
TileIndex GetVehicleOutOfTunnelTile(const Vehicle *v)
{
TileIndex tile;
TileIndexDiff delta = (v->direction & 2) ? TileDiffXY(0, 1) : TileDiffXY(1, 0);
byte z = v->z_pos;
for (tile = v->tile;; tile += delta) {
if (IsTunnelTile(tile) && GetTileZ(tile) == z) break;
}
return tile;
}
const TileTypeProcs _tile_type_tunnelbridge_procs = { const TileTypeProcs _tile_type_tunnelbridge_procs = {
DrawTile_TunnelBridge, /* draw_tile_proc */ DrawTile_TunnelBridge, /* draw_tile_proc */
GetSlopeZ_TunnelBridge, /* get_slope_z_proc */ GetSlopeZ_TunnelBridge, /* get_slope_z_proc */

View File

@ -309,7 +309,6 @@ VARDEF bool _exit_game;
VARDEF SmallFiosItem _file_to_saveload; VARDEF SmallFiosItem _file_to_saveload;
VARDEF byte _make_screenshot; VARDEF byte _make_screenshot;
VARDEF byte _get_z_hint; // used as a hint to getslopez to return the right height at a bridge.
VARDEF char *_newgrf_files[32]; VARDEF char *_newgrf_files[32];

View File

@ -286,7 +286,6 @@ uint32 VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y);
StringID VehicleInTheWayErrMsg(const Vehicle* v); StringID VehicleInTheWayErrMsg(const Vehicle* v);
Vehicle *FindVehicleBetween(TileIndex from, TileIndex to, byte z); Vehicle *FindVehicleBetween(TileIndex from, TileIndex to, byte z);
TileIndex GetVehicleOutOfTunnelTile(const Vehicle *v);
bool UpdateSignalsOnSegment(TileIndex tile, DiagDirection direction); bool UpdateSignalsOnSegment(TileIndex tile, DiagDirection direction);
void SetSignalsOnBothDir(TileIndex tile, byte track); void SetSignalsOnBothDir(TileIndex tile, byte track);

View File

@ -20,7 +20,7 @@
#include "train.h" #include "train.h"
#include "water_map.h" #include "water_map.h"
const SpriteID _water_shore_sprites[15] = { static const SpriteID _water_shore_sprites[] = {
0, 0,
SPR_SHORE_TILEH_1, SPR_SHORE_TILEH_1,
SPR_SHORE_TILEH_2, SPR_SHORE_TILEH_2,
@ -65,6 +65,8 @@ int32 CmdBuildShipDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
if (!IsClearWaterTile(tile) || !IsClearWaterTile(tile2)) if (!IsClearWaterTile(tile) || !IsClearWaterTile(tile2))
return_cmd_error(STR_3801_MUST_BE_BUILT_ON_WATER); return_cmd_error(STR_3801_MUST_BE_BUILT_ON_WATER);
if (IsBridgeAbove(tile) || IsBridgeAbove(tile2)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
if (CmdFailed(ret)) return CMD_ERROR; if (CmdFailed(ret)) return CMD_ERROR;
ret = DoCommand(tile2, 0, 0, flags, CMD_LANDSCAPE_CLEAR); ret = DoCommand(tile2, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
@ -139,6 +141,8 @@ static int32 DoBuildShiplift(TileIndex tile, DiagDirection dir, uint32 flags)
return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION); return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
} }
if (IsBridgeAbove(tile) || IsBridgeAbove(tile - delta) || IsBridgeAbove(tile + delta)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
MakeLock(tile, dir); MakeLock(tile, dir);
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
@ -227,6 +231,8 @@ int32 CmdBuildCanal(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
cost = 0; cost = 0;
BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) { BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) {
int32 ret;
if (GetTileSlope(tile, NULL) != SLOPE_FLAT) { if (GetTileSlope(tile, NULL) != SLOPE_FLAT) {
return_cmd_error(STR_0007_FLAT_LAND_REQUIRED); return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
} }
@ -234,26 +240,12 @@ int32 CmdBuildCanal(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
// can't make water of water! // can't make water of water!
if (IsTileType(tile, MP_WATER)) continue; if (IsTileType(tile, MP_WATER)) continue;
/* is middle piece of a bridge? */ ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
if (IsBridgeTile(tile) && IsBridgeMiddle(tile)) { if (CmdFailed(ret)) return ret;
if (IsTransportUnderBridge(tile)) { cost += ret;
return_cmd_error(STR_5800_OBJECT_IN_THE_WAY);
}
if (IsWaterUnderBridge(tile)) return_cmd_error(STR_1007_ALREADY_BUILT);
if (flags & DC_EXEC) SetWaterUnderBridge(tile);
} else {
/* no bridge, try to clear it. */
int32 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
if (CmdFailed(ret)) return ret;
cost += ret;
if (flags & DC_EXEC) MakeWater(tile);
}
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
MakeWater(tile);
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
MarkTilesAroundDirty(tile); MarkTilesAroundDirty(tile);
} }
@ -336,17 +328,9 @@ static int32 ClearTile_Water(TileIndex tile, byte flags)
static bool IsWateredTile(TileIndex tile) static bool IsWateredTile(TileIndex tile)
{ {
switch (GetTileType(tile)) { switch (GetTileType(tile)) {
case MP_WATER: case MP_WATER: return !IsCoast(tile);
return !IsCoast(tile); case MP_STATION: return IsOilRig(tile) || IsDock(tile) || IsBuoy_(tile);
default: return false;
case MP_STATION:
return IsOilRig(tile) || IsDock(tile) || IsBuoy_(tile);
case MP_TUNNELBRIDGE:
return IsBridge(tile) && IsBridgeMiddle(tile) && IsWaterUnderBridge(tile);
default:
return false;
} }
} }
@ -422,11 +406,13 @@ static void DrawTile_Water(TileInfo *ti)
case WATER_CLEAR: case WATER_CLEAR:
DrawGroundSprite(SPR_FLAT_WATER_TILE); DrawGroundSprite(SPR_FLAT_WATER_TILE);
if (ti->z != 0) DrawCanalWater(ti->tile); if (ti->z != 0) DrawCanalWater(ti->tile);
DrawBridgeMiddle(ti);
break; break;
case WATER_COAST: case WATER_COAST:
assert(!IsSteepSlope(ti->tileh)); assert(!IsSteepSlope(ti->tileh));
DrawGroundSprite(_water_shore_sprites[ti->tileh]); DrawGroundSprite(_water_shore_sprites[ti->tileh]);
DrawBridgeMiddle(ti);
break; break;
case WATER_LOCK: { case WATER_LOCK: {
@ -536,27 +522,10 @@ static void TileLoopWaterHelper(TileIndex tile, const TileIndexDiffC *offs)
} }
break; break;
case MP_TUNNELBRIDGE:
if (IsBridge(target) && IsBridgeMiddle(target) && IsClearUnderBridge(target)) {
SetWaterUnderBridge(target);
MarkTileDirtyByTile(target);
}
break;
default: default:
break; break;
} }
} else { } else {
if (IsBridgeTile(target) && IsBridgeMiddle(target)) {
if (IsWaterUnderBridge(target) ||
(IsTransportUnderBridge(target) && GetTransportTypeUnderBridge(target) == TRANSPORT_WATER)) { // XXX does this happen at all?
return;
}
SetWaterUnderBridge(target);
MarkTileDirtyByTile(target);
return;
}
_current_player = OWNER_WATER; _current_player = OWNER_WATER;
{ {
Vehicle *v = FindVehicleOnTileZ(target, 0); Vehicle *v = FindVehicleOnTileZ(target, 0);

View File

@ -9,6 +9,7 @@
#include "map.h" #include "map.h"
#include "order.h" #include "order.h"
#include "rail_map.h" #include "rail_map.h"
#include "bridge_map.h"
#include "saveload.h" #include "saveload.h"
#include "station.h" #include "station.h"
#include "tile.h" #include "tile.h"
@ -201,6 +202,8 @@ int32 CmdBuildTrainWaypoint(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
return_cmd_error(STR_0007_FLAT_LAND_REQUIRED); return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
} }
if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
/* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */ /* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */
wp = FindDeletedWaypointCloseTo(tile); wp = FindDeletedWaypointCloseTo(tile);
if (wp == NULL) { if (wp == NULL) {

View File

@ -27,7 +27,7 @@ struct CFollowTrackT : public FollowTrack_t
m_new_tile = INVALID_TILE; m_new_tile = INVALID_TILE;
m_new_td_bits = TRACKDIR_BIT_NONE; m_new_td_bits = TRACKDIR_BIT_NONE;
m_exitdir = INVALID_DIAGDIR; m_exitdir = INVALID_DIAGDIR;
m_is_station = m_is_tunnel = false; m_is_station = m_is_bridge = m_is_tunnel = false;
m_tiles_skipped = 0; m_tiles_skipped = 0;
} }
@ -60,6 +60,9 @@ protected:
/** Follow the m_exitdir from m_old_tile and fill m_new_tile and m_tiles_skipped */ /** Follow the m_exitdir from m_old_tile and fill m_new_tile and m_tiles_skipped */
FORCEINLINE void FollowTileExit() FORCEINLINE void FollowTileExit()
{ {
m_is_station = m_is_bridge = m_is_tunnel = false;
m_tiles_skipped = 0;
// extra handling for tunnels in our direction // extra handling for tunnels in our direction
if (IsTunnelTile(m_old_tile)) { if (IsTunnelTile(m_old_tile)) {
DiagDirection tunnel_enterdir = GetTunnelDirection(m_old_tile); DiagDirection tunnel_enterdir = GetTunnelDirection(m_old_tile);
@ -73,11 +76,22 @@ protected:
} }
assert(ReverseDiagDir(tunnel_enterdir) == m_exitdir); assert(ReverseDiagDir(tunnel_enterdir) == m_exitdir);
} }
// not a tunnel or station
m_is_tunnel = false;
m_tiles_skipped = 0;
// normal or station tile // extra handling for bridge ramp in our direction
if (IsBridgeTile(m_old_tile)) {
DiagDirection bridge_enterdir = GetBridgeRampDirection(m_old_tile);
if (bridge_enterdir == m_exitdir) {
// we are entering the bridge ramp
m_new_tile = GetOtherBridgeEnd(m_old_tile);
uint32 bridge_length = GetBridgeLength(m_old_tile, m_new_tile);
m_tiles_skipped = bridge_length;
m_is_bridge = true;
return;
}
assert(ReverseDiagDir(bridge_enterdir) == m_exitdir);
}
// normal or station tile, do one step
TileIndexDiff diff = TileOffsByDir(m_exitdir); TileIndexDiff diff = TileOffsByDir(m_exitdir);
m_new_tile = TILE_ADD(m_old_tile, diff); m_new_tile = TILE_ADD(m_old_tile, diff);
@ -148,22 +162,7 @@ protected:
// rail transport is possible only on tiles with the same owner as vehicle // rail transport is possible only on tiles with the same owner as vehicle
if (IsRailTT() && GetTileOwner(m_new_tile) != m_veh->owner) { if (IsRailTT() && GetTileOwner(m_new_tile) != m_veh->owner) {
// different owner // different owner
if (IsBridgeTile(m_new_tile)) { return false;
if (IsBridgeMiddle(m_new_tile)) {
// bridge middle has no owner - tile is owned by the owner of the under-bridge track
if (GetBridgeAxis(m_new_tile) != DiagDirToAxis(m_exitdir)) {
// so it must be under bridge track (and wrong owner)
return false;
}
// in the middle of the bridge - when we came here, it should be ok
} else {
// different owner, on the bridge ramp
return false;
}
} else {
// different owner, not a bridge
return false;
}
} }
// rail transport is possible only on compatible rail types // rail transport is possible only on compatible rail types
@ -224,20 +223,10 @@ public:
int max_speed = INT_MAX; // no limit int max_speed = INT_MAX; // no limit
// for now we handle only on-bridge speed limit // for now we handle only on-bridge speed limit
if (IsBridgeTile(m_old_tile) && !IsWaterTT() && IsDiagonalTrackdir(m_old_td)) { if (!IsWaterTT() && IsBridgeTile(m_old_tile)) {
bool is_on_bridge = true; int spd = _bridge[GetBridgeType(m_old_tile)].speed;
if (IsBridgeMiddle(m_old_tile)) { if (IsRoadTT()) spd *= 2;
// get track axis if (max_speed > spd) max_speed = spd;
Axis track_axis = DiagDirToAxis(TrackdirToExitdir(m_old_td));
// get under-bridge axis
Axis bridge_axis = GetBridgeAxis(m_old_tile);
if (track_axis != bridge_axis) is_on_bridge = false;
}
if (is_on_bridge) {
int spd = _bridge[GetBridgeType(m_old_tile)].speed;
if (IsRoadTT()) spd *= 2;
if (max_speed > spd) max_speed = spd;
}
} }
// if min speed was requested, return it // if min speed was requested, return it

View File

@ -34,9 +34,9 @@ typedef struct FollowTrack_t
Trackdir m_old_td; Trackdir m_old_td;
TileIndex m_new_tile; TileIndex m_new_tile;
TrackdirBits m_new_td_bits; TrackdirBits m_new_td_bits;
// TrackdirBits m_red_td_bits;
DiagDirection m_exitdir; DiagDirection m_exitdir;
bool m_is_tunnel; bool m_is_tunnel;
bool m_is_bridge;
bool m_is_station; bool m_is_station;
int m_tiles_skipped; int m_tiles_skipped;
} FollowTrack_t; } FollowTrack_t;

View File

@ -423,7 +423,9 @@ uint YapfRoadVehDistanceToTile(const Vehicle* v, TileIndex tile)
Depot* YapfFindNearestRoadDepot(const Vehicle *v) Depot* YapfFindNearestRoadDepot(const Vehicle *v)
{ {
TileIndex tile = v->tile; TileIndex tile = v->tile;
#if 0 /* NOT NEEDED, function does/did nothing */
if (v->u.road.state == 255) tile = GetVehicleOutOfTunnelTile(v); if (v->u.road.state == 255) tile = GetVehicleOutOfTunnelTile(v);
#endif
Trackdir trackdir = GetVehicleTrackdir(v); Trackdir trackdir = GetVehicleTrackdir(v);
if ((GetTileTrackStatus(tile, TRANSPORT_ROAD) & TrackdirToTrackdirBits(trackdir)) == 0) if ((GetTileTrackStatus(tile, TRANSPORT_ROAD) & TrackdirToTrackdirBits(trackdir)) == 0)
return NULL; return NULL;