(svn r7573) -Merged the bridge branch. Allows to build bridges of arbitrary rail/road combinations (including signals)

This commit is contained in:
celestar 2006-12-27 12:38:02 +00:00
parent d92103d6ff
commit d95e2c2dd1
39 changed files with 845 additions and 1179 deletions

8
BUGS
View File

@ -2,6 +2,14 @@
KNOWN BUGS / PROBLEMS: KNOWN BUGS / PROBLEMS:
bridges:
- Clearing tiles which may not have a bridge above can cause random bridge pieces to appear, which leads to crash in the long run
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)
TODO:
- Reallow the AI to build signals under bridges (about ai/default/default.c:1600) as
r4911 manually disallows it (not via the command)

View File

@ -2183,9 +2183,7 @@ static bool AiRemoveTileAndGoForward(Player *p)
return false; return false;
p->ai.cur_tile_a = TILE_MASK(_build_tunnel_endtile - TileOffsByDiagDir(p->ai.cur_dir_a)); p->ai.cur_tile_a = TILE_MASK(_build_tunnel_endtile - TileOffsByDiagDir(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;
@ -3704,7 +3702,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,28 @@
#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 = TileOffsByDiagDir(dir); TileIndexDiff delta = TileOffsByDiagDir(dir);
assert(DiagDirToAxis(dir) == GetBridgeAxis(tile)); dir = ReverseDiagDir(dir);
do { do {
tile += delta; tile += delta;
} while (!IsBridgeRamp(tile)); } while (!IsBridgeTile(tile) || GetBridgeRampDirection(tile) != dir);
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 +33,19 @@ TileIndex GetSouthernBridgeEnd(TileIndex t)
TileIndex GetOtherBridgeEnd(TileIndex tile) TileIndex GetOtherBridgeEnd(TileIndex tile)
{ {
TileIndexDiff delta = TileOffsByDiagDir(GetBridgeRampDirection(tile)); assert(IsBridgeTile(tile));
return GetBridgeEnd(tile, GetBridgeRampDirection(tile));
do { }
tile += delta;
} while (!IsBridgeRamp(tile)); uint GetBridgeHeight(TileIndex t)
{
return tile; uint h;
uint tileh = GetTileSlope(t, &h);
uint f = GetBridgeFoundation(tileh, DiagDirToAxis(GetBridgeRampDirection(t)));
// one height level extra if the ramp is on a flat foundation
return
h + TILE_HEIGHT +
(IS_INT_INSIDE(f, 1, 15) ? TILE_HEIGHT : 0) +
(IsSteepSlope(tileh) ? TILE_HEIGHT : 0);
} }

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,22 @@ 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)); IsTileType(t, MP_UNMOVABLE);
return HASBIT(_m[t].m5, 6);
} }
/** static inline bool IsBridgeAbove(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, 2) != 0;
} }
@ -65,65 +62,22 @@ static inline uint GetBridgeType(TileIndex t)
*/ */
static inline DiagDirection GetBridgeRampDirection(TileIndex t) static inline DiagDirection GetBridgeRampDirection(TileIndex t)
{ {
assert(IsBridgeRamp(t)); assert(IsBridgeTile(t));
return ReverseDiagDir(XYNSToDiagDir((Axis)GB(_m[t].m5, 0, 1), GB(_m[t].m5, 5, 1))); return (DiagDirection)GB(_m[t].m5, 0, 2);
} }
static inline Axis GetBridgeAxis(TileIndex t) static inline Axis GetBridgeAxis(TileIndex t)
{ {
assert(IsBridgeMiddle(t)); assert(IsBridgeAbove(t));
return (Axis)GB(_m[t].m5, 0, 1); return (Axis)(GB(_m[t].extra, 6, 2) - 1);
} }
static inline TransportType GetBridgeTransportType(TileIndex t) static inline TransportType GetBridgeTransportType(TileIndex t)
{ {
assert(IsBridgeTile(t)); assert(IsBridgeTile(t));
return (TransportType)GB(_m[t].m5, 1, 2); return (TransportType)GB(_m[t].m5, 2, 2);
}
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 Track GetRailUnderBridge(TileIndex t)
{
assert(GetTransportTypeUnderBridge(t) == TRANSPORT_RAIL);
return AxisToTrack(OtherAxis(GetBridgeAxis(t)));
}
static inline TrackBits GetRailBitsUnderBridge(TileIndex t)
{
return TrackToTrackBits(GetRailUnderBridge(t));
} }
@ -132,6 +86,11 @@ static inline TrackBits GetRailBitsUnderBridge(TileIndex t)
*/ */
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
*/ */
@ -143,58 +102,36 @@ TileIndex GetSouthernBridgeEnd(TileIndex t);
*/ */
TileIndex GetOtherBridgeEnd(TileIndex); TileIndex GetOtherBridgeEnd(TileIndex);
uint GetBridgeHeight(TileIndex t); uint GetBridgeHeight(TileIndex tile);
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 SetCanalUnderBridge(TileIndex t, Owner o) 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, 0 << 2 | 1);
SB(_m[t].m3, 0, 4, 0);
}
static inline void SetRailUnderBridge(TileIndex t, Owner o, RailType r)
{
assert(IsBridgeMiddle(t));
SetTileOwner(t, o);
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);
} }
static inline void MakeBridgeRamp(TileIndex t, Owner o, uint bridgetype, DiagDirection d, TransportType tt) static inline void MakeBridgeRamp(TileIndex t, Owner o, uint bridgetype, DiagDirection d, TransportType tt)
{ {
uint northsouth = (d == DIAGDIR_NE || d == DIAGDIR_NW);
SetTileType(t, MP_TUNNELBRIDGE); SetTileType(t, MP_TUNNELBRIDGE);
SetTileOwner(t, o); SetTileOwner(t, o);
_m[t].m2 = bridgetype << 4; _m[t].m2 = bridgetype << 4;
_m[t].m4 = 0; _m[t].m4 = 0;
_m[t].m5 = 1 << 7 | 0 << 6 | northsouth << 5 | tt << 1 | DiagDirToAxis(d); _m[t].m5 = 1 << 7 | tt << 2 | d;
} }
static inline void MakeRoadBridgeRamp(TileIndex t, Owner o, uint bridgetype, DiagDirection d) static inline void MakeRoadBridgeRamp(TileIndex t, Owner o, uint bridgetype, DiagDirection d)
@ -210,26 +147,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 /* BRIDGE_MAP_H */ #endif /* BRIDGE_MAP_H */

