Changeset - r10083:2e8288935c09
[Not reviewed]
master
0 12 0
rubidium - 16 years ago 2008-09-07 11:23:10
rubidium@openttd.org
(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.
12 files changed with 247 insertions and 156 deletions:
0 comments (0 inline, 0 general)
src/pbs.cpp
Show inline comments
 
@@ -203,42 +203,60 @@ static PBSTileInfo FollowReservation(Own
 
		if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) break;
 
	}
 

	
 
	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;
 
}
 

	
 
/**
 
 * Follow a train reservation to the last tile.
 
 *
 
 * @param v the vehicle
 
 * @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);
 

	
 
	TileIndex tile = v->tile;
 
	Trackdir  trackdir = GetVehicleTrackdir(v);
 

	
 
	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;
 
}
 

	
 
/**
 
 * Find the train which has reserved a specific path.
 
 *
 
 * @param tile A tile on the path.
 
@@ -253,30 +271,31 @@ Vehicle *GetTrainForReservation(TileInde
 
	RailTypes rts = GetRailTypeInfo(GetTileRailType(tile))->compatible_railtypes;
 

	
 
	/* Follow the path from tile to both ends, one of the end tiles should
 
	 * 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;
 
		}
 
	}
 

	
 
	return NULL;
 
}
 

	
src/pbs.h
Show inline comments
 
@@ -24,13 +24,13 @@ struct PBSTileInfo {
 
	bool      okay;      ///< True if tile is a safe waiting position, false otherwise.
 

	
 
	PBSTileInfo() : tile(INVALID_TILE), trackdir(INVALID_TRACKDIR), okay(false) {}
 
	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);
 

	
 
Vehicle *GetTrainForReservation(TileIndex tile, Track track);
 

	
 
/**
src/rail_cmd.cpp
Show inline comments
 
@@ -127,13 +127,13 @@ Vehicle *EnsureNoTrainOnTrackProc(Vehicl
 
 * @param track The track.
 
 */
 
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)
 
