1
0
Fork 0

Codechange: Replace FindVehicleOnPos with 'for' loop.

pull/14082/head
frosch 2025-04-22 15:54:43 +02:00 committed by frosch
parent 06c399b79e
commit 2bee313642
12 changed files with 144 additions and 288 deletions

View File

@ -355,15 +355,6 @@ public:
return 0;
}
static Vehicle *CountShipProc(Vehicle *v, void *data)
{
uint *count = (uint*)data;
/* Ignore other vehicles (aircraft) and ships inside depot. */
if (v->type == VEH_SHIP && !v->vehstatus.Test(VehState::Hidden)) (*count)++;
return nullptr;
}
/**
* Called by YAPF to calculate the cost from the origin to the given node.
* Calculates only the cost of given node, adds it to the parent node cost
@ -378,8 +369,10 @@ public:
if (IsDockingTile(n.GetTile())) {
/* Check docking tile for occupancy. */
uint count = 0;
FindVehicleOnPos(n.GetTile(), &count, &CountShipProc);
uint count = std::ranges::count_if(VehiclesOnTile(n.GetTile()), [](const Vehicle *v) {
/* Ignore other vehicles (aircraft) and ships inside depot. */
return v->type == VEH_SHIP && !v->vehstatus.Test(VehState::Hidden);
});
c += count * 3 * YAPF_TILE_LENGTH;
}

View File

@ -259,23 +259,20 @@ struct FindTrainOnTrackInfo {
FindTrainOnTrackInfo() : best(nullptr) {}
};
/** Callback for Has/FindVehicleOnPos to find a train on a specific track. */
static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data)
/** Find the best matching vehicle on a tile. */
static void CheckTrainsOnTrack(FindTrainOnTrackInfo &info, TileIndex tile)
{
FindTrainOnTrackInfo *info = (FindTrainOnTrackInfo *)data;
for (Vehicle *v : VehiclesOnTile(tile)) {
if (v->type != VEH_TRAIN || v->vehstatus.Test(VehState::Crashed)) continue;
if (v->type != VEH_TRAIN || v->vehstatus.Test(VehState::Crashed)) return nullptr;
Train *t = Train::From(v);
if (t->track == TRACK_BIT_WORMHOLE || HasBit(static_cast<TrackBits>(t->track), TrackdirToTrack(info.res.trackdir))) {
t = t->First();
Train *t = Train::From(v);
if (t->track == TRACK_BIT_WORMHOLE || HasBit((TrackBits)t->track, TrackdirToTrack(info->res.trackdir))) {
t = t->First();
/* ALWAYS return the lowest ID (anti-desync!) */
if (info->best == nullptr || t->index < info->best->index) info->best = t;
return t;
/* ALWAYS return the lowest ID (anti-desync!) */
if (info.best == nullptr || t->index < info.best->index) info.best = t;
}
}
return nullptr;
}
/**
@ -298,7 +295,7 @@ PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res)
ftoti.res = FollowReservation(v->owner, GetRailTypeInfo(v->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 != nullptr) {
FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
CheckTrainsOnTrack(ftoti, ftoti.res.tile);
if (ftoti.best != nullptr) *train_on_res = ftoti.best->First();
if (*train_on_res == nullptr && IsRailStationTile(ftoti.res.tile)) {
/* The target tile is a rail station. The track follower
@ -307,13 +304,13 @@ PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res)
* for a possible train. */
TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir)));
for (TileIndex st_tile = ftoti.res.tile + diff; *train_on_res == nullptr && IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) {
FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum);
CheckTrainsOnTrack(ftoti, st_tile);
if (ftoti.best != nullptr) *train_on_res = ftoti.best->First();
}
}
if (*train_on_res == nullptr && IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) {
/* The target tile is a bridge/tunnel, also check the other end tile. */
FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum);
CheckTrainsOnTrack(ftoti, GetOtherTunnelBridgeEnd(ftoti.res.tile));
if (ftoti.best != nullptr) *train_on_res = ftoti.best->First();
}
}
@ -345,21 +342,21 @@ Train *GetTrainForReservation(TileIndex tile, Track track)
FindTrainOnTrackInfo ftoti;
ftoti.res = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true);
FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
CheckTrainsOnTrack(ftoti, ftoti.res.tile);
if (ftoti.best != nullptr) return ftoti.best;
/* Special case for stations: check the whole platform for a vehicle. */
if (IsRailStationTile(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);
CheckTrainsOnTrack(ftoti, st_tile);
if (ftoti.best != nullptr) return ftoti.best;
}
}
/* Special case for bridges/tunnels: check the other end as well. */
if (IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) {
FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum);
CheckTrainsOnTrack(ftoti, GetOtherTunnelBridgeEnd(ftoti.res.tile));
if (ftoti.best != nullptr) return ftoti.best;
}
}