View File

@ -12,6 +12,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"
@ -276,25 +277,32 @@ int32 CmdTerraformLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
} }
} }
if (direction == -1) { {
/* Check if tunnel would take damage */ /* Check if tunnel would take damage */
int count; int count;
TileIndex *ti = ts.tile_table; TileIndex *ti = ts.tile_table;
for (count = ts.tile_table_count; count != 0; count--, ti++) { for (count = ts.tile_table_count; count != 0; count--, ti++) {
uint z, t;
TileIndex tile = *ti; TileIndex tile = *ti;
z = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0)); if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) {
t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0)); return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
if (t <= z) z = t; }
t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1));
if (t <= z) z = t;
t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1));
if (t <= z) z = t;
if (IsTunnelInWay(tile, z * TILE_HEIGHT)) { if (direction == -1) {
return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE); uint z, t;
z = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0));
t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0));
if (t <= z) z = t;
t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1));
if (t <= z) z = t;
t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1));
if (t <= z) z = t;
if (IsTunnelInWay(tile, z * TILE_HEIGHT)) {
return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
}
} }
} }
} }
@ -534,6 +542,7 @@ static void DrawTile_Clear(TileInfo *ti)
} }
DrawClearLandFence(ti); DrawClearLandFence(ti);
DrawBridgeMiddle(ti);
} }
static uint GetSlopeZ_Clear(TileIndex tile, uint x, uint y) static uint GetSlopeZ_Clear(TileIndex tile, uint x, uint y)

View File

@ -20,11 +20,7 @@
#ifdef NO_DEBUG_MESSAGES #ifdef NO_DEBUG_MESSAGES
#define DEBUG(name, level, ...) #define DEBUG(name, level, ...)
#else #else
#if defined(__GNUC__) && (__GNUC__ < 3) #define DEBUG(name, level, ...) if (level == 0 || _debug_ ## name ## _level >= level) debug(#name, __VA_ARGS__)
#define DEBUG(name, level, args...) if ((level == 0) || ( _debug_ ## name ## _level >= level)) debug(#name, args)
#else
#define DEBUG(name, level, ...) if (level == 0 || _debug_ ## name ## _level >= level) debug(#name, __VA_ARGS__)
#endif
extern int _debug_ai_level; extern int _debug_ai_level;
extern int _debug_driver_level; extern int _debug_driver_level;

View File

