summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2008-09-07 11:23:10 +0000
committerrubidium <rubidium@openttd.org>2008-09-07 11:23:10 +0000
commit9474db5cb6c4b9db2f7b68d1dda1a523305282f1 (patch)
tree94706b006a8848169482c99bfbb9ca6f9c734954
parentf4ee4fd5aed4861fe65757d2c61ce9510c4a6216 (diff)
downloadopenttd-9474db5cb6c4b9db2f7b68d1dda1a523305282f1.tar.xz
(svn r14258) -Codechange: rework the way to query the vehicle hash to make sure it always results in the same irregardless of the order of the hash-linked-list.
-Fix: desync in PBS reservation following, vehicle flooding and road vehicle overtake/follow code.
-rw-r--r--src/pbs.cpp57
-rw-r--r--src/pbs.h2
-rw-r--r--src/rail_cmd.cpp10
-rw-r--r--src/road_cmd.cpp4
-rw-r--r--src/roadveh_cmd.cpp54
-rw-r--r--src/signal.cpp18
-rw-r--r--src/station_cmd.cpp2
-rw-r--r--src/train_cmd.cpp30
-rw-r--r--src/tunnelbridge_cmd.cpp4
-rw-r--r--src/vehicle.cpp145
-rw-r--r--src/vehicle_func.h10
-rw-r--r--src/water_cmd.cpp65
12 files changed, 246 insertions, 155 deletions
diff --git a/src/pbs.cpp b/src/pbs.cpp
index ac16a7a7b..c57eba615 100644
--- a/src/pbs.cpp
+++ b/src/pbs.cpp
@@ -206,12 +206,29 @@ static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Tra
return PBSTileInfo(tile, trackdir, false);
}
-/** Callback for VehicleFromPos to find a train on a specific track. */
+/**
+ * Helper struct for finding the best matching vehicle on a specific track.
+ */
+struct FindTrainOnTrackInfo {
+ PBSTileInfo res; ///< Information about the track.
+ Vehicle *best; ///< The currently "best" vehicle we have found.
+
+ /** Init the best location to NULL always! */
+ FindTrainOnTrackInfo() : best(NULL) {}
+};
+
+/** Callback for Has/FindVehicleOnPos to find a train on a specific track. */
static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data)
{
- PBSTileInfo info = *(PBSTileInfo *)data;
+ FindTrainOnTrackInfo *info = (FindTrainOnTrackInfo *)data;
+
+ if (v->type == VEH_TRAIN && !(v->vehstatus & VS_CRASHED) && HasBit((TrackBits)v->u.rail.track, TrackdirToTrack(info->res.trackdir))) {
+ v = v->First();
- if (v->type == VEH_TRAIN && !(v->vehstatus & VS_CRASHED) && HasBit((TrackBits)v->u.rail.track, TrackdirToTrack(info.trackdir))) return v;
+ /* ALWAYS return the lowest ID (anti-desync!) */
+ if (info->best == NULL || v->index < info->best->index) info->best = v;
+ return v;
+ }
return NULL;
}
@@ -223,7 +240,7 @@ static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data)
* @param train_on_res Is set to a train we might encounter
* @returns The last tile of the reservation or the current train tile if no reservation present.
*/
-PBSTileInfo FollowTrainReservation(const Vehicle *v, Vehicle **train_on_res)
+PBSTileInfo FollowTrainReservation(const Vehicle *v, bool *train_on_res)
{
assert(v->type == VEH_TRAIN);
@@ -232,10 +249,11 @@ PBSTileInfo FollowTrainReservation(const Vehicle *v, Vehicle **train_on_res)
if (IsRailDepotTile(tile) && !GetRailDepotReservation(tile)) return PBSTileInfo(tile, trackdir, false);
- PBSTileInfo res = FollowReservation(v->owner, GetRailTypeInfo(v->u.rail.railtype)->compatible_railtypes, tile, trackdir);
- res.okay = IsSafeWaitingPosition(v, res.tile, res.trackdir, true, _settings_game.pf.forbid_90_deg);
- if (train_on_res != NULL) *train_on_res = VehicleFromPos(res.tile, &res, FindTrainOnTrackEnum);
- return res;
+ FindTrainOnTrackInfo ftoti;
+ ftoti.res = FollowReservation(v->owner, GetRailTypeInfo(v->u.rail.railtype)->compatible_railtypes, tile, trackdir);
+ ftoti.res.okay = IsSafeWaitingPosition(v, ftoti.res.tile, ftoti.res.trackdir, true, _settings_game.pf.forbid_90_deg);
+ if (train_on_res != NULL) *train_on_res = HasVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
+ return ftoti.res;
}
/**
@@ -256,24 +274,25 @@ Vehicle *GetTrainForReservation(TileIndex tile, Track track)
* have a train on it. We need FollowReservation to ignore one-way signals
* here, as one of the two search directions will be the "wrong" way. */
for (int i = 0; i < 2; ++i, trackdir = ReverseTrackdir(trackdir)) {
- PBSTileInfo dest = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true);
+ FindTrainOnTrackInfo ftoti;
+ ftoti.res = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true);
- Vehicle *v = VehicleFromPos(dest.tile, &dest, FindTrainOnTrackEnum);
- if (v != NULL) return v->First();
+ FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
+ if (ftoti.best != NULL) return ftoti.best;
/* Special case for stations: check the whole platform for a vehicle. */
- if (IsRailwayStationTile(dest.tile)) {
- TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(dest.trackdir)));
- for (TileIndex st_tile = dest.tile + diff; IsCompatibleTrainStationTile(st_tile, dest.tile); st_tile += diff) {
- v = VehicleFromPos(st_tile, &dest, FindTrainOnTrackEnum);
- if (v != NULL) return v->First();
+ if (IsRailwayStationTile(ftoti.res.tile)) {
+ TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir)));
+ for (TileIndex st_tile = ftoti.res.tile + diff; IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) {
+ FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum);
+ if (ftoti.best != NULL) return ftoti.best;
}
}
/* Special case for bridges/tunnels: check the other end as well. */
- if (IsTileType(dest.tile, MP_TUNNELBRIDGE)) {
- v = VehicleFromPos(GetOtherTunnelBridgeEnd(dest.tile), &dest, FindTrainOnTrackEnum);
- if (v != NULL) return v->First();
+ if (IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) {
+ FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum);
+ if (ftoti.best != NULL) return ftoti.best;
}
}
diff --git a/src/pbs.h b/src/pbs.h
index c0ee485d1..8e426705f 100644
--- a/src/pbs.h
+++ b/src/pbs.h
@@ -27,7 +27,7 @@ struct PBSTileInfo {
PBSTileInfo(TileIndex _t, Trackdir _td, bool _okay) : tile(_t), trackdir(_td), okay(_okay) {}
};
-PBSTileInfo FollowTrainReservation(const Vehicle *v, Vehicle **train_on_res = NULL);
+PBSTileInfo FollowTrainReservation(const Vehicle *v, bool *train_on_res = NULL);
bool IsSafeWaitingPosition(const Vehicle *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg = false);
bool IsWaitingPositionFree(const Vehicle *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg = false);
diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp
index eea934a6c..b101934e4 100644
--- a/src/rail_cmd.cpp
+++ b/src/rail_cmd.cpp
@@ -130,7 +130,7 @@ static bool EnsureNoTrainOnTrack(TileIndex tile, Track track)
{
TrackBits rail_bits = TrackToTrackBits(track);
- return VehicleFromPos(tile, &rail_bits, &EnsureNoTrainOnTrackProc) == NULL;
+ return !HasVehicleOnPos(tile, &rail_bits, &EnsureNoTrainOnTrackProc);
}
static bool CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags)
@@ -1334,7 +1334,7 @@ CommandCost CmdConvertRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
SetRailType(tile, totype);
MarkTileDirtyByTile(tile);
/* update power of train engines on this tile */
- VehicleFromPos(tile, NULL, &UpdateTrainPowerProc);
+ FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
}
}
@@ -1384,7 +1384,7 @@ CommandCost CmdConvertRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
/* When not coverting rail <-> el. rail, any vehicle cannot be in tunnel/bridge */
if (!IsCompatibleRail(GetRailType(tile), totype) &&
- GetVehicleTunnelBridge(tile, endtile) != NULL) continue;
+ !HasVehicleOnTunnelBridge(tile, endtile)) continue;
if (flags & DC_EXEC) {
Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
@@ -1398,8 +1398,8 @@ CommandCost CmdConvertRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
SetRailType(tile, totype);
SetRailType(endtile, totype);
- VehicleFromPos(tile, NULL, &UpdateTrainPowerProc);
- VehicleFromPos(endtile, NULL, &UpdateTrainPowerProc);
+ FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
+ FindVehicleOnPos(endtile, NULL, &UpdateTrainPowerProc);
YapfNotifyTrackLayoutChange(tile, track);
YapfNotifyTrackLayoutChange(endtile, track);
diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp
index 44a0ae854..cea81bca7 100644
--- a/src/road_cmd.cpp
+++ b/src/road_cmd.cpp
@@ -223,7 +223,7 @@ static CommandCost RemoveRoad(TileIndex tile, uint32 flags, RoadBits pieces, Roa
case MP_TUNNELBRIDGE:
if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) return CMD_ERROR;
- if (GetVehicleTunnelBridge(tile, GetOtherTunnelBridgeEnd(tile)) != NULL) return CMD_ERROR;
+ if (HasVehicleOnTunnelBridge(tile, GetOtherTunnelBridgeEnd(tile))) return CMD_ERROR;
break;
default:
@@ -589,7 +589,7 @@ CommandCost CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
if (MirrorRoadBits(DiagDirToRoadBits(GetTunnelBridgeDirection(tile))) != pieces) return CMD_ERROR;
if (HasTileRoadType(tile, rt)) return_cmd_error(STR_1007_ALREADY_BUILT);
/* Don't allow adding roadtype to the bridge/tunnel when vehicles are already driving on it */
- if (GetVehicleTunnelBridge(tile, GetOtherTunnelBridgeEnd(tile)) != NULL) return CMD_ERROR;
+ if (HasVehicleOnTunnelBridge(tile, GetOtherTunnelBridgeEnd(tile))) return CMD_ERROR;
break;
default: {
diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp
index 9b453baf8..45906696b 100644
--- a/src/roadveh_cmd.cpp
+++ b/src/roadveh_cmd.cpp
@@ -646,7 +646,7 @@ static void RoadVehCheckTrainCrash(Vehicle *v)
if (!IsLevelCrossingTile(tile)) continue;
- if (VehicleFromPosXY(v->x_pos, v->y_pos, u, EnumCheckRoadVehCrashTrain) != NULL) {
+ if (HasVehicleOnPosXY(v->x_pos, v->y_pos, u, EnumCheckRoadVehCrashTrain)) {
RoadVehCrash(v);
return;
}
@@ -725,7 +725,9 @@ static void StartRoadVehSound(const Vehicle* v)
struct RoadVehFindData {
int x;
int y;
- const Vehicle* veh;
+ const Vehicle *veh;
+ Vehicle *best;
+ uint best_diff;
Direction dir;
};
@@ -734,28 +736,34 @@ static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data)
static const int8 dist_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 };
static const int8 dist_y[] = { -4, -1, 4, 8, 4, 1, -4, -8 };
- const RoadVehFindData *rvf = (RoadVehFindData*)data;
+ RoadVehFindData *rvf = (RoadVehFindData*)data;
short x_diff = v->x_pos - rvf->x;
short y_diff = v->y_pos - rvf->y;
- return
- v->type == VEH_ROAD &&
- !v->IsInDepot() &&
- abs(v->z_pos - rvf->veh->z_pos) < 6 &&
- v->direction == rvf->dir &&
- rvf->veh->First() != v->First() &&
- (dist_x[v->direction] >= 0 || (x_diff > dist_x[v->direction] && x_diff <= 0)) &&
- (dist_x[v->direction] <= 0 || (x_diff < dist_x[v->direction] && x_diff >= 0)) &&
- (dist_y[v->direction] >= 0 || (y_diff > dist_y[v->direction] && y_diff <= 0)) &&
- (dist_y[v->direction] <= 0 || (y_diff < dist_y[v->direction] && y_diff >= 0)) ?
- v : NULL;
+ if (v->type == VEH_ROAD &&
+ !v->IsInDepot() &&
+ abs(v->z_pos - rvf->veh->z_pos) < 6 &&
+ v->direction == rvf->dir &&
+ rvf->veh->First() != v->First() &&
+ (dist_x[v->direction] >= 0 || (x_diff > dist_x[v->direction] && x_diff <= 0)) &&
+ (dist_x[v->direction] <= 0 || (x_diff < dist_x[v->direction] && x_diff >= 0)) &&
+ (dist_y[v->direction] >= 0 || (y_diff > dist_y[v->direction] && y_diff <= 0)) &&
+ (dist_y[v->direction] <= 0 || (y_diff < dist_y[v->direction] && y_diff >= 0))) {
+ uint diff = abs(x_diff) + abs(y_diff);
+
+ if (diff < rvf->best_diff || (diff == rvf->best_diff && v->index < rvf->best->index)) {
+ rvf->best = v;
+ rvf->best_diff = diff;
+ }
+ }
+
+ return NULL;
}
-static Vehicle* RoadVehFindCloseTo(Vehicle* v, int x, int y, Direction dir)
+static Vehicle *RoadVehFindCloseTo(Vehicle *v, int x, int y, Direction dir)
{
RoadVehFindData rvf;
- Vehicle *u;
Vehicle *front = v->First();
if (front->u.road.reverse_ctr != 0) return NULL;
@@ -764,25 +772,27 @@ static Vehicle* RoadVehFindCloseTo(Vehicle* v, int x, int y, Direction dir)
rvf.y = y;
rvf.dir = dir;
rvf.veh = v;
+ rvf.best_diff = UINT_MAX;
+
if (front->u.road.state == RVSB_WORMHOLE) {
- u = VehicleFromPos(v->tile, &rvf, EnumCheckRoadVehClose);
- if (u == NULL) u = (Vehicle*)VehicleFromPos(GetOtherTunnelBridgeEnd(v->tile), &rvf, EnumCheckRoadVehClose);
+ FindVehicleOnPos(v->tile, &rvf, EnumCheckRoadVehClose);
+ FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &rvf, EnumCheckRoadVehClose);
} else {
- u = VehicleFromPosXY(x, y, &rvf, EnumCheckRoadVehClose);
+ FindVehicleOnPosXY(x, y, &rvf, EnumCheckRoadVehClose);
}
/* This code protects a roadvehicle from being blocked for ever
* If more than 1480 / 74 days a road vehicle is blocked, it will
* drive just through it. The ultimate backup-code of TTD.
* It can be disabled. */
- if (u == NULL) {
+ if (rvf.best_diff == UINT_MAX) {
front->u.road.blocked_ctr = 0;
return NULL;
}
if (++front->u.road.blocked_ctr > 1480) return NULL;
- return u;
+ return rvf.best;
}
static void RoadVehArrivesAt(const Vehicle* v, Station* st)
@@ -903,7 +913,7 @@ static bool CheckRoadBlockedForOvertaking(OvertakeData *od)
if (!HasBit(trackdirbits, od->trackdir) || (trackbits & ~TRACK_BIT_CROSS) || (red_signals != TRACKDIR_BIT_NONE)) return true;
/* Are there more vehicles on the tile except the two vehicles involved in overtaking */
- return VehicleFromPos(od->tile, od, EnumFindVehBlockingOvertake) != NULL;
+ return HasVehicleOnPos(od->tile, od, EnumFindVehBlockingOvertake);
}
static void RoadVehCheckOvertake(Vehicle *v, Vehicle *u)
diff --git a/src/signal.cpp b/src/signal.cpp
index 8d43b5dbd..9a86ceb8f 100644
--- a/src/signal.cpp
+++ b/src/signal.cpp
@@ -285,13 +285,13 @@ static SigFlags ExploreSegment(Owner owner)
if (IsRailDepot(tile)) {
if (enterdir == INVALID_DIAGDIR) { // from 'inside' - train just entered or left the depot
- if (!(flags & SF_TRAIN) && VehicleFromPos(tile, NULL, &TrainOnTileEnum) != NULL) flags |= SF_TRAIN;
+ if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
exitdir = GetRailDepotDirection(tile);
tile += TileOffsByDiagDir(exitdir);
enterdir = ReverseDiagDir(exitdir);
break;
} else if (enterdir == GetRailDepotDirection(tile)) { // entered a depot
- if (!(flags & SF_TRAIN) && VehicleFromPos(tile, NULL, &TrainOnTileEnum) != NULL) flags |= SF_TRAIN;
+ if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
continue;
} else {
continue;
@@ -300,7 +300,7 @@ static SigFlags ExploreSegment(Owner owner)
if (GetRailTileType(tile) == RAIL_TILE_WAYPOINT) {
if (GetWaypointAxis(tile) != DiagDirToAxis(enterdir)) continue;
- if (!(flags & SF_TRAIN) && VehicleFromPos(tile, NULL, &TrainOnTileEnum) != NULL) flags |= SF_TRAIN;
+ if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
tile += TileOffsByDiagDir(exitdir);
/* enterdir and exitdir stay the same */
break;
@@ -311,10 +311,10 @@ static SigFlags ExploreSegment(Owner owner)
if (tracks == TRACK_BIT_HORZ || tracks == TRACK_BIT_VERT) { // there is exactly one incidating track, no need to check
tracks = tracks_masked;
- if (!(flags & SF_TRAIN) && VehicleFromPos(tile, &tracks, &EnsureNoTrainOnTrackProc) != NULL) flags |= SF_TRAIN;
+ if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, &tracks, &EnsureNoTrainOnTrackProc)) flags |= SF_TRAIN;
} else {
if (tracks_masked == TRACK_BIT_NONE) continue; // no incidating track
- if (!(flags & SF_TRAIN) && VehicleFromPos(tile, NULL, &TrainOnTileEnum) != NULL) flags |= SF_TRAIN;
+ if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
}
if (HasSignals(tile)) { // there is exactly one track - not zero, because there is exit from this tile
@@ -366,7 +366,7 @@ static SigFlags ExploreSegment(Owner owner)
if (DiagDirToAxis(enterdir) != GetRailStationAxis(tile)) continue; // different axis
if (IsStationTileBlocked(tile)) continue; // 'eye-candy' station tile
- if (!(flags & SF_TRAIN) && VehicleFromPos(tile, NULL, &TrainOnTileEnum) != NULL) flags |= SF_TRAIN;
+ if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
tile += TileOffsByDiagDir(exitdir);
break;
@@ -375,7 +375,7 @@ static SigFlags ExploreSegment(Owner owner)
if (GetTileOwner(tile) != owner) continue;
if (DiagDirToAxis(enterdir) == GetCrossingRoadAxis(tile)) continue; // different axis
- if (!(flags & SF_TRAIN) && VehicleFromPos(tile, NULL, &TrainOnTileEnum) != NULL) flags |= SF_TRAIN;
+ if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
tile += TileOffsByDiagDir(exitdir);
break;
@@ -385,13 +385,13 @@ static SigFlags ExploreSegment(Owner owner)
DiagDirection dir = GetTunnelBridgeDirection(tile);
if (enterdir == INVALID_DIAGDIR) { // incoming from the wormhole
- if (!(flags & SF_TRAIN) && VehicleFromPos(tile, NULL, &TrainOnTileEnum) != NULL) flags |= SF_TRAIN;
+ if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
enterdir = dir;
exitdir = ReverseDiagDir(dir);
tile += TileOffsByDiagDir(exitdir); // just skip to next tile
} else { // NOT incoming from the wormhole!
if (ReverseDiagDir(enterdir) != dir) continue;
- if (!(flags & SF_TRAIN) && VehicleFromPos(tile, NULL, &TrainOnTileEnum) != NULL) flags |= SF_TRAIN;
+ if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
tile = GetOtherTunnelBridgeEnd(tile); // just skip to exit tile
enterdir = INVALID_DIAGDIR;
exitdir = INVALID_DIAGDIR;
diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp
index 8f8ef13b6..f9274a643 100644
--- a/src/station_cmd.cpp
+++ b/src/station_cmd.cpp
@@ -1506,7 +1506,7 @@ static CommandCost RemoveRoadStop(Station *st, uint32 flags, TileIndex tile)
/* don't do the check for drive-through road stops when company bankrupts */
if (IsDriveThroughStopTile(tile) && (flags & DC_BANKRUPT)) {
/* remove the 'going through road stop' status from all vehicles on that tile */
- if (flags & DC_EXEC) VehicleFromPos(tile, NULL, &ClearRoadStopStatusEnum);
+ if (flags & DC_EXEC) FindVehicleOnPos(tile, NULL, &ClearRoadStopStatusEnum);
} else {
if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
}
diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp
index 42e1d02ff..328c39e88 100644
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -1694,24 +1694,22 @@ static Vehicle *TrainApproachingCrossingEnum(Vehicle *v, void *data)
/**
* Finds a vehicle approaching rail-road crossing
* @param tile tile to test
- * @return pointer to vehicle approaching the crossing
+ * @return true if a vehicle is approaching the crossing
* @pre tile is a rail-road crossing
*/
-static Vehicle *TrainApproachingCrossing(TileIndex tile)
+static bool TrainApproachingCrossing(TileIndex tile)
{
assert(IsLevelCrossingTile(tile));
DiagDirection dir = AxisToDiagDir(GetCrossingRailAxis(tile));
TileIndex tile_from = tile + TileOffsByDiagDir(dir);
- Vehicle *v = VehicleFromPos(tile_from, &tile, &TrainApproachingCrossingEnum);
-
- if (v != NULL) return v;
+ if (HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum)) return true;
dir = ReverseDiagDir(dir);
tile_from = tile + TileOffsByDiagDir(dir);
- return VehicleFromPos(tile_from, &tile, &TrainApproachingCrossingEnum);
+ return HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum);
}
@@ -1726,7 +1724,7 @@ void UpdateLevelCrossing(TileIndex tile, bool sound)
assert(IsLevelCrossingTile(tile));
/* train on crossing || train approaching crossing || reserved */
- bool new_state = VehicleFromPos(tile, NULL, &TrainOnTileEnum) != NULL || TrainApproachingCrossing(tile) || GetCrossingReservation(tile);
+ bool new_state = HasVehicleOnPos(tile, NULL, &TrainOnTileEnum) || TrainApproachingCrossing(tile) || GetCrossingReservation(tile);
if (new_state != IsCrossingBarred(tile)) {
if (new_state && sound) {
@@ -3028,7 +3026,7 @@ bool TryPathReserve(Vehicle *v, bool mark_as_stuck, bool first_tile_okay)
}
}
- Vehicle *other_train = NULL;
+ bool other_train = false;
PBSTileInfo origin = FollowTrainReservation(v, &other_train);
/* If we have a reserved path and the path ends at a safe tile, we are finished already. */
if (origin.okay && (v->tile != origin.tile || first_tile_okay)) {
@@ -3041,7 +3039,7 @@ bool TryPathReserve(Vehicle *v, bool mark_as_stuck, bool first_tile_okay)
* This can only happen when tracks and signals are changed. A crash
* is probably imminent, don't do any further reservation because
* it might cause stale reservations. */
- if (other_train != NULL && v->tile != origin.tile) {
+ if (other_train && v->tile != origin.tile) {
if (mark_as_stuck) MarkTrainAsStuck(v);
return false;
}
@@ -3518,10 +3516,10 @@ static void CheckTrainCollision(Vehicle *v)
/* find colliding vehicles */
if (v->u.rail.track == TRACK_BIT_WORMHOLE) {
- VehicleFromPos(v->tile, &tcc, FindTrainCollideEnum);
- VehicleFromPos(GetOtherTunnelBridgeEnd(v->tile), &tcc, FindTrainCollideEnum);
+ FindVehicleOnPos(v->tile, &tcc, FindTrainCollideEnum);
+ FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &tcc, FindTrainCollideEnum);
} else {
- VehicleFromPosXY(v->x_pos, v->y_pos, &tcc, FindTrainCollideEnum);
+ FindVehicleOnPosXY(v->x_pos, v->y_pos, &tcc, FindTrainCollideEnum);
}
/* any dead -> no crash */
@@ -3652,7 +3650,7 @@ static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image)
exitdir = ReverseDiagDir(exitdir);
/* check if a train is waiting on the other side */
- if (VehicleFromPos(o_tile, &exitdir, &CheckVehicleAtSignal) == NULL) return;
+ if (!HasVehicleOnPos(o_tile, &exitdir, &CheckVehicleAtSignal)) return;
}
}
@@ -3819,9 +3817,9 @@ reverse_train_direction:
}
/** Collect trackbits of all crashed train vehicles on a tile
- * @param v Vehicle passed from VehicleFromPos()
+ * @param v Vehicle passed from Find/HasVehicleOnPos()
* @param data trackdirbits for the result
- * @return NULL to not abort VehicleFromPos()
+ * @return NULL to iterate over all vehicles on the tile.
*/
static Vehicle *CollectTrackbitsFromCrashedVehiclesEnum(Vehicle *v, void *data)
{
@@ -3894,7 +3892,7 @@ static void DeleteLastWagon(Vehicle *v)
/* If there are still crashed vehicles on the tile, give the track reservation to them */
TrackBits remaining_trackbits = TRACK_BIT_NONE;
- VehicleFromPos(tile, &remaining_trackbits, CollectTrackbitsFromCrashedVehiclesEnum);
+ FindVehicleOnPos(tile, &remaining_trackbits, CollectTrackbitsFromCrashedVehiclesEnum);
/* It is important that these two are the first in the loop, as reservation cannot deal with every trackbit combination */
assert(TRACK_BEGIN == TRACK_X && TRACK_Y == TRACK_BEGIN + 1);
diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp
index fcf05ffb8..95bb68d7c 100644
--- a/src/tunnelbridge_cmd.cpp
+++ b/src/tunnelbridge_cmd.cpp
@@ -605,7 +605,7 @@ static CommandCost DoClearTunnel(TileIndex tile, uint32 flags)
endtile = GetOtherTunnelEnd(tile);
- if (GetVehicleTunnelBridge(tile, endtile) != NULL) return CMD_ERROR;
+ if (HasVehicleOnTunnelBridge(tile, endtile)) return CMD_ERROR;
_build_tunnel_endtile = endtile;
@@ -670,7 +670,7 @@ static CommandCost DoClearBridge(TileIndex tile, uint32 flags)
endtile = GetOtherBridgeEnd(tile);
- if (GetVehicleTunnelBridge(tile, endtile) != NULL) return CMD_ERROR;
+ if (HasVehicleOnTunnelBridge(tile, endtile)) return CMD_ERROR;
direction = GetTunnelBridgeDirection(tile);
delta = TileOffsByDiagDir(direction);
diff --git a/src/vehicle.cpp b/src/vehicle.cpp
index 435f2b122..a3886c705 100644
--- a/src/vehicle.cpp
+++ b/src/vehicle.cpp
@@ -168,42 +168,12 @@ static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data)
return v;
}
-Vehicle *FindVehicleOnTileZ(TileIndex tile, byte z)
-{
- return (Vehicle*)VehicleFromPos(tile, &z, &EnsureNoVehicleProcZ);
-}
-
bool EnsureNoVehicleOnGround(TileIndex tile)
{
- return FindVehicleOnTileZ(tile, GetTileMaxZ(tile)) == NULL;
+ byte z = GetTileMaxZ(tile);
+ return !HasVehicleOnPos(tile, &z, &EnsureNoVehicleProcZ);
}
-Vehicle *FindVehicleBetween(TileIndex from, TileIndex to, byte z, bool without_crashed)
-{
- int x1 = TileX(from);
- int y1 = TileY(from);
- int x2 = TileX(to);
- int y2 = TileY(to);
- Vehicle *veh;
-
- /* Make sure x1 < x2 or y1 < y2 */
- if (x1 > x2 || y1 > y2) {
- Swap(x1, x2);
- Swap(y1, y2);
- }
- FOR_ALL_VEHICLES(veh) {
- if (without_crashed && (veh->vehstatus & VS_CRASHED) != 0) continue;
- if ((veh->type == VEH_TRAIN || veh->type == VEH_ROAD) && (z == 0xFF || veh->z_pos == z)) {
- if ((veh->x_pos >> 4) >= x1 && (veh->x_pos >> 4) <= x2 &&
- (veh->y_pos >> 4) >= y1 && (veh->y_pos >> 4) <= y2) {
- return veh;
- }
- }
- }
- return NULL;
-}
-
-
/** Procedure called for every vehicle found in tunnel/bridge in the hash map */
static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
{
@@ -217,14 +187,12 @@ static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
* Finds vehicle in tunnel / bridge
* @param tile first end
* @param endtile second end
- * @return pointer to vehicle found
+ * @return true if the bridge has a vehicle
*/
-Vehicle *GetVehicleTunnelBridge(TileIndex tile, TileIndex endtile)
+bool HasVehicleOnTunnelBridge(TileIndex tile, TileIndex endtile)
{
- Vehicle *v = (Vehicle*)VehicleFromPos(tile, NULL, &GetVehicleTunnelBridgeProc);
- if (v != NULL) return v;
-
- return (Vehicle*)VehicleFromPos(endtile, NULL, &GetVehicleTunnelBridgeProc);
+ return HasVehicleOnPos(tile, NULL, &GetVehicleTunnelBridgeProc) ||
+ HasVehicleOnPos(endtile, NULL, &GetVehicleTunnelBridgeProc);
}
@@ -384,14 +352,14 @@ const int HASH_RES = 0;
static Vehicle *_new_vehicle_position_hash[TOTAL_HASH_SIZE];
-static Vehicle *VehicleFromHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc)
+static Vehicle *VehicleFromHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc, bool find_first)
{
for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
for (int x = xl; ; x = (x + 1) & HASH_MASK) {
Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
for (; v != NULL; v = v->next_new_hash) {
Vehicle *a = proc(v, data);
- if (a != NULL) return a;
+ if (find_first && a != NULL) return a;
}
if (x == xu) break;
}
@@ -402,7 +370,18 @@ static Vehicle *VehicleFromHash(int xl, int yl, int xu, int yu, void *data, Vehi
}
-Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
+/**
+ * Helper function for FindVehicleOnPos/HasVehicleOnPos.
+ * @note Do not call this function directly!
+ * @param x The X location on the map
+ * @param y The Y location on the map
+ * @param data Arbitrary data passed to proc
+ * @param proc The proc that determines whether a vehicle will be "found".
+ * @param find_first Whether to return on the first found or iterate over
+ * all vehicles
+ * @return the best matching or first vehicle (depending on find_first).
+ */
+static Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc, bool find_first)
{
const int COLL_DIST = 6;
@@ -412,11 +391,55 @@ Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
int yl = GB((y - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
int yu = GB((y + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
- return VehicleFromHash(xl, yl, xu, yu, data, proc);
+ return VehicleFromHash(xl, yl, xu, yu, data, proc, find_first);
+}
+
+/**
+ * Find a vehicle from a specific location. It will call proc for ALL vehicles
+ * on the tile and YOU must make SURE that the "best one" is stored in the
+ * data value and is ALWAYS the same regardless of the order of the vehicles
+ * where proc was called on!
+ * When you fail to do this properly you create an almost untraceable DESYNC!
+ * @note The return value of proc will be ignored.
+ * @note Use this when you have the intention that all vehicles
+ * should be iterated over.
+ * @param x The X location on the map
+ * @param y The Y location on the map
+ * @param data Arbitrary data passed to proc
+ * @param proc The proc that determines whether a vehicle will be "found".
+ */
+void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
+{
+ VehicleFromPosXY(x, y, data, proc, false);
}
+/**
+ * Checks whether a vehicle in on a specific location. It will call proc for
+ * vehicles until it returns non-NULL.
+ * @note Use FindVehicleOnPosXY when you have the intention that all vehicles
+ * should be iterated over.
+ * @param x The X location on the map
+ * @param y The Y location on the map
+ * @param data Arbitrary data passed to proc
+ * @param proc The proc that determines whether a vehicle will be "found".
+ * @return True if proc returned non-NULL.
+ */
+bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
+{
+ return VehicleFromPosXY(x, y, data, proc, true) != NULL;
+}
-Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
+/**
+ * Helper function for FindVehicleOnPos/HasVehicleOnPos.
+ * @note Do not call this function directly!
+ * @param tile The location on the map
+ * @param data Arbitrary data passed to proc
+ * @param proc The proc that determines whether a vehicle will be "found".
+ * @param find_first Whether to return on the first found or iterate over
+ * all vehicles
+ * @return the best matching or first vehicle (depending on find_first).
+ */
+static Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first)
{
int x = GB(TileX(tile), HASH_RES, HASH_BITS);
int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
@@ -426,12 +449,46 @@ Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
if (v->tile != tile) continue;
Vehicle *a = proc(v, data);
- if (a != NULL) return a;
+ if (find_first && a != NULL) return a;
}
return NULL;
}
+/**
+ * Find a vehicle from a specific location. It will call proc for ALL vehicles
+ * on the tile and YOU must make SURE that the "best one" is stored in the
+ * data value and is ALWAYS the same regardless of the order of the vehicles
+ * where proc was called on!
+ * When you fail to do this properly you create an almost untraceable DESYNC!
+ * @note The return value of proc will be ignored.
+ * @note Use this when you have the intention that all vehicles
+ * should be iterated over.
+ * @param tile The location on the map
+ * @param data Arbitrary data passed to proc
+ * @param proc The proc that determines whether a vehicle will be "found".
+ */
+void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
+{
+ VehicleFromPos(tile, data, proc, false);
+}
+
+/**
+ * Checks whether a vehicle in on a specific location. It will call proc for
+ * vehicles until it returns non-NULL.
+ * @note Use FindVehicleOnPos when you have the intention that all vehicles
+ * should be iterated over.
+ * @param tile The location on the map
+ * @param data Arbitrary data passed to proc
+ * @param proc The proc that determines whether a vehicle will be "found".
+ * @return True if proc returned non-NULL.
+ */
+bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
+{
+ return VehicleFromPos(tile, data, proc, true) != NULL;
+}
+
+
static void UpdateNewVehiclePosHash(Vehicle *v, bool remove)
{
Vehicle **old_hash = v->old_new_hash;
diff --git a/src/vehicle_func.h b/src/vehicle_func.h
index ce0c7407f..754004d59 100644
--- a/src/vehicle_func.h
+++ b/src/vehicle_func.h
@@ -28,10 +28,11 @@ const Vehicle *GetLastVehicleInChain(const Vehicle *v);
uint CountVehiclesInChain(const Vehicle *v);
bool IsEngineCountable(const Vehicle *v);
void DeleteVehicleChain(Vehicle *v);
-Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc);
-Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc);
+void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc);
+void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc);
+bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc);
+bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc);
void CallVehicleTicks();
-Vehicle *FindVehicleOnTileZ(TileIndex tile, byte z);
uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *color);
void InitializeTrains();
@@ -50,8 +51,7 @@ SpriteID GetRotorImage(const Vehicle *v);
uint32 VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y);
StringID VehicleInTheWayErrMsg(const Vehicle* v);
-Vehicle *FindVehicleBetween(TileIndex from, TileIndex to, byte z, bool without_crashed = false);
-Vehicle *GetVehicleTunnelBridge(TileIndex tile, TileIndex endtile);
+bool HasVehicleOnTunnelBridge(TileIndex tile, TileIndex endtile);
void DecreaseVehicleValue(Vehicle *v);
void CheckVehicleBreakdown(Vehicle *v);
diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp
index e82e8cbba..95ba515bf 100644
--- a/src/water_cmd.cpp
+++ b/src/water_cmd.cpp
@@ -37,6 +37,7 @@
#include "tree_map.h"
#include "station_base.h"
#include "airport.h"
+#include "aircraft.h"
#include "newgrf_cargo.h"
#include "effectvehicle_func.h"
#include "oldpool_func.h"
@@ -801,28 +802,47 @@ static void AnimateTile_Water(TileIndex tile)
/* not used */
}
+static void FloodVehicle(Vehicle *v);
+
+/**
+ * Flood a vehicle if we are allowed to flood it, i.e. when it is on the ground.
+ * @param v The vehicle to test for flooding.
+ * @param data The z of level to flood.
+ * @return NULL as we always want to remove everything.
+ */
+static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
+{
+ byte z = *(byte*)data;
+
+ if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
+ if (v->z_pos > z || (v->vehstatus & VS_CRASHED) != 0) return NULL;
+
+ FloodVehicle(v);
+ return NULL;
+}
/**
* Finds a vehicle to flood.
* It does not find vehicles that are already crashed on bridges, i.e. flooded.
* @param tile the tile where to find a vehicle to flood
- * @return a vehicle too flood or NULL when there is no vehicle too flood.
*/
-static Vehicle *FindFloodableVehicleOnTile(TileIndex tile)
+static void FloodVehicles(TileIndex tile)
{
+ byte z = 0;
+
if (IsTileType(tile, MP_STATION) && IsAirport(tile)) {
const Station *st = GetStationByTile(tile);
const AirportFTAClass *airport = st->Airport();
+ z = 1 + airport->delta_z;
for (uint x = 0; x < airport->size_x; x++) {
for (uint y = 0; y < airport->size_y; y++) {
tile = TILE_ADDXY(st->airport_tile, x, y);
- Vehicle *v = FindVehicleOnTileZ(tile, 1 + airport->delta_z);
- if (v != NULL && (v->vehstatus & VS_CRASHED) == 0) return v;
+ FindVehicleOnPos(tile, &z, &FloodVehicleProc);
}
}
/* No vehicle could be flooded on this airport anymore */
- return NULL;
+ return;
}
/* if non-uniform stations are disabled, flood some train in this train station (if there is any) */
@@ -831,31 +851,23 @@ static Vehicle *FindFloodableVehicleOnTile(TileIndex tile)
BEGIN_TILE_LOOP(t, st->trainst_w, st->trainst_h, st->train_tile)
if (st->TileBelongsToRailStation(t)) {
- Vehicle *v = FindVehicleOnTileZ(t, 0);
- if (v != NULL && (v->vehstatus & VS_CRASHED) == 0) return v;
+ FindVehicleOnPos(tile, &z, &FloodVehicleProc);
}
END_TILE_LOOP(t, st->trainst_w, st->trainst_h, st->train_tile)
- return NULL;
+ return;
}
- if (!IsBridgeTile(tile)) return FindVehicleOnTileZ(tile, 0);
+ if (!IsBridgeTile(tile)) {
+ FindVehicleOnPos(tile, &z, &FloodVehicleProc);
+ return;
+ }
TileIndex end = GetOtherBridgeEnd(tile);
- byte z = GetBridgeHeight(tile);
- Vehicle *v;
-
- /* check the start tile first since as this is closest to the water */
- v = FindVehicleOnTileZ(tile, z);
- if (v != NULL && (v->vehstatus & VS_CRASHED) == 0) return v;
+ z = GetBridgeHeight(tile);
- /* check a vehicle in between both bridge heads */
- v = FindVehicleBetween(tile, end, z, true);
- if (v != NULL) return v;
-
- /* check the end tile last to give fleeing vehicles a chance to escape */
- v = FindVehicleOnTileZ(end, z);
- return (v != NULL && (v->vehstatus & VS_CRASHED) == 0) ? v : NULL;
+ FindVehicleOnPos(tile, &z, &FloodVehicleProc);
+ FindVehicleOnPos(end, &z, &FloodVehicleProc);
}
static void FloodVehicle(Vehicle *v)
@@ -989,12 +1001,8 @@ static void DoFloodTile(TileIndex target)
switch (GetTileType(target)) {
case MP_RAILWAY: {
if (!IsPlainRailTile(target)) break;
-
+ FloodVehicles(target);
flooded = FloodHalftile(target);
-
- Vehicle *v = FindFloodableVehicleOnTile(target);
- if (v != NULL) FloodVehicle(v);
-
break;
}
@@ -1019,8 +1027,7 @@ static void DoFloodTile(TileIndex target)
}
} else {
/* Flood vehicles */
- Vehicle *v = FindFloodableVehicleOnTile(target);
- if (v != NULL) FloodVehicle(v);
+ FloodVehicles(target);
/* flood flat tile */
if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {