Files
@ r2556:182249972e8b
Branch filter:
Location: cpp/openttd-patchpack/source/pbs.c
r2556:182249972e8b
7.8 KiB
text/x-c
(svn r3089) Fix possible issue with out-of-bounds array access in replace vehicle gui, and add brief commenting.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | /* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "functions.h"
#include "pbs.h"
#include "debug.h"
#include "map.h"
#include "tile.h"
#include "npf.h"
#include "pathfind.h"
#include "depot.h"
/** @file pbs.c Path-Based-Signalling implementation file
* @see pbs.h */
/* reserved track encoding:
normal railway tracks:
map3hi bits 4..6 = 'Track'number of reserved track + 1, if this is zero it means nothing is reserved on this tile
map3hi bit 7 = if this is set, then the opposite track ('Track'number^1) is also reserved
waypoints/stations:
map3lo bit 6 set = track is reserved
tunnels/bridges:
map3hi bit 0 set = track with 'Track'number 0 is reserved
map3hi bit 1 set = track with 'Track'number 1 is reserved
level crossings:
map5 bit 0 set = the rail track is reserved
*/
/**
* maps an encoded reserved track (from map3lo bits 4..7)
* to the tracks that are reserved.
* 0xFF are invalid entries and should never be accessed.
*/
static const byte encrt_to_reserved[16] = {
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0xFF,
0xFF, 0xFF, 0xFF, 0x0C, 0x0C, 0x30, 0x30, 0xFF
};
/**
* maps an encoded reserved track (from map3lo bits 4..7)
* to the track(dir)s that are unavailable due to reservations.
* 0xFFFF are invalid entries and should never be accessed.
*/
static const uint16 encrt_to_unavail[16] = {
0x0000, 0x3F3F, 0x3F3F, 0x3737, 0x3B3B, 0x1F1F, 0x2F2F, 0xFFFF,
0xFFFF, 0xFFFF, 0xFFFF, 0x3F3F, 0x3F3F, 0x3F3F, 0x3F3F, 0xFFFF
};
void PBSReserveTrack(TileIndex tile, Track track) {
assert(IsValidTile(tile));
assert(track <= 5);
switch (GetTileType(tile)) {
case MP_RAILWAY:
if ((_m[tile].m5 & ~1) == 0xC4) {
// waypoint
SETBIT(_m[tile].m3, 6);
} else {
// normal rail track
byte encrt = GB(_m[tile].m4, 4, 4); // get current encoded info (see comments at top of file)
if (encrt == 0) // nothing reserved before
encrt = track + 1;
else if (encrt == (track^1) + 1) // opposite track reserved before
encrt |= 8;
SB(_m[tile].m4, 4, 4, encrt);
}
break;
case MP_TUNNELBRIDGE:
_m[tile].m4 |= (1 << track) & 3;
break;
case MP_STATION:
SETBIT(_m[tile].m3, 6);
break;
case MP_STREET:
// make sure it is a railroad crossing
if (!IsLevelCrossing(tile)) return;
SETBIT(_m[tile].m5, 0);
break;
default:
return;
}
// if debugging, mark tile dirty to show reserved status
if (_debug_pbs_level >= 1)
MarkTileDirtyByTile(tile);
}
byte PBSTileReserved(TileIndex tile) {
assert(IsValidTile(tile));
switch (GetTileType(tile)) {
case MP_RAILWAY:
if ((_m[tile].m5 & ~1) == 0xC4) {
// waypoint
// check if its reserved
if (!HASBIT(_m[tile].m3, 6)) return 0;
// return the track for the correct direction
return HASBIT(_m[tile].m5, 0) ? 2 : 1;
} else {
// normal track
byte res = encrt_to_reserved[GB(_m[tile].m4, 4, 4)];
assert(res != 0xFF);
return res;
}
case MP_TUNNELBRIDGE:
return GB(_m[tile].m4, 0, 2);
case MP_STATION:
// check if its reserved
if (!HASBIT(_m[tile].m3, 6)) return 0;
// return the track for the correct direction
return HASBIT(_m[tile].m5, 0) ? 2 : 1;
case MP_STREET:
// make sure its a railroad crossing
if (!IsLevelCrossing(tile)) return 0;
// check if its reserved
if (!HASBIT(_m[tile].m5, 0)) return 0;
// return the track for the correct direction
return HASBIT(_m[tile].m5, 3) ? 1 : 2;
default:
return 0;
}
}
uint16 PBSTileUnavail(TileIndex tile) {
assert(IsValidTile(tile));
switch (GetTileType(tile)) {
case MP_RAILWAY:
if ((_m[tile].m5 & ~1) == 0xC4) {
// waypoint
return HASBIT(_m[tile].m3, 6) ? TRACKDIR_BIT_MASK : 0;
} else {
// normal track
uint16 res = encrt_to_unavail[GB(_m[tile].m4, 4, 4)];
assert(res != 0xFFFF);
return res;
}
case MP_TUNNELBRIDGE:
return GB(_m[tile].m4, 0, 2) | (GB(_m[tile].m4, 0, 2) << 8);
case MP_STATION:
return HASBIT(_m[tile].m3, 6) ? TRACKDIR_BIT_MASK : 0;
case MP_STREET:
// make sure its a railroad crossing
if (!IsLevelCrossing(tile)) return 0;
// check if its reserved
return (HASBIT(_m[tile].m5, 0)) ? TRACKDIR_BIT_MASK : 0;
default:
return 0;
}
}
void PBSClearTrack(TileIndex tile, Track track) {
assert(IsValidTile(tile));
assert(track <= 5);
switch (GetTileType(tile)) {
case MP_RAILWAY:
if ((_m[tile].m5 & ~1) == 0xC4) {
// waypoint
CLRBIT(_m[tile].m3, 6);
} else {
// normal rail track
byte encrt = GB(_m[tile].m4, 4, 4);
if (encrt == track + 1)
encrt = 0;
else if (encrt == track + 1 + 8)
encrt = (track^1) + 1;
else if (encrt == (track^1) + 1 + 8)
encrt &= 7;
SB(_m[tile].m4, 4, 4, encrt);
}
break;
case MP_TUNNELBRIDGE:
_m[tile].m4 &= ~((1 << track) & 3);
break;
case MP_STATION:
CLRBIT(_m[tile].m3, 6);
break;
case MP_STREET:
// make sure it is a railroad crossing
if (!IsLevelCrossing(tile)) return;
CLRBIT(_m[tile].m5, 0);
break;
default:
return;
}
// if debugging, mark tile dirty to show reserved status
if (_debug_pbs_level >= 1)
MarkTileDirtyByTile(tile);
}
void PBSClearPath(TileIndex tile, Trackdir trackdir, TileIndex end_tile, Trackdir end_trackdir) {
uint16 res;
FindLengthOfTunnelResult flotr;
assert(IsValidTile(tile));
assert(IsValidTrackdir(trackdir));
do {
PBSClearTrack(tile, TrackdirToTrack(trackdir));
if (tile == end_tile && TrackdirToTrack(trackdir) == TrackdirToTrack(end_trackdir))
return;
if (IsTileType(tile, MP_TUNNELBRIDGE) &&
GB(_m[tile].m5, 4, 4) == 0 &&
GB(_m[tile].m5, 0, 2) == TrackdirToExitdir(trackdir)) {
// this is a tunnel
flotr = FindLengthOfTunnel(tile, TrackdirToExitdir(trackdir));
tile = flotr.tile;
} else {
byte exitdir = TrackdirToExitdir(trackdir);
tile = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir(exitdir));
}
res = PBSTileReserved(tile);
res |= res << 8;
res &= TrackdirReachesTrackdirs(trackdir);
trackdir = FindFirstBit2x64(res);
} while (res != 0);
}
bool PBSIsPbsSignal(TileIndex tile, Trackdir trackdir)
{
assert(IsValidTile(tile));
assert(IsValidTrackdir(trackdir));
if (!_patches.new_pathfinding_all)
return false;
if (!IsTileType(tile, MP_RAILWAY))
return false;
if (GetRailTileType(tile) != RAIL_TYPE_SIGNALS)
return false;
if (!HasSignalOnTrackdir(tile, trackdir))
return false;
if (GetSignalType(tile, TrackdirToTrack(trackdir)) == 4)
return true;
else
return false;
}
typedef struct SetSignalsDataPbs {
int cur;
// these are used to keep track of the signals.
byte bit[NUM_SSD_ENTRY];
TileIndex tile[NUM_SSD_ENTRY];
} SetSignalsDataPbs;
// This function stores the signals inside the SetSignalsDataPbs struct, passed as callback to FollowTrack() in the PBSIsPbsSegment() function below
static bool SetSignalsEnumProcPBS(uint tile, SetSignalsDataPbs *ssd, int trackdir, uint length, byte *state)
{
// the tile has signals?
if (IsTileType(tile, MP_RAILWAY)) {
if (HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) {
if (ssd->cur != NUM_SSD_ENTRY) {
ssd->tile[ssd->cur] = tile; // remember the tile index
ssd->bit[ssd->cur] = TrackdirToTrack(trackdir); // and the controlling bit number
ssd->cur++;
}
return true;
} else if (IsTileDepotType(tile, TRANSPORT_RAIL))
return true; // don't look further if the tile is a depot
}
return false;
}
bool PBSIsPbsSegment(uint tile, Trackdir trackdir)
{
SetSignalsDataPbs ssd;
bool result = PBSIsPbsSignal(tile, trackdir);
DiagDirection direction = TrackdirToExitdir(trackdir);//GetDepotDirection(tile,TRANSPORT_RAIL);
int i;
ssd.cur = 0;
FollowTrack(tile, 0xC000 | TRANSPORT_RAIL, direction, (TPFEnumProc*)SetSignalsEnumProcPBS, NULL, &ssd);
for(i=0; i!=ssd.cur; i++) {
uint tile = ssd.tile[i];
byte bit = ssd.bit[i];
if (!PBSIsPbsSignal(tile, bit) && !PBSIsPbsSignal(tile, bit | 8))
return false;
result = true;
}
return result;
}
|