@ -554,31 +554,12 @@ m5 bits 7..4 clear: tunnel entrance/exit
<li>m3 bits 3..0 = <a href="#TrackType">track type</a> for railway tunnel, must be 0 for road tunnel</li> <li>m3 bits 3..0 = <a href="#TrackType">track type</a> for railway tunnel, must be 0 for road tunnel</li>
<li>m4 bit 7 set = on snow or desert</li> <li>m4 bit 7 set = on snow or desert</li>
</ul> </ul>
m5 bit 7 set: bridge m5 bit 7 set: bridge ramp
<ul><li>
m5 bit 6 clear: bridge ending
<ul> <ul>
<li>m5 bit 5: clear - northern, set - southern ending</li>
<li>m3 bits 3..0 = <a href="#TrackType">type of track</a> on the bridge, must be 0 for road bridge</li>
<li>m1: <a href="#OwnershipInfo">owner</a> of the bridge</li> <li>m1: <a href="#OwnershipInfo">owner</a> of the bridge</li>
</ul> <li>m3 bits 3..0 = <a href="#TrackType">type of track</a> on the bridge, must be 0 for road bridge</li>
m5 bit 6 set: bridge middle part <li>m5 bits 3..2: <tt>0</tt> - railway bridge, <tt>1</tt> - road bridge</li>
<ul> <li>m5 bit 0..1: DiagDirection onto the bridge</li>
<li>m5 bit 5 clear:
<ul>
<li>m5 bits 4..3: land under bridge: <tt>0</tt> - grass, snow or desert, <tt>1</tt> - water</li>
</ul>
m5 bit 5 set:
<ul>
<li>m5 bits 4..3: transport route under bridge: <tt>0</tt> - railway, <tt>1</tt> - road</li>
</ul>
<li>m3 bits 7..4 = <a href="#TrackType">type of track</a> on the bridge, must be 0 for road bridge</li>
<li>m3 bits 3..0 = <a href="#TrackType">type of track</a> under the bridge, if any</li>
<li>m2 bits 3..0: bridge piece (<tt>0</tt>..<tt>5</tt>)
<li>m1: <a href="#OwnershipInfo">owner</a> of the land under bridge</li>
</ul></li>
<li>m5 bits 2..1: <tt>0</tt> - railway bridge, <tt>1</tt> - road bridge</li>
<li>m5 bit 0: clear - bridge in the X direction, set - bridge in the Y direction</li>
<li>m2 bits 7..4: <a name="BridgeType">bridge type</a>: <li>m2 bits 7..4: <a name="BridgeType">bridge type</a>:
<table> <table>
<tr><th align=left>Type&nbsp;</th><th align=left>Max. speed (mph)&nbsp;</th><th align=left>Description</th></tr> <tr><th align=left>Type&nbsp;</th><th align=left>Max. speed (mph)&nbsp;</th><th align=left>Description</th></tr>

View File

@ -225,7 +225,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits">-inherit-</td> <td class="bits">-inherit-</td>
</tr> </tr>
<tr> <tr>
<td rowspan=3>9</td> <td rowspan=2>9</td>
<td class="caption">tunnel</td> <td class="caption">tunnel</td>
<td class="bits">XXXX XXXX</td> <td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td> <td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
@ -241,16 +241,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits"><span class="free">OOOO</span> XXXX</td> <td class="bits"><span class="free">OOOO</span> XXXX</td>
<td class="bits">X<span class="free">OOO OOOO</span></td> <td class="bits">X<span class="free">OOO OOOO</span></td>
<td class="bits">XXXX XXXX</td> <td class="bits">XXXX XXXX</td>
<td class="bits">XXX<span class="free">O O</span>XXX</td> <td class="bits">X<span class="free">OOO</span> XXXX</td>
</tr>
<tr>
<td>bridge middle part</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO</span> <span class="abuse">XXXX XXXX</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">X<span class="free">OOO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
</tr> </tr>
<tr> <tr>
<td>A</td> <td>A</td>

View File

@ -95,18 +95,10 @@ static TrackBits GetRailTrackBitsUniversal(TileIndex t, byte *override)
return AxisToTrackBits(DiagDirToAxis(GetTunnelDirection(t))); return AxisToTrackBits(DiagDirToAxis(GetTunnelDirection(t)));
} 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 AxisToTrackBits(DiagDirToAxis(GetBridgeRampDirection(t)));
} }
return AxisToTrackBits(DiagDirToAxis(GetBridgeRampDirection(t)));
} }
case MP_STREET: case MP_STREET:
@ -135,17 +127,15 @@ static void AdjustTileh(TileIndex tile, Slope *tileh)
if (IsTunnel(tile)) { if (IsTunnel(tile)) {
*tileh = SLOPE_FLAT; *tileh = SLOPE_FLAT;
} else { } else {
if (IsBridgeRamp(tile)) { if (*tileh != SLOPE_FLAT) {
if (*tileh != SLOPE_FLAT) { *tileh = SLOPE_FLAT;
*tileh = SLOPE_FLAT; } else {
} else { switch (GetBridgeRampDirection(tile)) {
switch (GetBridgeRampDirection(tile)) { case DIAGDIR_NE: *tileh = SLOPE_NE; break;
case DIAGDIR_NE: *tileh = SLOPE_NE; break; case DIAGDIR_SE: *tileh = SLOPE_SE; break;
case DIAGDIR_SE: *tileh = SLOPE_SE; break; case DIAGDIR_SW: *tileh = SLOPE_SW; break;
case DIAGDIR_SW: *tileh = SLOPE_SW; break; case DIAGDIR_NW: *tileh = SLOPE_NW; break;
case DIAGDIR_NW: *tileh = SLOPE_NW; break; default: NOT_REACHED();
default: break;
}
} }
} }
} }
@ -205,7 +195,7 @@ 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;
} }
@ -232,7 +222,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) && GetRailType(neighbour) == RAILTYPE_ELECTRIC) foundation = GetRailFoundation(tileh[TS_NEIGHBOUR], trackconfig[TS_NEIGHBOUR]); if (IsTileType(neighbour, MP_RAILWAY) && GetRailType(neighbour) == RAILTYPE_ELECTRIC) 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)));
} }
@ -260,6 +250,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));
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];
@ -284,11 +282,10 @@ static void DrawCatenaryRailway(const TileInfo *ti)
} }
/* Don't draw a wire under a low bridge */ /* Don't draw a wire under a low bridge */
if (IsBridgeTile(ti->tile) && if (MayHaveBridgeAbove(ti->tile) && IsBridgeAbove(ti->tile) && !(_display_opt & DO_TRANS_BUILDINGS)) {
IsBridgeMiddle(ti->tile) && uint height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile));
!(_display_opt & DO_TRANS_BUILDINGS) &&
GetBridgeHeight(ti->tile) <= TilePixelHeight(ti->tile) + TILE_HEIGHT) { if (height <= TilePixelHeight(ti->tile) + TILE_HEIGHT) return;
return;
} }
/* Drawing of pylons is finished, now draw the wires */ /* Drawing of pylons is finished, now draw the wires */
@ -335,7 +332,7 @@ static void DrawCatenaryOnBridge(const TileInfo *ti)
sss = &CatenarySpriteData[WIRE_X_FLAT_SW + (num % 2) + offset]; sss = &CatenarySpriteData[WIRE_X_FLAT_SW + (num % 2) + offset];
} }
height = GetBridgeHeight(ti->tile); height = GetBridgeHeight(end);
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, height + sss->z_offset sss->x_size, sss->y_size, sss->z_size, height + sss->z_offset
@ -363,6 +360,13 @@ static void DrawCatenaryOnBridge(const TileInfo *ti)
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);
}
}
if (_patches.disable_elrails) return; if (_patches.disable_elrails) return;
switch (GetTileType(ti->tile)) { switch (GetTileType(ti->tile)) {
@ -380,12 +384,10 @@ void DrawCatenary(const TileInfo *ti)
break; break;
case MP_TUNNELBRIDGE: case MP_TUNNELBRIDGE:
if (IsBridge(ti->tile) && IsBridgeMiddle(ti->tile) && GetRailTypeOnBridge(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenaryOnBridge(ti); case MP_STREET:
case MP_STATION:
break; break;
case MP_STREET: break;
case MP_STATION: break;
default: return; default: return;
} }
DrawCatenaryRailway(ti); DrawCatenaryRailway(ti);

View File

@ -2,6 +2,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "openttd.h"
#include "bridge_map.h"
#include "heightmap.h" #include "heightmap.h"
#include "clear_map.h" #include "clear_map.h"
#include "functions.h" #include "functions.h"
@ -414,6 +415,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

@ -551,16 +551,26 @@ static void Load_MAPE(void)
uint size = MapSize(); uint size = MapSize();
uint i; uint i;
for (i = 0; i != size;) { if (CheckSavegameVersion(42)) {
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];
} }
} }
} }
@ -570,17 +580,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);
} }
} }

46
npf.c
View File

@ -181,6 +181,11 @@ static uint NPFTunnelCost(AyStarNode* current)
} }
} }
static inline uint NPFBridgeCost(AyStarNode *current)
{
return NPF_TILE_LENGTH * GetBridgeLength(current->tile, GetOtherBridgeEnd(current->tile));
}
static uint NPFSlopeCost(AyStarNode* current) static uint NPFSlopeCost(AyStarNode* current)
{ {
TileIndex next = current->tile + TileOffsByDiagDir(TrackdirToExitdir(current->direction)); TileIndex next = current->tile + TileOffsByDiagDir(TrackdirToExitdir(current->direction));
@ -265,11 +270,7 @@ static int32 NPFRoadPathCost(AyStar* as, AyStarNode* current, OpenListNode* pare
/* Determine base length */ /* Determine base length */
switch (GetTileType(tile)) { switch (GetTileType(tile)) {
case MP_TUNNELBRIDGE: case MP_TUNNELBRIDGE:
if (IsTunnel(tile)) { cost = IsTunnel(tile) ? NPFTunnelCost(current) : NPFBridgeCost(current);
cost = NPFTunnelCost(current);
} else {
cost = NPF_TILE_LENGTH;
}
break; break;
case MP_STREET: case MP_STREET:
@ -310,12 +311,8 @@ static int32 NPFRailPathCost(AyStar* as, AyStarNode* current, OpenListNode* pare
/* Determine base length */ /* Determine base length */
switch (GetTileType(tile)) { switch (GetTileType(tile)) {
case MP_TUNNELBRIDGE: case MP_TUNNELBRIDGE:
if (IsTunnel(tile)) { cost = IsTunnel(tile) ? NPFTunnelCost(current) : NPFBridgeCost(current);
cost = NPFTunnelCost(current); break;
break;
}
/* Fall through if above if is false, it is a bridge
* then. We treat that as ordinary rail */
case MP_RAILWAY: case MP_RAILWAY:
cost = _trackdir_length[trackdir]; /* Should be different for diagonal tracks */ cost = _trackdir_length[trackdir]; /* Should be different for diagonal tracks */
@ -472,17 +469,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;
@ -526,6 +513,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);
@ -536,6 +524,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
@ -583,8 +575,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

@ -55,6 +55,12 @@
#include "fontcache.h" #include "fontcache.h"
#include "newgrf_config.h" #include "newgrf_config.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 CallLandscapeTick(void); void CallLandscapeTick(void);
@ -1294,6 +1300,80 @@ bool AfterLoadGame(void)
} }
} }
if (CheckSavegameVersion(42)) {
TileIndex map_end = MapSize();
TileIndex tile;
Vehicle* v;
for (tile = 0; tile != map_end; tile++) {
if (MayHaveBridgeAbove(tile)) ClearBridgeMiddle(tile);
if (IsBridgeTile(tile)) {
if (HASBIT(_m[tile].m5, 6)) { // middle part
Axis axis = (Axis)GB(_m[tile].m5, 0, 1);
if (HASBIT(_m[tile].m5, 5)) { // 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 {
TownID 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 {
MakeCanal(tile, GetTileOwner(tile));
}
}
SetBridgeMiddle(tile, axis);
} else { // ramp
Axis axis = (Axis)GB(_m[tile].m5, 0, 1);
uint north_south = GB(_m[tile].m5, 5, 1);
DiagDirection dir = ReverseDiagDir(XYNSToDiagDir(axis, north_south));
TransportType type = (TransportType)GB(_m[tile].m5, 1, 2);
_m[tile].m5 = 1 << 7 | type << 2 | dir;
}
}
}
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: NOT_REACHED();
case DIAGDIR_NE: if ((v->x_pos & 0xF) != 0) continue; break;
case DIAGDIR_SE: if ((v->y_pos & 0xF) != TILE_SIZE - 1) continue; break;
case DIAGDIR_SW: if ((v->x_pos & 0xF) != TILE_SIZE - 1) continue; break;
case DIAGDIR_NW: if ((v->y_pos & 0xF) != 0) continue; break;
}
} else if (v->z_pos > GetSlopeZ(v->x_pos, v->y_pos)) {
v->tile = GetNorthernBridgeEnd(v->tile);
} else {
continue;
}
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;
@ -1344,15 +1424,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

@ -258,21 +258,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 += TileOffsByDiagDir(direction); tile += TileOffsByDiagDir(direction);
@ -283,11 +289,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
@ -670,7 +672,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;
@ -708,22 +709,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
@ -751,12 +770,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 a bridge. */ if (!HASBIT(tpf->railtypes, IsTileType(tile, MP_STREET) ? GetRailTypeCrossing(tile) : GetRailType(tile))) {
if (!(IsBridgeTile(tile) && IsBridgeMiddle(tile) && GetBridgeAxis(tile) == DiagDirToAxis(direction))) { bits = 0;
if (!HASBIT(tpf->railtypes, IsTileType(tile, MP_STREET) ? GetRailTypeCrossing(tile) : GetRailType(tile))) { break;
bits = 0;
break;
}
} }
/////////////////// ///////////////////

22
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);
@ -120,26 +119,9 @@ RailType GetTileRailType(TileIndex tile, Trackdir trackdir)
case MP_TUNNELBRIDGE: case MP_TUNNELBRIDGE:
if (IsTunnel(tile)) { if (IsTunnel(tile)) {
if (GetTunnelTransportType(tile) == TRANSPORT_RAIL) { if (GetTunnelTransportType(tile) == TRANSPORT_RAIL) return GetRailType(tile);
return GetRailType(tile);
}
} else { } else {
if (IsBridgeRamp(tile)) { if (GetBridgeTransportType(tile) == TRANSPORT_RAIL) return GetRailType(tile);
if (GetBridgeTransportType(tile) == TRANSPORT_RAIL) {
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

@ -247,36 +247,13 @@ 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) ||
AxisToTrackBits(OtherAxis(GetBridgeAxis(tile))) != 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, railtype);
} 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)) {
return CMD_ERROR; return CMD_ERROR;
} }
if (!IsTileOwner(tile, _current_player) || if (!IsTileOwner(tile, _current_player) ||
!IsCompatibleRail(GetRailType(tile), railtype)) { GetRailType(tile) != railtype) {
// Get detailed error message // Get detailed error message
return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
} }
@ -366,20 +343,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 ||
@ -617,6 +580,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;
@ -1414,6 +1379,7 @@ default_waypoint:
); );
} }
} }
DrawBridgeMiddle(ti);
} }
@ -1513,19 +1479,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 * 0x101) return v; if (dest->track & v->u.rail.track * 0x101) return v;
@ -1541,15 +1499,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)
@ -1559,9 +1520,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; //Vehicle inside a tunnel or on a bridge
for (; tile != end; tile += TileOffsByDiagDir(direction)) { for (; tile != end; tile += TileOffsByDiagDir(direction)) {
if (VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL) if (VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL)
return true; return true;

View File

@ -87,11 +87,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);
@ -103,11 +98,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);
}
static inline TrackBits GetTrackBits(TileIndex tile) static inline TrackBits GetTrackBits(TileIndex tile)
{ {

View File

@ -105,103 +105,73 @@ 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) {
/* Are we removing a piece of road below a bridge, or not. If below t = GetTownByTile(tile);
* a bridge we need to calculate the town's index as it is not saved
* in the map array (no space) */
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
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 (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
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);
YapfNotifyTrackLayoutChange(tile, FIND_FIRST_BIT(GetTrackBits(tile)));
} }
return _price.remove_road * 2; return _price.remove_road * 2;
}
case MP_STREET: default:
if (!EnsureNoVehicle(tile)) return CMD_ERROR; case ROAD_TILE_DEPOT:
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 (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
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);
YapfNotifyTrackLayoutChange(tile, FIND_FIRST_BIT(GetTrackBits(tile)));
}
return _price.remove_road * 2;
}
default:
case ROAD_TILE_DEPOT:
return CMD_ERROR;
}
default: return CMD_ERROR;
} }
} }
@ -362,32 +332,6 @@ int32 CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
return _price.build_road * 2; return _price.build_road * 2;
} }
case MP_TUNNELBRIDGE:
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);
@ -587,6 +531,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;
@ -820,6 +766,7 @@ static void DrawTile_Road(TileInfo *ti)
break; break;
} }
} }
DrawBridgeMiddle(ti);
} }
void DrawRoadDepotSprite(int x, int y, DiagDirection dir) void DrawRoadDepotSprite(int x, int y, DiagDirection dir)

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) ||
GetTransportTypeUnderBridge(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

@ -21,7 +21,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_callbacks.h" #include "newgrf_callbacks.h"
#include "newgrf_engine.h" #include "newgrf_engine.h"
@ -322,8 +324,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;
@ -444,14 +444,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 ||
IsRoadVehInDepot(v) ||
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;
@ -518,11 +523,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;
@ -872,6 +875,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) {
@ -1339,8 +1343,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);
@ -1351,6 +1354,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 = 41; const uint16 SAVEGAME_VERSION = 42;
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