{
 
	TrackBits current; // The current track layout
 
	TrackBits future;  // The track layout we want to build
 
@@ -1331,13 +1331,13 @@ CommandCost CmdConvertRail(TileIndex til
 
						}
 
					}
 

	
 
					SetRailType(tile, totype);
 
					MarkTileDirtyByTile(tile);
 
					/* update power of train engines on this tile */
 
					VehicleFromPos(tile, NULL, &UpdateTrainPowerProc);
 
					FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
 
				}
 
			}
 

	
 
			switch (tt) {
 
				case MP_RAILWAY:
 
					switch (GetRailTileType(tile)) {
 
@@ -1381,13 +1381,13 @@ CommandCost CmdConvertRail(TileIndex til
 
					 * it would cause assert because of different test and exec runs */
 
					if (endtile < tile && TileX(endtile) >= sx && TileX(endtile) <= ex &&
 
							TileY(endtile) >= sy && TileY(endtile) <= ey) continue;
 

	
 
					/* 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));
 
						if (GetTunnelBridgeReservation(tile)) {
 
							Vehicle *v = GetTrainForReservation(tile, track);
 
							if (v != NULL) {
 
@@ -1395,14 +1395,14 @@ CommandCost CmdConvertRail(TileIndex til
 
								*vehicles_affected.Append() = v;
 
							}
 
						}
 
						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);
 

	
 
						MarkTileDirtyByTile(tile);
 
						MarkTileDirtyByTile(endtile);
src/road_cmd.cpp
Show inline comments
 
@@ -220,13 +220,13 @@ static CommandCost RemoveRoad(TileIndex 
 
			if (rt == ROADTYPE_ROAD) town_road_under_stop = GetStopBuiltOnTownRoad(tile);
 
			if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
 
			break;
 

	
 
		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:
 
			return CMD_ERROR;
 
	}
 

	
 
@@ -586,13 +586,13 @@ CommandCost CmdBuildRoad(TileIndex tile,
 

	
 
		case MP_TUNNELBRIDGE:
 
			if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) return CMD_ERROR;
 
			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: {
 
do_clear:;
 
			CommandCost ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
			if (CmdFailed(ret)) return ret;
src/roadveh_cmd.cpp
Show inline comments
 
@@ -643,13 +643,13 @@ static void RoadVehCheckTrainCrash(Vehic
 
		if (u->u.road.state == RVSB_WORMHOLE) continue;
 

	
 
		TileIndex tile = u->tile;
 

	
 
		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;
 
		}
 
	}
 
}
 

	
 
@@ -722,70 +722,80 @@ static void StartRoadVehSound(const Vehi
 
	}
 
}
 

	
 
struct RoadVehFindData {
 
	int x;
 
	int y;
 
	const Vehicle* veh;
 
	const Vehicle *veh;
 
	Vehicle *best;
 
	uint best_diff;
 
	Direction dir;
 
};
 

	
 
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;
 

	
 
	rvf.x = x;
 
	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)
 
{
 
	if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
 
		/* Check if station was ever visited before */
 
@@ -900,13 +910,13 @@ static bool CheckRoadBlockedForOvertakin
 
	TrackBits trackbits = TrackdirBitsToTrackBits(trackdirbits);
 

	
 
	/* Track does not continue along overtaking direction || track has junction || levelcrossing is barred */
 
	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)
 
{
 
	OvertakeData od;
 

	
src/signal.cpp
Show inline comments
 
@@ -282,42 +282,42 @@ static SigFlags ExploreSegment(Owner own
 
		switch (GetTileType(tile)) {
 
			case MP_RAILWAY: {
 
				if (GetTileOwner(tile) != owner) continue; // do not propagate signals on others' tiles (remove for tracksharing)
 

	
 
				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;
 
					}
 
				}
 

	
 
				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;
 
				}
 

	
 
				TrackBits tracks = GetTrackBits(tile); // trackbits of tile
 
				TrackBits tracks_masked = (TrackBits)(tracks & _enterdir_to_trackbits[enterdir]); // only incidating trackbits
 

	
 
				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
 
					Track track = TrackBitsToTrack(tracks_masked); // mask TRACK_BIT_X and Y too
 
					if (HasSignalOnTrack(tile, track)) { // now check whole track, not trackdir
 
						SignalType sig = GetSignalType(tile, track);
 
@@ -363,38 +363,38 @@ static SigFlags ExploreSegment(Owner own
 
			case MP_STATION:
 
				if (!IsRailwayStation(tile)) continue;
 
				if (GetTileOwner(tile) != owner) continue;
 
				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;
 

	
 
			case MP_ROAD:
 
				if (!IsLevelCrossing(tile)) continue;
 
				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;
 

	
 
			case MP_TUNNELBRIDGE: {
 
				if (GetTileOwner(tile) != owner) continue;
 
				if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
 
				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;
 
				}
 
				}
 
				break;
src/station_cmd.cpp
Show inline comments
 
@@ -1503,13 +1503,13 @@ static CommandCost RemoveRoadStop(Statio
 

	
 
	assert(cur_stop != NULL);
 

	
 
	/* 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;
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		if (*primary_stop == cur_stop) {
src/train_cmd.cpp
Show inline comments
 
@@ -1691,30 +1691,28 @@ static Vehicle *TrainApproachingCrossing
 
}
 

	
 

	
 
/**
 
 * 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);
 
}
 

	
 

	
 
/**
 
 * Sets correct crossing state
 
 * @param tile tile to update
 
@@ -1723,13 +1721,13 @@ static Vehicle *TrainApproachingCrossing
 
 */
 
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) {
 
			SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
 
		}
 
		SetCrossingBarred(tile, new_state);
 
@@ -3025,26 +3023,26 @@ bool TryPathReserve(Vehicle *v, bool mar
 
			/* Signal already reserved, is not ours. */
 
			if (mark_as_stuck) MarkTrainAsStuck(v);
 
			return false;
 
		}
 
	}
 

	
 
	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)) {
 
		/* Can't be stuck then. */
 
		if (HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
		ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK);
 
		return true;
 
	}
 
	/* The path we are driving on is alread blocked by some other train.
 
	 * 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;
 
	}
 

	
 
	/* If we are in a depot, tentativly reserve the depot. */
 
	if (v->u.rail.track & TRACK_BIT_DEPOT) {
 
@@ -3515,16 +3513,16 @@ static void CheckTrainCollision(Vehicle 
 
	TrainCollideChecker tcc;
 
	tcc.v = v;
 
	tcc.num = 0;
 

	
 
	/* 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 */
 
	if (tcc.num == 0) return;
 

	
 
	SetDParam(0, tcc.num);
 
@@ -3649,13 +3647,13 @@ static void TrainController(Vehicle *v, 
 
								DiagDirection exitdir = TrackdirToExitdir(i);
 
								TileIndex o_tile = TileAddByDiagDir(gp.new_tile, exitdir);
 

	
 
								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;
 
							}
 
						}
 

	
 
						/* If we would reverse but are currently in a PBS block and
 
						 * reversing of stuck trains is disabled, don't reverse. */
 
						if (_settings_game.pf.wait_for_pbs_path == 255 && UpdateSignalsOnSegment(v->tile, enterdir, v->owner) == SIGSEG_PBS) {
 
@@ -3816,15 +3814,15 @@ reverse_train_direction:
 
	v->cur_speed = 0;
 
	v->subspeed = 0;
 
	ReverseTrainDirection(v);
 
}
 

	
 
/** 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)
 
{
 
	TrackBits *trackbits = (TrackBits *)data;
 

	
 
	if (v->type == VEH_TRAIN && (v->vehstatus & VS_CRASHED) != 0) {
 
@@ -3891,13 +3889,13 @@ static void DeleteLastWagon(Vehicle *v)
 
	Track track = TrackBitsToTrack(trackbits);
 
	if (HasReservedTracks(tile, trackbits)) {
 
		UnreserveRailTrack(tile, track);
 

	
 
		/* 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);
 
		for (Track t = TRACK_BEGIN; t < TRACK_END; t++) {
 
			if (HasBit(remaining_trackbits, t)) {
 
				TryReserveRailTrack(tile, t);
src/tunnelbridge_cmd.cpp
Show inline comments
 
@@ -602,13 +602,13 @@ static CommandCost DoClearTunnel(TileInd
 
	TileIndex endtile;
 

	
 
	if (!CheckAllowRemoveTunnelBridge(tile)) return CMD_ERROR;
 

	
 
	endtile = GetOtherTunnelEnd(tile);
 

	
 
	if (GetVehicleTunnelBridge(tile, endtile) != NULL) return CMD_ERROR;
 
	if (HasVehicleOnTunnelBridge(tile, endtile)) return CMD_ERROR;
 

	
 
	_build_tunnel_endtile = endtile;
 

	
 
	if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
 
		t = ClosestTownFromTile(tile, (uint)-1); // town penalty rating
 

	
 
@@ -667,13 +667,13 @@ static CommandCost DoClearBridge(TileInd
 
	Town *t = NULL;
 

	
 
	if (!CheckAllowRemoveTunnelBridge(tile)) return CMD_ERROR;
 

	
 
	endtile = GetOtherBridgeEnd(tile);
 

	
 
	if (GetVehicleTunnelBridge(tile, endtile) != NULL) return CMD_ERROR;
 
	if (HasVehicleOnTunnelBridge(tile, endtile)) return CMD_ERROR;
 

	
 
	direction = GetTunnelBridgeDirection(tile);
 
	delta = TileOffsByDiagDir(direction);
 

	
 
	if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
 
		t = ClosestTownFromTile(tile, (uint)-1); // town penalty rating
src/vehicle.cpp
Show inline comments
 
@@ -165,48 +165,18 @@ static Vehicle *EnsureNoVehicleProcZ(Veh
 
	if (v->z_pos > z) return NULL;
 

	
 
	_error_message = VehicleInTheWayErrMsg(v);
 
	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)
 
{
 
	if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return NULL;
 

	
 
	_error_message = VehicleInTheWayErrMsg(v);
 
@@ -214,20 +184,18 @@ static Vehicle *GetVehicleTunnelBridgePr
 
}
 

	
 
/**
 
 * 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);
 
}
 

	
 

	
 
static void UpdateVehiclePosHash(Vehicle *v, int x, int y);
 

	
 
void VehiclePositionChanged(Vehicle *v)
 
@@ -381,60 +349,149 @@ const int TOTAL_HASH_MASK = TOTAL_HASH_S
 
/* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc.
 
 * Profiling results show that 0 is fastest. */
 
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;
 
		}
 
		if (y == yu) break;
 
	}
 

	
 
	return NULL;
 
}
 

	
 

	
 
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;
 

	
 
	/* Hash area to scan is from xl,yl to xu,yu */
 
	int xl = GB((x - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
 
	int xu = GB((x + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
 
	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);
 
}
 

	
 

	
 
Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
 
/**
 
 * 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;
 

	
 
	Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
 
	for (; v != NULL; v = v->next_new_hash) {
 
		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;
 
	Vehicle **new_hash;
 

	
 
	if (remove) {
src/vehicle_func.h
Show inline comments
 
@@ -25,16 +25,17 @@ void VehicleServiceInDepot(Vehicle *v);
 
void VehiclePositionChanged(Vehicle *v);
 
Vehicle *GetLastVehicleInChain(Vehicle *v);
 
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();
 
byte VehicleRandomBits();
 
void ResetVehiclePosHash();
 
void ResetVehicleColorMap();
 
@@ -47,14 +48,13 @@ void ViewportAddVehicles(DrawPixelInfo *
 

	
 
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);
 
void AgeVehicle(Vehicle *v);
 
void VehicleEnteredDepotThisTick(Vehicle *v);
 

	
src/water_cmd.cpp
Show inline comments
 
@@ -34,12 +34,13 @@
 
#include "player_func.h"
 
#include "settings_type.h"
 
#include "clear_map.h"
 
#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"
 
#include "tunnelbridge_map.h"
 

	
 
#include "table/sprites.h"
 
@@ -798,67 +799,78 @@ static void GetTileDesc_Water(TileIndex 
 

	
 
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) */
 
	if (!_settings_game.station.nonuniform_stations && IsTileType(tile, MP_STATION) && GetStationType(tile) == STATION_RAIL) {
 
		const Station *st = GetStationByTile(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)
 
{
 
	if (!(v->vehstatus & VS_CRASHED)) {
 
		uint16 pass = 0;
 
@@ -986,18 +998,14 @@ static void DoFloodTile(TileIndex target
 
	Slope tileh = GetTileSlope(target, NULL);
 
	if (tileh != SLOPE_FLAT) {
 
		/* make coast.. */
 
		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;
 
			}
 

	
 
			case MP_TREES:
 
				if (!IsSlopeWithOneCornerRaised(tileh)) {
 
					SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
 
@@ -1016,14 +1024,13 @@ static void DoFloodTile(TileIndex target
 

	
 
			default:
 
				break;
 
		}
 
	} 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))) {
 
			MakeWater(target);
 
			MarkTileDirtyByTile(target);
 
			flooded = true;
0 comments (0 inline, 0 general)