View File

@ -1528,17 +1528,6 @@ CommandCost CmdRemoveSignalTrack(DoCommandFlags flags, TileIndex tile, TileIndex
return CmdSignalTrackHelper(flags, tile, end_tile, track, SIGTYPE_BLOCK, SIG_ELECTRIC, false, true, autofill, false, 1); // bit 5 is remove bit
}
/** Update power of train under which is the railtype being converted */
static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
{
if (v->type != VEH_TRAIN) return nullptr;
TrainList *affected_trains = static_cast<TrainList*>(data);
include(*affected_trains, Train::From(v)->First());
return nullptr;
}
/**
* Convert one rail type to the other. You can convert normal rail to
* monorail/maglev easily or vice-versa.
@ -1640,7 +1629,9 @@ CommandCost CmdConvertRail(DoCommandFlags flags, TileIndex tile, TileIndex area_
SetRailType(tile, totype);
MarkTileDirtyByTile(tile);
/* update power of train on this tile */
FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
for (Vehicle *v : VehiclesOnTile(tile)) {
if (v->type == VEH_TRAIN) include(affected_trains, Train::From(v)->First());
}
}
}
@ -1717,8 +1708,12 @@ CommandCost CmdConvertRail(DoCommandFlags flags, TileIndex tile, TileIndex area_
SetRailType(tile, totype);
SetRailType(endtile, totype);
FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc);
for (Vehicle *v : VehiclesOnTile(tile)) {
if (v->type == VEH_TRAIN) include(affected_trains, Train::From(v)->First());
}
for (Vehicle *v : VehiclesOnTile(endtile)) {
if (v->type == VEH_TRAIN) include(affected_trains, Train::From(v)->First());
}
YapfNotifyTrackLayoutChange(tile, track);
YapfNotifyTrackLayoutChange(endtile, track);

View File