@ -4,6 +4,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"
@ -795,6 +796,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

@ -745,6 +745,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"
@ -73,11 +74,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 "date.h" #include "date.h"
#include "table/town_land.h" #include "table/town_land.h"
#include "genworld.h" #include "genworld.h"
@ -1118,6 +1119,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;
@ -1160,6 +1163,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;
} }
@ -1291,6 +1296,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_sound.h" #include "newgrf_sound.h"
@ -105,10 +106,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 {
@ -1601,13 +1599,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 */
@ -1940,8 +1939,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
@ -2733,9 +2730,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;
@ -2811,13 +2806,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
@ -3158,15 +3146,16 @@ static void TrainController(Vehicle *v, bool update_image)
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;
} }
} }
@ -3263,7 +3252,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)
@ -3294,15 +3283,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);
} }
@ -3313,7 +3303,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);
} }
@ -3402,10 +3392,11 @@ 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; dir = IsTunnel(tile) ? GetTunnelDirection(tile) : 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"
@ -75,6 +76,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);
@ -134,6 +136,7 @@ void PlaceTreesRandomly(void)
IncreaseGeneratingWorldProgress(GWP_TREE); IncreaseGeneratingWorldProgress(GWP_TREE);
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);
@ -167,7 +170,10 @@ void PlaceTreesRandomly(void)
IncreaseGeneratingWorldProgress(GWP_TREE); IncreaseGeneratingWorldProgress(GWP_TREE);
if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_FIELDS) && GetTropicZone(tile) == TROPICZONE_RAINFOREST) { if (IsTileType(tile, MP_CLEAR) &&
!IsBridgeAbove(tile) &&
!IsClearGround(tile, CLEAR_FIELDS) &&
GetTropicZone(tile) == TROPICZONE_RAINFOREST) {
PlaceTree(tile, r); PlaceTree(tile, r);
} }
} while (--i); } while (--i);
@ -250,7 +256,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;
} }
@ -547,7 +554,7 @@ static void TileLoop_Trees(TileIndex tile)
tile += TileOffsByDir(Random() & 7); tile += TileOffsByDir(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:
@ -580,6 +587,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;
@ -602,6 +610,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);
@ -614,6 +623,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) {

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "openttd.h"
#include "bridge_map.h"
#include "table/strings.h" #include "table/strings.h"
#include "table/sprites.h" #include "table/sprites.h"
#include "functions.h" #include "functions.h"
@ -144,6 +145,7 @@ static void DrawTile_Unmovable(TileInfo *ti)
PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile)) + PALETTE_MODIFIER_COLOR + SPR_BOUGHT_LAND, PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile)) + PALETTE_MODIFIER_COLOR + SPR_BOUGHT_LAND,
ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 10, GetSlopeZ(ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2) ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 10, GetSlopeZ(ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2)
); );
DrawBridgeMiddle(ti);
break; break;
default: { default: {

View File

@ -314,7 +314,6 @@ VARDEF StringID _switch_mode_errorstr;
VARDEF bool _exit_game; VARDEF bool _exit_game;
VARDEF SmallFiosItem _file_to_saveload; VARDEF SmallFiosItem _file_to_saveload;
VARDEF byte _get_z_hint; // used as a hint to getslopez to return the right height at a bridge.
VARDEF Vehicle *_place_clicked_vehicle; VARDEF Vehicle *_place_clicked_vehicle;

View File

@ -300,7 +300,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

@ -21,7 +21,7 @@
#include "water_map.h" #include "water_map.h"
#include "newgrf.h" #include "newgrf.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,
@ -66,6 +66,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);
@ -140,6 +142,12 @@ 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 ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
(MayHaveBridgeAbove(tile - delta) && IsBridgeAbove(tile - delta)) ||
(MayHaveBridgeAbove(tile + delta) && IsBridgeAbove(tile + delta))) {
return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
}
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
MakeLock(tile, _current_player, dir); MakeLock(tile, _current_player, dir);
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
@ -230,6 +238,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);
} }
@ -237,38 +247,16 @@ 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) && (!IsTileOwner(tile, OWNER_WATER) || HASBIT(p2, 0))) continue; if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || HASBIT(p2, 0))) 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) && (!IsTileOwner(tile, OWNER_WATER) || HASBIT(p2, 0))) return_cmd_error(STR_1007_ALREADY_BUILT);
if (flags & DC_EXEC) {
if (TileHeight(tile) == 0 && HASBIT(p2, 0)) {
SetWaterUnderBridge(tile);
} else {
SetCanalUnderBridge(tile, _current_player);
}
}
} 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) {
if (TileHeight(tile) == 0 && HASBIT(p2, 0)) {
MakeWater(tile);
} else {
MakeCanal(tile, _current_player);
}
}
}
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
if (TileHeight(tile) == 0) {
MakeWater(tile);
} else {
MakeCanal(tile, _current_player);
}
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
MarkTilesAroundDirty(tile); MarkTilesAroundDirty(tile);
} }
@ -366,14 +354,8 @@ static bool IsWateredTile(TileIndex tile)
return false; return false;
} }
case MP_STATION: case MP_STATION: return IsOilRig(tile) || IsDock(tile) || IsBuoy_(tile);
return IsOilRig(tile) || IsDock(tile) || IsBuoy_(tile); default: return false;
case MP_TUNNELBRIDGE:
return IsBridge(tile) && IsBridgeMiddle(tile) && IsWaterUnderBridge(tile);
default:
return false;
} }
} }
@ -449,6 +431,7 @@ 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 || !IsTileOwner(ti->tile, OWNER_WATER)) DrawCanalWater(ti->tile); if (ti->z != 0 || !IsTileOwner(ti->tile, OWNER_WATER)) DrawCanalWater(ti->tile);
DrawBridgeMiddle(ti);
break; break;
case WATER_COAST: case WATER_COAST:
@ -458,6 +441,7 @@ static void DrawTile_Water(TileInfo *ti)
} else { } else {
DrawGroundSprite(_water_shore_sprites[ti->tileh]); DrawGroundSprite(_water_shore_sprites[ti->tileh]);
} }
DrawBridgeMiddle(ti);
break; break;
case WATER_LOCK: { case WATER_LOCK: {
@ -570,27 +554,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"
@ -206,6 +207,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 = TileOffsByDiagDir(m_exitdir); TileIndexDiff diff = TileOffsByDiagDir(m_exitdir);
m_new_tile = TILE_ADD(m_old_tile, diff); m_new_tile = TILE_ADD(m_old_tile, diff);
@ -152,22 +166,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
@ -215,7 +214,7 @@ protected:
m_new_td_bits = TrackdirToTrackdirBits(ReverseTrackdir(m_old_td)); m_new_td_bits = TrackdirToTrackdirBits(ReverseTrackdir(m_old_td));
m_exitdir = exitdir; m_exitdir = exitdir;
m_tiles_skipped = 0; m_tiles_skipped = 0;
m_is_tunnel = m_is_station = false; m_is_tunnel = m_is_bridge = m_is_station = false;
return true; return true;
} }
} }
@ -249,20 +248,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

