mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-02-03 04:43:12 +00:00
(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.
This commit is contained in:
parent
f4ee4fd5ae
commit
9474db5cb6
57
src/pbs.cpp
57
src/pbs.cpp
@ -206,12 +206,29 @@ static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Tra
|
|||||||
return PBSTileInfo(tile, trackdir, false);
|
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)
|
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;
|
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
|
* @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.
|
* @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);
|
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);
|
if (IsRailDepotTile(tile) && !GetRailDepotReservation(tile)) return PBSTileInfo(tile, trackdir, false);
|
||||||
|
|
||||||
PBSTileInfo res = FollowReservation(v->owner, GetRailTypeInfo(v->u.rail.railtype)->compatible_railtypes, tile, trackdir);
|
FindTrainOnTrackInfo ftoti;
|
||||||
res.okay = IsSafeWaitingPosition(v, res.tile, res.trackdir, true, _settings_game.pf.forbid_90_deg);
|
ftoti.res = FollowReservation(v->owner, GetRailTypeInfo(v->u.rail.railtype)->compatible_railtypes, tile, trackdir);
|
||||||
if (train_on_res != NULL) *train_on_res = VehicleFromPos(res.tile, &res, FindTrainOnTrackEnum);
|
ftoti.res.okay = IsSafeWaitingPosition(v, ftoti.res.tile, ftoti.res.trackdir, true, _settings_game.pf.forbid_90_deg);
|
||||||
return res;
|
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
|
* 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. */
|
* here, as one of the two search directions will be the "wrong" way. */
|
||||||
for (int i = 0; i < 2; ++i, trackdir = ReverseTrackdir(trackdir)) {
|
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);
|
FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
|
||||||
if (v != NULL) return v->First();
|
if (ftoti.best != NULL) return ftoti.best;
|
||||||
|
|
||||||
/* Special case for stations: check the whole platform for a vehicle. */
|
/* Special case for stations: check the whole platform for a vehicle. */
|
||||||
if (IsRailwayStationTile(dest.tile)) {
|
if (IsRailwayStationTile(ftoti.res.tile)) {
|
||||||
TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(dest.trackdir)));
|
TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir)));
|
||||||
for (TileIndex st_tile = dest.tile + diff; IsCompatibleTrainStationTile(st_tile, dest.tile); st_tile += diff) {
|
for (TileIndex st_tile = ftoti.res.tile + diff; IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) {
|
||||||
v = VehicleFromPos(st_tile, &dest, FindTrainOnTrackEnum);
|
FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum);
|
||||||
if (v != NULL) return v->First();
|
if (ftoti.best != NULL) return ftoti.best;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Special case for bridges/tunnels: check the other end as well. */
|
/* Special case for bridges/tunnels: check the other end as well. */
|
||||||
if (IsTileType(dest.tile, MP_TUNNELBRIDGE)) {
|
if (IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) {
|
||||||
v = VehicleFromPos(GetOtherTunnelBridgeEnd(dest.tile), &dest, FindTrainOnTrackEnum);
|
FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum);
|
||||||
if (v != NULL) return v->First();
|
if (ftoti.best != NULL) return ftoti.best;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ struct PBSTileInfo {
|
|||||||
PBSTileInfo(TileIndex _t, Trackdir _td, bool _okay) : tile(_t), trackdir(_td), okay(_okay) {}
|
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 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);
|
bool IsWaitingPositionFree(const Vehicle *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg = false);
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ static bool EnsureNoTrainOnTrack(TileIndex tile, Track track)
|
|||||||
{
|
{
|
||||||
TrackBits rail_bits = TrackToTrackBits(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)
|
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);
|
SetRailType(tile, totype);
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
/* update power of train engines on this 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 */
|
/* When not coverting rail <-> el. rail, any vehicle cannot be in tunnel/bridge */
|
||||||
if (!IsCompatibleRail(GetRailType(tile), totype) &&
|
if (!IsCompatibleRail(GetRailType(tile), totype) &&
|
||||||
GetVehicleTunnelBridge(tile, endtile) != NULL) continue;
|
!HasVehicleOnTunnelBridge(tile, endtile)) continue;
|
||||||
|
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
|
Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
|
||||||
@ -1398,8 +1398,8 @@ CommandCost CmdConvertRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
|||||||
SetRailType(tile, totype);
|
SetRailType(tile, totype);
|
||||||
SetRailType(endtile, totype);
|
SetRailType(endtile, totype);
|
||||||
|
|
||||||
VehicleFromPos(tile, NULL, &UpdateTrainPowerProc);
|
FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
|
||||||
VehicleFromPos(endtile, NULL, &UpdateTrainPowerProc);
|
FindVehicleOnPos(endtile, NULL, &UpdateTrainPowerProc);
|
||||||
|
|
||||||
YapfNotifyTrackLayoutChange(tile, track);
|
YapfNotifyTrackLayoutChange(tile, track);
|
||||||
YapfNotifyTrackLayoutChange(endtile, track);
|
YapfNotifyTrackLayoutChange(endtile, track);
|
||||||
|
@ -223,7 +223,7 @@ static CommandCost RemoveRoad(TileIndex tile, uint32 flags, RoadBits pieces, Roa
|
|||||||
|
|
||||||
case MP_TUNNELBRIDGE:
|
case MP_TUNNELBRIDGE:
|
||||||
if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) return CMD_ERROR;
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
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 (MirrorRoadBits(DiagDirToRoadBits(GetTunnelBridgeDirection(tile))) != pieces) return CMD_ERROR;
|
||||||
if (HasTileRoadType(tile, rt)) return_cmd_error(STR_1007_ALREADY_BUILT);
|
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 */
|
/* 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;
|
break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
|
@ -646,7 +646,7 @@ static void RoadVehCheckTrainCrash(Vehicle *v)
|
|||||||
|
|
||||||
if (!IsLevelCrossingTile(tile)) continue;
|
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);
|
RoadVehCrash(v);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -726,6 +726,8 @@ struct RoadVehFindData {
|
|||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
const Vehicle *veh;
|
const Vehicle *veh;
|
||||||
|
Vehicle *best;
|
||||||
|
uint best_diff;
|
||||||
Direction dir;
|
Direction dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -734,13 +736,12 @@ static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data)
|
|||||||
static const int8 dist_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 };
|
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 };
|
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 x_diff = v->x_pos - rvf->x;
|
||||||
short y_diff = v->y_pos - rvf->y;
|
short y_diff = v->y_pos - rvf->y;
|
||||||
|
|
||||||
return
|
if (v->type == VEH_ROAD &&
|
||||||
v->type == VEH_ROAD &&
|
|
||||||
!v->IsInDepot() &&
|
!v->IsInDepot() &&
|
||||||
abs(v->z_pos - rvf->veh->z_pos) < 6 &&
|
abs(v->z_pos - rvf->veh->z_pos) < 6 &&
|
||||||
v->direction == rvf->dir &&
|
v->direction == rvf->dir &&
|
||||||
@ -748,14 +749,21 @@ static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data)
|
|||||||
(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_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)) &&
|
||||||
(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;
|
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;
|
RoadVehFindData rvf;
|
||||||
Vehicle *u;
|
|
||||||
Vehicle *front = v->First();
|
Vehicle *front = v->First();
|
||||||
|
|
||||||
if (front->u.road.reverse_ctr != 0) return NULL;
|
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.y = y;
|
||||||
rvf.dir = dir;
|
rvf.dir = dir;
|
||||||
rvf.veh = v;
|
rvf.veh = v;
|
||||||
|
rvf.best_diff = UINT_MAX;
|
||||||
|
|
||||||
if (front->u.road.state == RVSB_WORMHOLE) {
|
if (front->u.road.state == RVSB_WORMHOLE) {
|
||||||
u = VehicleFromPos(v->tile, &rvf, EnumCheckRoadVehClose);
|
FindVehicleOnPos(v->tile, &rvf, EnumCheckRoadVehClose);
|
||||||
if (u == NULL) u = (Vehicle*)VehicleFromPos(GetOtherTunnelBridgeEnd(v->tile), &rvf, EnumCheckRoadVehClose);
|
FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &rvf, EnumCheckRoadVehClose);
|
||||||
} else {
|
} else {
|
||||||
u = VehicleFromPosXY(x, y, &rvf, EnumCheckRoadVehClose);
|
FindVehicleOnPosXY(x, y, &rvf, EnumCheckRoadVehClose);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This code protects a roadvehicle from being blocked for ever
|
/* This code protects a roadvehicle from being blocked for ever
|
||||||
* If more than 1480 / 74 days a road vehicle is blocked, it will
|
* If more than 1480 / 74 days a road vehicle is blocked, it will
|
||||||
* drive just through it. The ultimate backup-code of TTD.
|
* drive just through it. The ultimate backup-code of TTD.
|
||||||
* It can be disabled. */
|
* It can be disabled. */
|
||||||
if (u == NULL) {
|
if (rvf.best_diff == UINT_MAX) {
|
||||||
front->u.road.blocked_ctr = 0;
|
front->u.road.blocked_ctr = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++front->u.road.blocked_ctr > 1480) return NULL;
|
if (++front->u.road.blocked_ctr > 1480) return NULL;
|
||||||
|
|
||||||
return u;
|
return rvf.best;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RoadVehArrivesAt(const Vehicle* v, Station* st)
|
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;
|
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 */
|
/* 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)
|
static void RoadVehCheckOvertake(Vehicle *v, Vehicle *u)
|
||||||
|
@ -285,13 +285,13 @@ static SigFlags ExploreSegment(Owner owner)
|
|||||||
|
|
||||||
if (IsRailDepot(tile)) {
|
if (IsRailDepot(tile)) {
|
||||||
if (enterdir == INVALID_DIAGDIR) { // from 'inside' - train just entered or left the depot
|
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);
|
exitdir = GetRailDepotDirection(tile);
|
||||||
tile += TileOffsByDiagDir(exitdir);
|
tile += TileOffsByDiagDir(exitdir);
|
||||||
enterdir = ReverseDiagDir(exitdir);
|
enterdir = ReverseDiagDir(exitdir);
|
||||||
break;
|
break;
|
||||||
} else if (enterdir == GetRailDepotDirection(tile)) { // entered a depot
|
} 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;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
@ -300,7 +300,7 @@ static SigFlags ExploreSegment(Owner owner)
|
|||||||
|
|
||||||
if (GetRailTileType(tile) == RAIL_TILE_WAYPOINT) {
|
if (GetRailTileType(tile) == RAIL_TILE_WAYPOINT) {
|
||||||
if (GetWaypointAxis(tile) != DiagDirToAxis(enterdir)) continue;
|
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);
|
tile += TileOffsByDiagDir(exitdir);
|
||||||
/* enterdir and exitdir stay the same */
|
/* enterdir and exitdir stay the same */
|
||||||
break;
|
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
|
if (tracks == TRACK_BIT_HORZ || tracks == TRACK_BIT_VERT) { // there is exactly one incidating track, no need to check
|
||||||
tracks = tracks_masked;
|
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 {
|
} else {
|
||||||
if (tracks_masked == TRACK_BIT_NONE) continue; // no incidating track
|
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
|
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 (DiagDirToAxis(enterdir) != GetRailStationAxis(tile)) continue; // different axis
|
||||||
if (IsStationTileBlocked(tile)) continue; // 'eye-candy' station tile
|
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);
|
tile += TileOffsByDiagDir(exitdir);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -375,7 +375,7 @@ static SigFlags ExploreSegment(Owner owner)
|
|||||||
if (GetTileOwner(tile) != owner) continue;
|
if (GetTileOwner(tile) != owner) continue;
|
||||||
if (DiagDirToAxis(enterdir) == GetCrossingRoadAxis(tile)) continue; // different axis
|
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);
|
tile += TileOffsByDiagDir(exitdir);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -385,13 +385,13 @@ static SigFlags ExploreSegment(Owner owner)
|
|||||||
DiagDirection dir = GetTunnelBridgeDirection(tile);
|
DiagDirection dir = GetTunnelBridgeDirection(tile);
|
||||||
|
|
||||||
if (enterdir == INVALID_DIAGDIR) { // incoming from the wormhole
|
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;
|
enterdir = dir;
|
||||||
exitdir = ReverseDiagDir(dir);
|
exitdir = ReverseDiagDir(dir);
|
||||||
tile += TileOffsByDiagDir(exitdir); // just skip to next tile
|
tile += TileOffsByDiagDir(exitdir); // just skip to next tile
|
||||||
} else { // NOT incoming from the wormhole!
|
} else { // NOT incoming from the wormhole!
|
||||||
if (ReverseDiagDir(enterdir) != dir) continue;
|
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
|
tile = GetOtherTunnelBridgeEnd(tile); // just skip to exit tile
|
||||||
enterdir = INVALID_DIAGDIR;
|
enterdir = INVALID_DIAGDIR;
|
||||||
exitdir = INVALID_DIAGDIR;
|
exitdir = INVALID_DIAGDIR;
|
||||||
|
@ -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 */
|
/* don't do the check for drive-through road stops when company bankrupts */
|
||||||
if (IsDriveThroughStopTile(tile) && (flags & DC_BANKRUPT)) {
|
if (IsDriveThroughStopTile(tile) && (flags & DC_BANKRUPT)) {
|
||||||
/* remove the 'going through road stop' status from all vehicles on that tile */
|
/* 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 {
|
} else {
|
||||||
if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
|
if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -1694,24 +1694,22 @@ static Vehicle *TrainApproachingCrossingEnum(Vehicle *v, void *data)
|
|||||||
/**
|
/**
|
||||||
* Finds a vehicle approaching rail-road crossing
|
* Finds a vehicle approaching rail-road crossing
|
||||||
* @param tile tile to test
|
* @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
|
* @pre tile is a rail-road crossing
|
||||||
*/
|
*/
|
||||||
static Vehicle *TrainApproachingCrossing(TileIndex tile)
|
static bool TrainApproachingCrossing(TileIndex tile)
|
||||||
{
|
{
|
||||||
assert(IsLevelCrossingTile(tile));
|
assert(IsLevelCrossingTile(tile));
|
||||||
|
|
||||||
DiagDirection dir = AxisToDiagDir(GetCrossingRailAxis(tile));
|
DiagDirection dir = AxisToDiagDir(GetCrossingRailAxis(tile));
|
||||||
TileIndex tile_from = tile + TileOffsByDiagDir(dir);
|
TileIndex tile_from = tile + TileOffsByDiagDir(dir);
|
||||||
|
|
||||||
Vehicle *v = VehicleFromPos(tile_from, &tile, &TrainApproachingCrossingEnum);
|
if (HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum)) return true;
|
||||||
|
|
||||||
if (v != NULL) return v;
|
|
||||||
|
|
||||||
dir = ReverseDiagDir(dir);
|
dir = ReverseDiagDir(dir);
|
||||||
tile_from = tile + TileOffsByDiagDir(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));
|
assert(IsLevelCrossingTile(tile));
|
||||||
|
|
||||||
/* train on crossing || train approaching crossing || reserved */
|
/* 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 != IsCrossingBarred(tile)) {
|
||||||
if (new_state && sound) {
|
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);
|
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 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)) {
|
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
|
* This can only happen when tracks and signals are changed. A crash
|
||||||
* is probably imminent, don't do any further reservation because
|
* is probably imminent, don't do any further reservation because
|
||||||
* it might cause stale reservations. */
|
* 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);
|
if (mark_as_stuck) MarkTrainAsStuck(v);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -3518,10 +3516,10 @@ static void CheckTrainCollision(Vehicle *v)
|
|||||||
|
|
||||||
/* find colliding vehicles */
|
/* find colliding vehicles */
|
||||||
if (v->u.rail.track == TRACK_BIT_WORMHOLE) {
|
if (v->u.rail.track == TRACK_BIT_WORMHOLE) {
|
||||||
VehicleFromPos(v->tile, &tcc, FindTrainCollideEnum);
|
FindVehicleOnPos(v->tile, &tcc, FindTrainCollideEnum);
|
||||||
VehicleFromPos(GetOtherTunnelBridgeEnd(v->tile), &tcc, FindTrainCollideEnum);
|
FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &tcc, FindTrainCollideEnum);
|
||||||
} else {
|
} else {
|
||||||
VehicleFromPosXY(v->x_pos, v->y_pos, &tcc, FindTrainCollideEnum);
|
FindVehicleOnPosXY(v->x_pos, v->y_pos, &tcc, FindTrainCollideEnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* any dead -> no crash */
|
/* any dead -> no crash */
|
||||||
@ -3652,7 +3650,7 @@ static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image)
|
|||||||
exitdir = ReverseDiagDir(exitdir);
|
exitdir = ReverseDiagDir(exitdir);
|
||||||
|
|
||||||
/* check if a train is waiting on the other side */
|
/* 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
|
/** 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
|
* @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)
|
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 */
|
/* If there are still crashed vehicles on the tile, give the track reservation to them */
|
||||||
TrackBits remaining_trackbits = TRACK_BIT_NONE;
|
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 */
|
/* 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);
|
assert(TRACK_BEGIN == TRACK_X && TRACK_Y == TRACK_BEGIN + 1);
|
||||||
|
@ -605,7 +605,7 @@ static CommandCost DoClearTunnel(TileIndex tile, uint32 flags)
|
|||||||
|
|
||||||
endtile = GetOtherTunnelEnd(tile);
|
endtile = GetOtherTunnelEnd(tile);
|
||||||
|
|
||||||
if (GetVehicleTunnelBridge(tile, endtile) != NULL) return CMD_ERROR;
|
if (HasVehicleOnTunnelBridge(tile, endtile)) return CMD_ERROR;
|
||||||
|
|
||||||
_build_tunnel_endtile = endtile;
|
_build_tunnel_endtile = endtile;
|
||||||
|
|
||||||
@ -670,7 +670,7 @@ static CommandCost DoClearBridge(TileIndex tile, uint32 flags)
|
|||||||
|
|
||||||
endtile = GetOtherBridgeEnd(tile);
|
endtile = GetOtherBridgeEnd(tile);
|
||||||
|
|
||||||
if (GetVehicleTunnelBridge(tile, endtile) != NULL) return CMD_ERROR;
|
if (HasVehicleOnTunnelBridge(tile, endtile)) return CMD_ERROR;
|
||||||
|
|
||||||
direction = GetTunnelBridgeDirection(tile);
|
direction = GetTunnelBridgeDirection(tile);
|
||||||
delta = TileOffsByDiagDir(direction);
|
delta = TileOffsByDiagDir(direction);
|
||||||
|
145
src/vehicle.cpp
145
src/vehicle.cpp
@ -168,42 +168,12 @@ static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data)
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vehicle *FindVehicleOnTileZ(TileIndex tile, byte z)
|
|
||||||
{
|
|
||||||
return (Vehicle*)VehicleFromPos(tile, &z, &EnsureNoVehicleProcZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EnsureNoVehicleOnGround(TileIndex tile)
|
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 */
|
/** Procedure called for every vehicle found in tunnel/bridge in the hash map */
|
||||||
static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
|
static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
|
||||||
{
|
{
|
||||||
@ -217,14 +187,12 @@ static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
|
|||||||
* Finds vehicle in tunnel / bridge
|
* Finds vehicle in tunnel / bridge
|
||||||
* @param tile first end
|
* @param tile first end
|
||||||
* @param endtile second 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);
|
return HasVehicleOnPos(tile, NULL, &GetVehicleTunnelBridgeProc) ||
|
||||||
if (v != NULL) return v;
|
HasVehicleOnPos(endtile, NULL, &GetVehicleTunnelBridgeProc);
|
||||||
|
|
||||||
return (Vehicle*)VehicleFromPos(endtile, NULL, &GetVehicleTunnelBridgeProc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -384,14 +352,14 @@ const int HASH_RES = 0;
|
|||||||
|
|
||||||
static Vehicle *_new_vehicle_position_hash[TOTAL_HASH_SIZE];
|
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 y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
|
||||||
for (int x = xl; ; x = (x + 1) & HASH_MASK) {
|
for (int x = xl; ; x = (x + 1) & HASH_MASK) {
|
||||||
Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
|
Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
|
||||||
for (; v != NULL; v = v->next_new_hash) {
|
for (; v != NULL; v = v->next_new_hash) {
|
||||||
Vehicle *a = proc(v, data);
|
Vehicle *a = proc(v, data);
|
||||||
if (a != NULL) return a;
|
if (find_first && a != NULL) return a;
|
||||||
}
|
}
|
||||||
if (x == xu) break;
|
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;
|
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 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;
|
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 x = GB(TileX(tile), HASH_RES, HASH_BITS);
|
||||||
int y = GB(TileY(tile), HASH_RES, HASH_BITS) << 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;
|
if (v->tile != tile) continue;
|
||||||
|
|
||||||
Vehicle *a = proc(v, data);
|
Vehicle *a = proc(v, data);
|
||||||
if (a != NULL) return a;
|
if (find_first && a != NULL) return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
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)
|
static void UpdateNewVehiclePosHash(Vehicle *v, bool remove)
|
||||||
{
|
{
|
||||||
Vehicle **old_hash = v->old_new_hash;
|
Vehicle **old_hash = v->old_new_hash;
|
||||||
|
@ -28,10 +28,11 @@ const Vehicle *GetLastVehicleInChain(const Vehicle *v);
|
|||||||
uint CountVehiclesInChain(const Vehicle *v);
|
uint CountVehiclesInChain(const Vehicle *v);
|
||||||
bool IsEngineCountable(const Vehicle *v);
|
bool IsEngineCountable(const Vehicle *v);
|
||||||
void DeleteVehicleChain(Vehicle *v);
|
void DeleteVehicleChain(Vehicle *v);
|
||||||
Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc);
|
void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc);
|
||||||
Vehicle *VehicleFromPosXY(int x, int y, 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();
|
void CallVehicleTicks();
|
||||||
Vehicle *FindVehicleOnTileZ(TileIndex tile, byte z);
|
|
||||||
uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *color);
|
uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *color);
|
||||||
|
|
||||||
void InitializeTrains();
|
void InitializeTrains();
|
||||||
@ -50,8 +51,7 @@ SpriteID GetRotorImage(const Vehicle *v);
|
|||||||
uint32 VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y);
|
uint32 VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y);
|
||||||
|
|
||||||
StringID VehicleInTheWayErrMsg(const Vehicle* v);
|
StringID VehicleInTheWayErrMsg(const Vehicle* v);
|
||||||
Vehicle *FindVehicleBetween(TileIndex from, TileIndex to, byte z, bool without_crashed = false);
|
bool HasVehicleOnTunnelBridge(TileIndex tile, TileIndex endtile);
|
||||||
Vehicle *GetVehicleTunnelBridge(TileIndex tile, TileIndex endtile);
|
|
||||||
|
|
||||||
void DecreaseVehicleValue(Vehicle *v);
|
void DecreaseVehicleValue(Vehicle *v);
|
||||||
void CheckVehicleBreakdown(Vehicle *v);
|
void CheckVehicleBreakdown(Vehicle *v);
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "tree_map.h"
|
#include "tree_map.h"
|
||||||
#include "station_base.h"
|
#include "station_base.h"
|
||||||
#include "airport.h"
|
#include "airport.h"
|
||||||
|
#include "aircraft.h"
|
||||||
#include "newgrf_cargo.h"
|
#include "newgrf_cargo.h"
|
||||||
#include "effectvehicle_func.h"
|
#include "effectvehicle_func.h"
|
||||||
#include "oldpool_func.h"
|
#include "oldpool_func.h"
|
||||||
@ -801,28 +802,47 @@ static void AnimateTile_Water(TileIndex tile)
|
|||||||
/* not used */
|
/* 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.
|
* Finds a vehicle to flood.
|
||||||
* It does not find vehicles that are already crashed on bridges, i.e. flooded.
|
* 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
|
* @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)) {
|
if (IsTileType(tile, MP_STATION) && IsAirport(tile)) {
|
||||||
const Station *st = GetStationByTile(tile);
|
const Station *st = GetStationByTile(tile);
|
||||||
const AirportFTAClass *airport = st->Airport();
|
const AirportFTAClass *airport = st->Airport();
|
||||||
|
z = 1 + airport->delta_z;
|
||||||
for (uint x = 0; x < airport->size_x; x++) {
|
for (uint x = 0; x < airport->size_x; x++) {
|
||||||
for (uint y = 0; y < airport->size_y; y++) {
|
for (uint y = 0; y < airport->size_y; y++) {
|
||||||
tile = TILE_ADDXY(st->airport_tile, x, y);
|
tile = TILE_ADDXY(st->airport_tile, x, y);
|
||||||
Vehicle *v = FindVehicleOnTileZ(tile, 1 + airport->delta_z);
|
FindVehicleOnPos(tile, &z, &FloodVehicleProc);
|
||||||
if (v != NULL && (v->vehstatus & VS_CRASHED) == 0) return v;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No vehicle could be flooded on this airport anymore */
|
/* 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 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)
|
BEGIN_TILE_LOOP(t, st->trainst_w, st->trainst_h, st->train_tile)
|
||||||
if (st->TileBelongsToRailStation(t)) {
|
if (st->TileBelongsToRailStation(t)) {
|
||||||
Vehicle *v = FindVehicleOnTileZ(t, 0);
|
FindVehicleOnPos(tile, &z, &FloodVehicleProc);
|
||||||
if (v != NULL && (v->vehstatus & VS_CRASHED) == 0) return v;
|
|
||||||
}
|
}
|
||||||
END_TILE_LOOP(t, st->trainst_w, st->trainst_h, st->train_tile)
|
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);
|
TileIndex end = GetOtherBridgeEnd(tile);
|
||||||
byte z = GetBridgeHeight(tile);
|
z = GetBridgeHeight(tile);
|
||||||
Vehicle *v;
|
|
||||||
|
|
||||||
/* check the start tile first since as this is closest to the water */
|
FindVehicleOnPos(tile, &z, &FloodVehicleProc);
|
||||||
v = FindVehicleOnTileZ(tile, z);
|
FindVehicleOnPos(end, &z, &FloodVehicleProc);
|
||||||
if (v != NULL && (v->vehstatus & VS_CRASHED) == 0) return v;
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FloodVehicle(Vehicle *v)
|
static void FloodVehicle(Vehicle *v)
|
||||||
@ -989,12 +1001,8 @@ static void DoFloodTile(TileIndex target)
|
|||||||
switch (GetTileType(target)) {
|
switch (GetTileType(target)) {
|
||||||
case MP_RAILWAY: {
|
case MP_RAILWAY: {
|
||||||
if (!IsPlainRailTile(target)) break;
|
if (!IsPlainRailTile(target)) break;
|
||||||
|
FloodVehicles(target);
|
||||||
flooded = FloodHalftile(target);
|
flooded = FloodHalftile(target);
|
||||||
|
|
||||||
Vehicle *v = FindFloodableVehicleOnTile(target);
|
|
||||||
if (v != NULL) FloodVehicle(v);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1019,8 +1027,7 @@ static void DoFloodTile(TileIndex target)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Flood vehicles */
|
/* Flood vehicles */
|
||||||
Vehicle *v = FindFloodableVehicleOnTile(target);
|
FloodVehicles(target);
|
||||||
if (v != NULL) FloodVehicle(v);
|
|
||||||
|
|
||||||
/* flood flat tile */
|
/* flood flat tile */
|
||||||
if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
|
if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
|
||||||
|
Loading…
Reference in New Issue
Block a user