@ -2370,17 +2370,6 @@ static CommandCost TerraformTile_Road(TileIndex tile, DoCommandFlags flags, int
return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
}
/** Update power of road vehicle under which is the roadtype being converted */
static Vehicle *UpdateRoadVehPowerProc(Vehicle *v, void *data)
{
if (v->type != VEH_ROAD) return nullptr;
RoadVehicleList *affected_rvs = static_cast<RoadVehicleList*>(data);
include(*affected_rvs, RoadVehicle::From(v)->First());
return nullptr;
}
/**
* Checks the tile and returns whether the current player is allowed to convert the roadtype to another roadtype without taking ownership
* @param owner the tile owner.
@ -2538,7 +2527,9 @@ CommandCost CmdConvertRoad(DoCommandFlags flags, TileIndex tile, TileIndex area_
MarkTileDirtyByTile(tile);
/* update power of train on this tile */
FindVehicleOnPos(tile, &affected_rvs, &UpdateRoadVehPowerProc);
for (Vehicle *v : VehiclesOnTile(tile)) {
if (v->type == VEH_ROAD) include(affected_rvs, RoadVehicle::From(v)->First());
}
if (IsRoadDepotTile(tile)) {
/* Update build vehicle window related to this depot */
@ -2595,8 +2586,12 @@ CommandCost CmdConvertRoad(DoCommandFlags flags, TileIndex tile, TileIndex area_
SetRoadType(tile, rtt, to_type);
SetRoadType(endtile, rtt, to_type);
FindVehicleOnPos(tile, &affected_rvs, &UpdateRoadVehPowerProc);
FindVehicleOnPos(endtile, &affected_rvs, &UpdateRoadVehPowerProc);
for (Vehicle *v : VehiclesOnTile(tile)) {
if (v->type == VEH_ROAD) include(affected_rvs, RoadVehicle::From(v)->First());
}
for (Vehicle *v : VehiclesOnTile(endtile)) {
if (v->type == VEH_ROAD) include(affected_rvs, RoadVehicle::From(v)->First());
}
if (IsBridge(tile)) {
MarkBridgeDirty(tile);

View File

@ -10,6 +10,7 @@
#include "stdafx.h"
#include "roadveh.h"
#include "core/pool_func.hpp"
#include "core/container_func.hpp"
#include "roadstop_base.h"
#include "station_base.h"
#include "vehicle_func.h"
@ -309,39 +310,6 @@ void RoadStop::Entry::Enter(const RoadVehicle *rv)
GetDriveThroughStopAxis(next) == GetDriveThroughStopAxis(rs);
}
typedef std::list<const RoadVehicle *> RVList; ///< A list of road vehicles
/** Helper for finding RVs in a road stop. */
struct RoadStopEntryRebuilderHelper {
RVList vehicles; ///< The list of vehicles to possibly add to.
DiagDirection dir; ///< The direction the vehicle has to face to be added.
};
/**
* Add road vehicles to the station's list if needed.
* @param v the found vehicle
* @param data the extra data used to make our decision
* @return always nullptr
*/
Vehicle *FindVehiclesInRoadStop(Vehicle *v, void *data)
{
RoadStopEntryRebuilderHelper *rserh = (RoadStopEntryRebuilderHelper*)data;
/* Not a RV or not in the right direction or crashed :( */
if (v->type != VEH_ROAD || DirToDiagDir(v->direction) != rserh->dir || !v->IsPrimaryVehicle() || v->vehstatus.Test(VehState::Crashed)) return nullptr;
RoadVehicle *rv = RoadVehicle::From(v);
/* Don't add ones not in a road stop */
if (rv->state < RVSB_IN_ROAD_STOP) return nullptr;
/* Do not add duplicates! */
for (const auto &it : rserh->vehicles) {
if (rv == it) return nullptr;
}
rserh->vehicles.push_back(rv);
return nullptr;
}
/**
* Get the DiagDirection for entering the drive through stop from the given 'side' (east or west) on the given axis.
* @param east Enter from the east when true or from the west when false.
@ -369,18 +337,27 @@ void RoadStop::Entry::Rebuild(const RoadStop *rs, int side)
Axis axis = GetDriveThroughStopAxis(rs->xy);
if (side == -1) side = (rs->east == this);
RoadStopEntryRebuilderHelper rserh;
rserh.dir = GetEntryDirection(side, axis);
auto entry_dir = GetEntryDirection(side, axis);
std::vector<const RoadVehicle *> vehicles;
this->length = 0;
TileIndexDiff offset = TileOffsByAxis(axis);
for (TileIndex tile = rs->xy; IsDriveThroughRoadStopContinuation(rs->xy, tile); tile += offset) {
this->length += TILE_SIZE;
FindVehicleOnPos(tile, &rserh, FindVehiclesInRoadStop);
for (const Vehicle *v : VehiclesOnTile(tile)) {
/* Not a RV or not in the right direction or crashed :( */
if (v->type != VEH_ROAD || DirToDiagDir(v->direction) != entry_dir || !v->IsPrimaryVehicle() || v->vehstatus.Test(VehState::Crashed)) continue;
const RoadVehicle *rv = RoadVehicle::From(v);
/* Don't add ones not in a road stop */
if (rv->state < RVSB_IN_ROAD_STOP) continue;
include(vehicles, rv);
}
}
this->occupied = 0;
for (const auto &it : rserh.vehicles) {
for (const auto &it : vehicles) {
this->occupied += it->gcache.cached_total_length;
}
}

View File

@ -659,8 +659,12 @@ static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction d
rvf.best_diff = UINT_MAX;
if (front->state == RVSB_WORMHOLE) {
FindVehicleOnPos(v->tile, &rvf, EnumCheckRoadVehClose);
FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &rvf, EnumCheckRoadVehClose);
for (Vehicle *u : VehiclesOnTile(v->tile)) {
EnumCheckRoadVehClose(u, &rvf);
}
for (Vehicle *u : VehiclesOnTile(GetOtherTunnelBridgeEnd(v->tile))) {
EnumCheckRoadVehClose(u, &rvf);
}
} else {
FindVehicleOnPosXY(x, y, &rvf, EnumCheckRoadVehClose);
}

View File