@ -95,6 +95,7 @@ typedef struct FollowTrack_t
TrackdirBits m_new_td_bits; ///< the new set of available trackdirs TrackdirBits m_new_td_bits; ///< the new set of available trackdirs
DiagDirection m_exitdir; ///< exit direction (leaving the old tile) DiagDirection m_exitdir; ///< exit direction (leaving the old tile)
bool m_is_tunnel; ///< last turn passed tunnel bool m_is_tunnel; ///< last turn passed tunnel
bool m_is_bridge; ///< last turn passed bridge ramp
bool m_is_station; ///< last turn passed station bool m_is_station; ///< last turn passed station
int m_tiles_skipped; ///< number of skipped tunnel or station tiles int m_tiles_skipped; ///< number of skipped tunnel or station tiles
} FollowTrack_t; } FollowTrack_t;

View File

@ -9,7 +9,7 @@ struct CYapfCostBase {
FORCEINLINE static bool stSlopeCost(TileIndex tile, Trackdir td) FORCEINLINE static bool stSlopeCost(TileIndex tile, Trackdir td)
{ {
if (IsDiagonalTrackdir(td)) { if (IsDiagonalTrackdir(td)) {
if (IsBridgeTile(tile) && IsBridgeRamp(tile)) { if (IsBridgeTile(tile)) {
// it is bridge ramp, check if we are entering the bridge // it is bridge ramp, check if we are entering the bridge
if (GetBridgeRampDirection(tile) != TrackdirToExitdir(td)) return false; // no, we are living it, no penalty if (GetBridgeRampDirection(tile) != TrackdirToExitdir(td)) return false; // no, we are living it, no penalty
// we are entering the bridge // we are entering the bridge

View File

@ -243,8 +243,6 @@ bool YapfCheckReverseTrain(Vehicle* v)
return reverse; return reverse;
} }
static TileIndex YapfGetVehicleOutOfTunnelTile(const Vehicle *v, bool bReverse);
bool YapfFindNearestRailDepotTwoWay(Vehicle *v, int max_distance, int reverse_penalty, TileIndex* depot_tile, bool* reversed) bool YapfFindNearestRailDepotTwoWay(Vehicle *v, int max_distance, int reverse_penalty, TileIndex* depot_tile, bool* reversed)
{ {
*depot_tile = INVALID_TILE; *depot_tile = INVALID_TILE;
@ -252,12 +250,8 @@ bool YapfFindNearestRailDepotTwoWay(Vehicle *v, int max_distance, int reverse_pe
Vehicle* last_veh = GetLastVehicleInChain(v); Vehicle* last_veh = GetLastVehicleInChain(v);
bool first_in_tunnel = v->u.rail.track == 0x40; TileIndex tile = v->tile;
bool last_in_tunnel = last_veh->u.rail.track == 0x40; TileIndex last_tile = last_veh->tile;
// tile where the engine and last wagon are
TileIndex tile = first_in_tunnel ? YapfGetVehicleOutOfTunnelTile(v, false) : v->tile;
TileIndex last_tile = last_in_tunnel ? YapfGetVehicleOutOfTunnelTile(last_veh, true) : last_veh->tile;
// their trackdirs // their trackdirs
Trackdir td = GetVehicleTrackdir(v); Trackdir td = GetVehicleTrackdir(v);
@ -276,38 +270,6 @@ bool YapfFindNearestRailDepotTwoWay(Vehicle *v, int max_distance, int reverse_pe
return ret; return ret;
} }
/** Retrieve the exit-tile of the vehicle from inside a tunnel
* Very similar to GetOtherTunnelEnd(), but we use the vehicle's
* direction for determining which end of the tunnel to find
* @param v the vehicle which is inside the tunnel and needs an exit
* @param bReverse should we search for the tunnel exit in the opposite direction?
* @return the exit-tile of the tunnel based on the vehicle's direction
* taken from tunnelbridge_cmd.c where the function body was disabled by
* #if 1 #else #endif (at r5951). Added bReverse argument to allow two-way
* operation (YapfFindNearestRailDepotTwoWay). */
static TileIndex YapfGetVehicleOutOfTunnelTile(const Vehicle *v, bool bReverse)
{
TileIndex tile = v->tile;
DiagDirection dir = DirToDiagDir((Direction)v->direction);
TileIndexDiff delta = TileOffsByDiagDir(dir);
byte z = v->z_pos;
if (bReverse) {
delta = -delta;
} else {
dir = ReverseDiagDir(dir);
}
while (
!IsTunnelTile(tile) ||
GetTunnelDirection(tile) != dir ||
GetTileZ(tile) != z
) {
tile += delta;
}
return tile;
}
/** if any track changes, this counter is incremented - that will invalidate segment cost cache */ /** if any track changes, this counter is incremented - that will invalidate segment cost cache */
int CSegmentCostCacheBase::s_rail_change_counter = 0; int CSegmentCostCacheBase::s_rail_change_counter = 0;

View File

@ -428,7 +428,6 @@ 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 (v->u.road.state == 255) tile = GetVehicleOutOfTunnelTile(v);
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;