(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.
authorrubidium
Sun, 07 Sep 2008 11:23:10 +0000
changeset 10083 eee4e42aa15b
parent 10082 44931aeaa000
child 10084 a544278a1b43
(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.
src/pbs.cpp
src/pbs.h
src/rail_cmd.cpp
src/road_cmd.cpp
src/roadveh_cmd.cpp
src/signal.cpp
src/station_cmd.cpp
src/train_cmd.cpp
src/tunnelbridge_cmd.cpp
src/vehicle.cpp
src/vehicle_func.h
src/water_cmd.cpp
--- a/src/pbs.cpp	Sun Sep 07 08:51:26 2008 +0000
+++ b/src/pbs.cpp	Sun Sep 07 11:23:10 2008 +0000
@@ -206,12 +206,29 @@
 	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.trackdir))) return v;
+	if (v->type == VEH_TRAIN && !(v->vehstatus & VS_CRASHED) && HasBit((TrackBits)v->u.rail.track, TrackdirToTrack(info->res.trackdir))) {
+		v = v->First();
+
+		/* 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 @@
  * @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 @@
 
 	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 @@
 	 * 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;
 		}
 	}
 
--- a/src/pbs.h	Sun Sep 07 08:51:26 2008 +0000
+++ b/src/pbs.h	Sun Sep 07 11:23:10 2008 +0000
@@ -27,7 +27,7 @@
 	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);
 
--- a/src/rail_cmd.cpp	Sun Sep 07 08:51:26 2008 +0000
+++ b/src/rail_cmd.cpp	Sun Sep 07 11:23:10 2008 +0000
@@ -130,7 +130,7 @@
 {
 	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 @@
 					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 @@
 
 					/* 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 @@
 						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);
--- a/src/road_cmd.cpp	Sun Sep 07 08:51:26 2008 +0000
+++ b/src/road_cmd.cpp	Sun Sep 07 11:23:10 2008 +0000
@@ -223,7 +223,7 @@
 
 		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 @@
 			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: {
--- a/src/roadveh_cmd.cpp	Sun Sep 07 08:51:26 2008 +0000
+++ b/src/roadveh_cmd.cpp	Sun Sep 07 11:23:10 2008 +0000
@@ -646,7 +646,7 @@
 
 		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 @@
 struct RoadVehFindData {
 	int x;
 	int y;
-	const Vehicle* veh;
+	const Vehicle *veh;
+	Vehicle *best;
+	uint best_diff;
 	Direction dir;
 };
 
@@ -734,28 +736,34 @@
 	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 @@
 	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 @@
 	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)
--- a/src/signal.cpp	Sun Sep 07 08:51:26 2008 +0000
+++ b/src/signal.cpp	Sun Sep 07 11:23:10 2008 +0000
@@ -285,13 +285,13 @@
 
 				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 @@
 
 				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 @@
 
 				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 @@
 				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 @@
 				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 @@
 				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;
--- a/src/station_cmd.cpp	Sun Sep 07 08:51:26 2008 +0000
+++ b/src/station_cmd.cpp	Sun Sep 07 11:23:10 2008 +0000
@@ -1506,7 +1506,7 @@
 	/* 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;
 	}
--- a/src/train_cmd.cpp	Sun Sep 07 08:51:26 2008 +0000
+++ b/src/train_cmd.cpp	Sun Sep 07 11:23:10 2008 +0000
@@ -1694,24 +1694,22 @@
 /**
  * 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 @@
 	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 @@
 		}
 	}
 
-	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 @@
 	 * 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 @@
 
 	/* 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 @@
 								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 @@
 }
 
 /** 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 @@
 
 		/* 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);
--- a/src/tunnelbridge_cmd.cpp	Sun Sep 07 08:51:26 2008 +0000
+++ b/src/tunnelbridge_cmd.cpp	Sun Sep 07 11:23:10 2008 +0000
@@ -605,7 +605,7 @@
 
 	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 @@
 
 	endtile = GetOtherBridgeEnd(tile);
 
-	if (GetVehicleTunnelBridge(tile, endtile) != NULL) return CMD_ERROR;
+	if (HasVehicleOnTunnelBridge(tile, endtile)) return CMD_ERROR;
 
 	direction = GetTunnelBridgeDirection(tile);
 	delta = TileOffsByDiagDir(direction);
--- a/src/vehicle.cpp	Sun Sep 07 08:51:26 2008 +0000
+++ b/src/vehicle.cpp	Sun Sep 07 11:23:10 2008 +0000
@@ -168,42 +168,12 @@
 	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 @@
  * 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 @@
 
 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 @@
 }
 
 
-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 @@
 	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);
 }
 
-
-Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
+/**
+ * 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;
+}
+
+/**
+ * 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 @@
 		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;
--- a/src/vehicle_func.h	Sun Sep 07 08:51:26 2008 +0000
+++ b/src/vehicle_func.h	Sun Sep 07 11:23:10 2008 +0000
@@ -28,10 +28,11 @@
 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 @@
 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);
--- a/src/water_cmd.cpp	Sun Sep 07 08:51:26 2008 +0000
+++ b/src/water_cmd.cpp	Sun Sep 07 11:23:10 2008 +0000
@@ -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 @@
 	/* 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 @@
 
 		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 @@
 		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 @@
 		}
 	} 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))) {