@ -2108,24 +2108,6 @@ CommandCost CmdBuildRoadStop(DoCommandFlags flags, TileIndex tile, uint8_t width
return cost;
}
static Vehicle *ClearRoadStopStatusEnum(Vehicle *v, void *)
{
if (v->type == VEH_ROAD) {
/* Okay... we are a road vehicle on a drive through road stop.
* But that road stop has just been removed, so we need to make
* sure we are in a valid state... however, vehicles can also
* turn on road stop tiles, so only clear the 'road stop' state
* bits and only when the state was 'in road stop', otherwise
* we'll end up clearing the turn around bits. */
RoadVehicle *rv = RoadVehicle::From(v);
if (HasBit(rv->state, RVS_IN_DT_ROAD_STOP)) rv->state &= RVSB_ROAD_STOP_TRACKDIR_MASK;
}
return nullptr;
}
/**
* Remove a bus station/truck stop
* @param tile TileIndex been queried
@ -2159,7 +2141,19 @@ static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlags flags, int repl
/* don't do the check for drive-through road stops when company bankrupts */
if (IsDriveThroughStopTile(tile) && flags.Test(DoCommandFlag::Bankrupt)) {
/* remove the 'going through road stop' status from all vehicles on that tile */
if (flags.Test(DoCommandFlag::Execute)) FindVehicleOnPos(tile, nullptr, &ClearRoadStopStatusEnum);
if (flags.Test(DoCommandFlag::Execute)) {
for (Vehicle *v : VehiclesOnTile(tile)) {
if (v->type != VEH_ROAD) continue;
/* Okay... we are a road vehicle on a drive through road stop.
* But that road stop has just been removed, so we need to make
* sure we are in a valid state... however, vehicles can also
* turn on road stop tiles, so only clear the 'road stop' state
* bits and only when the state was 'in road stop', otherwise
* we'll end up clearing the turn around bits. */
RoadVehicle *rv = RoadVehicle::From(v);
if (HasBit(rv->state, RVS_IN_DT_ROAD_STOP)) rv->state &= RVSB_ROAD_STOP_TRACKDIR_MASK;
}
}
} else {
CommandCost ret = EnsureNoVehicleOnGround(tile);
if (ret.Failed()) return ret;

View File

@ -3234,8 +3234,12 @@ static bool CheckTrainCollision(Train *v)
/* find colliding vehicles */
if (v->track == TRACK_BIT_WORMHOLE) {
FindVehicleOnPos(v->tile, &tcc, FindTrainCollideEnum);
FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &tcc, FindTrainCollideEnum);
for (Vehicle *u : VehiclesOnTile(v->tile)) {
FindTrainCollideEnum(u, &tcc);
}
for (Vehicle *u : VehiclesOnTile(GetOtherTunnelBridgeEnd(v->tile))) {
FindTrainCollideEnum(u, &tcc);
}
} else {
FindVehicleOnPosXY(v->x_pos, v->y_pos, &tcc, FindTrainCollideEnum);
}
@ -3582,29 +3586,6 @@ reverse_train_direction:
return false;
}
/**
* Collect trackbits of all crashed train vehicles on a tile
* @param v Vehicle passed from Find/HasVehicleOnPos()
* @param data trackdirbits for the result
* @return nullptr 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.Test(VehState::Crashed)) {
TrackBits train_tbits = Train::From(v)->track;
if (train_tbits == TRACK_BIT_WORMHOLE) {
/* Vehicle is inside a wormhole, v->track contains no useful value then. */
*trackbits |= DiagDirToDiagTrackBits(GetTunnelBridgeDirection(v->tile));
} else if (train_tbits != TRACK_BIT_DEPOT) {
*trackbits |= train_tbits;
}
}
return nullptr;
}
static bool IsRailStationPlatformOccupied(TileIndex tile)
{
TileIndexDiff delta = TileOffsByAxis(GetRailStationAxis(tile));
@ -3631,11 +3612,11 @@ static void DeleteLastWagon(Train *v)
Train *first = v->First();
/* Go to the last wagon and delete the link pointing there
* *u is then the one-before-last wagon, and *v the last
* new_last is then the one-before-last wagon, and v the last
* one which will physically be removed */
Train *u = v;
for (; v->Next() != nullptr; v = v->Next()) u = v;
u->SetNext(nullptr);
Train *new_last = v;
for (; v->Next() != nullptr; v = v->Next()) new_last = v;
new_last->SetNext(nullptr);
if (first != v) {
/* Recalculate cached train properties */
@ -3667,7 +3648,16 @@ static void DeleteLastWagon(Train *v)
/* If there are still crashed vehicles on the tile, give the track reservation to them */
TrackBits remaining_trackbits = TRACK_BIT_NONE;
FindVehicleOnPos(tile, &remaining_trackbits, CollectTrackbitsFromCrashedVehiclesEnum);
for (const Vehicle *u : VehiclesOnTile(tile)) {
if (u->type != VEH_TRAIN || !u->vehstatus.Test(VehState::Crashed)) continue;
TrackBits train_tbits = Train::From(u)->track;
if (train_tbits == TRACK_BIT_WORMHOLE) {
/* Vehicle is inside a wormhole, u->track contains no useful value then. */
remaining_trackbits |= DiagDirToDiagTrackBits(GetTunnelBridgeDirection(u->tile));
} else if (train_tbits != TRACK_BIT_DEPOT) {
remaining_trackbits |= train_tbits;
}
}
/* 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);

View File

@ -500,66 +500,6 @@ void VehiclesOnTile::Iterator::SkipFalseMatches()
while (this->current != nullptr && this->current->tile != this->tile) this->Increment();
}
/**
* 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 \a 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 = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
for (; v != nullptr; v = v->hash_tile_next) {
if (v->tile != tile) continue;
Vehicle *a = proc(v, data);
if (find_first && a != nullptr) return a;
}
return nullptr;
}
/**
* Find a vehicle from a specific location. It will call \a 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 \a proc will be ignored.
* @note Use this function 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 \a 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);
}
/**
* Callback that returns 'real' vehicles lower or at height \c *(int*)data .
* @param v Vehicle to examine.
* @param data Pointer to height data.
* @return \a v if conditions are met, else \c nullptr.
*/
static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data)
{
int z = *(int*)data;
if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return nullptr;
if (v->z_pos > z) return nullptr;
return v;
}
/**
* Ensure there is no vehicle at the ground at the given position.
* @param tile Position to examine.
@ -573,20 +513,15 @@ CommandCost EnsureNoVehicleOnGround(TileIndex tile)
* error message only (which may be different for different machines).
* Such a message does not affect MP synchronisation.
*/
Vehicle *v = VehicleFromPos(tile, &z, &EnsureNoVehicleProcZ, true);
if (v != nullptr) return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
for (const Vehicle *v : VehiclesOnTile(tile)) {
if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) continue;
if (v->z_pos > z) continue;
return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
}
return CommandCost();
}
/** 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 nullptr;
if (v == (const Vehicle *)data) return nullptr;
return v;
}
/**
* Finds vehicle in tunnel / bridge
* @param tile first end
@ -596,29 +531,20 @@ static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
*/
CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore)
{
/* Value v is not safe in MP games, however, it is used to generate a local
* error message only (which may be different for different machines).
* Such a message does not affect MP synchronisation.
*/
Vehicle *v = VehicleFromPos(tile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
if (v == nullptr) v = VehicleFromPos(endtile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
if (v != nullptr) return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
for (TileIndex t : {tile, endtile}) {
/* Value v is not safe in MP games, however, it is used to generate a local
* error message only (which may be different for different machines).
* Such a message does not affect MP synchronisation.
*/
for (const Vehicle *v : VehiclesOnTile(t)) {
if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) continue;
if (v == ignore) continue;
return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
}
}
return CommandCost();
}
static Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
{
TrackBits rail_bits = *(TrackBits *)data;
if (v->type != VEH_TRAIN) return nullptr;
Train *t = Train::From(v);
if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return nullptr;
return v;
}
/**
* Tests if a vehicle interacts with the specified track bits.
* All track bits interact except parallel #TRACK_BIT_HORZ or #TRACK_BIT_VERT.
@ -633,8 +559,14 @@ CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits)
* error message only (which may be different for different machines).
* Such a message does not affect MP synchronisation.
*/
Vehicle *v = VehicleFromPos(tile, &track_bits, &EnsureNoTrainOnTrackProc, true);
if (v != nullptr) return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
for (const Vehicle *v : VehiclesOnTile(tile)) {
if (v->type != VEH_TRAIN) continue;
const Train *t = Train::From(v);
if ((t->track != track_bits) && !TracksOverlap(t->track | track_bits)) continue;
return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
}
return CommandCost();
}

View File

@ -115,7 +115,6 @@ typedef Vehicle *VehicleFromPosProc(Vehicle *v, void *data);
void VehicleServiceInDepot(Vehicle *v);
uint CountVehiclesInChain(const Vehicle *v);
void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc);
void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc);
bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc);
void CallVehicleTicks();

View File

@ -32,39 +32,6 @@ WindowNumber VehicleListIdentifier::ToWindowNumber() const
return c << 28 | this->type << 23 | this->vtype << 26 | this->index;
}
/** Data for building a depot vehicle list. */
struct BuildDepotVehicleListData
{
VehicleList *engines; ///< Pointer to list to add vehicles to.
VehicleList *wagons; ///< Pointer to list to add wagons to (can be nullptr).
VehicleType type; ///< Type of vehicle.
bool individual_wagons; ///< If true add every wagon to \a wagons which is not attached to an engine. If false only add the first wagon of every row.
};
/**
* Add vehicles to a depot vehicle list.
* @param v The found vehicle.
* @param data The depot vehicle list data.
* @return Always nullptr.
*/
static Vehicle *BuildDepotVehicleListProc(Vehicle *v, void *data)
{
auto bdvld = static_cast<BuildDepotVehicleListData *>(data);
if (v->type != bdvld->type || !v->IsInDepot()) return nullptr;
if (bdvld->type == VEH_TRAIN) {
const Train *t = Train::From(v);
if (t->IsArticulatedPart() || t->IsRearDualheaded()) return nullptr;
if (bdvld->wagons != nullptr && t->First()->IsFreeWagon()) {
if (bdvld->individual_wagons || t->IsFreeWagon()) bdvld->wagons->push_back(t);
return nullptr;
}
}
if (v->IsPrimaryVehicle()) bdvld->engines->push_back(v);
return nullptr;
};
/**
* Generate a list of vehicles inside a depot.
* @param type Type of vehicle
@ -78,8 +45,20 @@ void BuildDepotVehicleList(VehicleType type, TileIndex tile, VehicleList *engine
engines->clear();
if (wagons != nullptr && wagons != engines) wagons->clear();
BuildDepotVehicleListData bdvld{engines, wagons, type, individual_wagons};
FindVehicleOnPos(tile, &bdvld, BuildDepotVehicleListProc);
for (Vehicle *v : VehiclesOnTile(tile)) {
if (v->type != type || !v->IsInDepot()) continue;
if (type == VEH_TRAIN) {
const Train *t = Train::From(v);
if (t->IsArticulatedPart() || t->IsRearDualheaded()) continue;
if (wagons != nullptr && t->First()->IsFreeWagon()) {
if (individual_wagons || t->IsFreeWagon()) wagons->push_back(t);
continue;
}
}
if (v->IsPrimaryVehicle()) engines->push_back(v);
}
}
/**

View File

@ -1012,12 +1012,11 @@ 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 nullptr as we always want to remove everything.
* @param z The z of level to flood.
*/
static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
static void FloodVehicleProc(Vehicle *v, int z)
{
if (v->vehstatus.Test(VehState::Crashed)) return nullptr;
if (v->vehstatus.Test(VehState::Crashed)) return;
switch (v->type) {
default: break;
@ -1038,14 +1037,18 @@ static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
case VEH_TRAIN:
case VEH_ROAD: {
int z = *(int*)data;
if (v->z_pos > z) break;
FloodVehicle(v->First());
break;
}
}
}
return nullptr;
static void FloodVehiclesOnTile(TileIndex tile, int z)
{
for (Vehicle *v : VehiclesOnTile(tile)) {
FloodVehicleProc(v, z);
}
}
/**
@ -1055,12 +1058,10 @@ static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
*/
static void FloodVehicles(TileIndex tile)
{
int z = 0;
if (IsAirportTile(tile)) {
const Station *st = Station::GetByTile(tile);
for (TileIndex airport_tile : st->airport) {
if (st->TileBelongsToAirport(airport_tile)) FindVehicleOnPos(airport_tile, &z, &FloodVehicleProc);
if (st->TileBelongsToAirport(airport_tile)) FloodVehiclesOnTile(airport_tile, 0);
}
/* No vehicle could be flooded on this airport anymore */
@ -1068,15 +1069,15 @@ static void FloodVehicles(TileIndex tile)
}
if (!IsBridgeTile(tile)) {
FindVehicleOnPos(tile, &z, &FloodVehicleProc);
FloodVehiclesOnTile(tile, 0);
return;
}
TileIndex end = GetOtherBridgeEnd(tile);
z = GetBridgePixelHeight(tile);
int z = GetBridgePixelHeight(tile);
FindVehicleOnPos(tile, &z, &FloodVehicleProc);
FindVehicleOnPos(end, &z, &FloodVehicleProc);
FloodVehiclesOnTile(tile, z);
FloodVehiclesOnTile(end, z);
}
/**