diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 6226b94b32..e9ea6bf292 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -3032,14 +3032,6 @@ static CommandCost TestAutoslopeOnRailTile(TileIndex tile, DoCommandFlags flags, return cost; } -/** - * Test-procedure for HasVehicleOnPos to check for a ship. - */ -static Vehicle *EnsureNoShipProc(Vehicle *v, void *) -{ - return v->type == VEH_SHIP ? v : nullptr; -} - static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlags flags, int z_new, Slope tileh_new) { auto [tileh_old, z_old] = GetTileSlopeZ(tile); @@ -3049,7 +3041,9 @@ static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlags flags, int bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)); /* Allow clearing the water only if there is no ship */ - if (was_water && HasVehicleOnPos(tile, nullptr, &EnsureNoShipProc)) return CommandCost(STR_ERROR_SHIP_IN_THE_WAY); + if (was_water && HasVehicleOnTile(tile, [](const Vehicle *v) { + return v->type == VEH_SHIP; + })) return CommandCost(STR_ERROR_SHIP_IN_THE_WAY); /* First test autoslope. However if it succeeds we still have to test the rest, because non-autoslope terraforming is cheaper. */ CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits); diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index fdddfb49ec..750b42b567 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -767,13 +767,6 @@ struct OvertakeData { Trackdir trackdir; }; -static Vehicle *EnumFindVehBlockingOvertake(Vehicle *v, void *data) -{ - const OvertakeData *od = (OvertakeData*)data; - - return (v->type == VEH_ROAD && v->First() == v && v != od->u && v != od->v) ? v : nullptr; -} - /** * Check if overtaking is possible on a piece of track * @@ -792,7 +785,9 @@ static bool CheckRoadBlockedForOvertaking(OvertakeData *od) if (!HasBit(trackdirbits, od->trackdir) || (trackbits & ~TRACK_BIT_CROSS) || (red_signals != TRACKDIR_BIT_NONE)) return true; /* Are there more vehicles on the tile except the two vehicles involved in overtaking */ - return HasVehicleOnPos(od->tile, od, EnumFindVehBlockingOvertake); + return HasVehicleOnTile(od->tile, [&](const Vehicle *v) { + return v->type == VEH_ROAD && v->First() == v && v != od->u && v != od->v; + }); } static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u) diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index f0200994e8..d75b7a338a 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -359,14 +359,6 @@ void Ship::UpdateDeltaXY() } } -/** - * Test-procedure for HasVehicleOnPos to check for any ships which are moving. - */ -static Vehicle *EnsureNoMovingShipProc(Vehicle *v, void *) -{ - return v->type == VEH_SHIP && v->cur_speed != 0 ? v : nullptr; -} - static bool CheckReverseShip(const Ship *v, Trackdir *trackdir = nullptr) { /* Ask pathfinder for best direction */ @@ -392,7 +384,9 @@ static bool CheckShipLeaveDepot(Ship *v) /* Don't leave depot if another vehicle is already entering/leaving */ /* This helps avoid CPU load if many ships are set to start at the same time */ - if (HasVehicleOnPos(v->tile, nullptr, &EnsureNoMovingShipProc)) return true; + if (HasVehicleOnTile(v->tile, [](const Vehicle *u) { + return u->type == VEH_SHIP && u->cur_speed != 0; + })) return true; TileIndex tile = v->tile; Axis axis = GetShipDepotAxis(tile); diff --git a/src/signal.cpp b/src/signal.cpp index b88ca97161..95b74a5022 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -189,11 +189,9 @@ static SmallSet _globset("_globset"); ///< set of /** Check whether there is a train on rail, not in a depot */ -static Vehicle *TrainOnTileEnum(Vehicle *v, void *) +static bool IsTrainAndNotInDepot(const Vehicle *v) { - if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return nullptr; - - return v; + return v->type == VEH_TRAIN && Train::From(v)->track != TRACK_BIT_DEPOT; } @@ -280,13 +278,13 @@ static SigFlags ExploreSegment(Owner owner) if (IsRailDepot(tile)) { if (enterdir == INVALID_DIAGDIR) { // from 'inside' - train just entered or left the depot - if (!flags.Test(SigFlag::Train) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags.Set(SigFlag::Train); + if (!flags.Test(SigFlag::Train) && HasVehicleOnTile(tile, IsTrainAndNotInDepot)) flags.Set(SigFlag::Train); exitdir = GetRailDepotDirection(tile); tile += TileOffsByDiagDir(exitdir); enterdir = ReverseDiagDir(exitdir); break; } else if (enterdir == GetRailDepotDirection(tile)) { // entered a depot - if (!flags.Test(SigFlag::Train) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags.Set(SigFlag::Train); + if (!flags.Test(SigFlag::Train) && HasVehicleOnTile(tile, IsTrainAndNotInDepot)) flags.Set(SigFlag::Train); continue; } else { continue; @@ -303,7 +301,7 @@ static SigFlags ExploreSegment(Owner owner) if (!flags.Test(SigFlag::Train) && EnsureNoTrainOnTrackBits(tile, tracks).Failed()) flags. Set(SigFlag::Train); } else { if (tracks_masked == TRACK_BIT_NONE) continue; // no incidating track - if (!flags.Test(SigFlag::Train) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags.Set(SigFlag::Train); + if (!flags.Test(SigFlag::Train) && HasVehicleOnTile(tile, IsTrainAndNotInDepot)) flags.Set(SigFlag::Train); } /* Is this a track merge or split? */ @@ -358,7 +356,7 @@ static SigFlags ExploreSegment(Owner owner) if (DiagDirToAxis(enterdir) != GetRailStationAxis(tile)) continue; // different axis if (IsStationTileBlocked(tile)) continue; // 'eye-candy' station tile - if (!flags.Test(SigFlag::Train) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags.Set(SigFlag::Train); + if (!flags.Test(SigFlag::Train) && HasVehicleOnTile(tile, IsTrainAndNotInDepot)) flags.Set(SigFlag::Train); tile += TileOffsByDiagDir(exitdir); break; @@ -367,7 +365,7 @@ static SigFlags ExploreSegment(Owner owner) if (GetTileOwner(tile) != owner) continue; if (DiagDirToAxis(enterdir) == GetCrossingRoadAxis(tile)) continue; // different axis - if (!flags.Test(SigFlag::Train) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags.Set(SigFlag::Train); + if (!flags.Test(SigFlag::Train) && HasVehicleOnTile(tile, IsTrainAndNotInDepot)) flags.Set(SigFlag::Train); tile += TileOffsByDiagDir(exitdir); break; @@ -377,13 +375,13 @@ static SigFlags ExploreSegment(Owner owner) DiagDirection dir = GetTunnelBridgeDirection(tile); if (enterdir == INVALID_DIAGDIR) { // incoming from the wormhole - if (!flags.Test(SigFlag::Train) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags.Set(SigFlag::Train); + if (!flags.Test(SigFlag::Train) && HasVehicleOnTile(tile, IsTrainAndNotInDepot)) flags.Set(SigFlag::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.Test(SigFlag::Train) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags.Set(SigFlag::Train); + if (!flags.Test(SigFlag::Train) && HasVehicleOnTile(tile, IsTrainAndNotInDepot)) flags.Set(SigFlag::Train); tile = GetOtherTunnelBridgeEnd(tile); // just skip to exit tile enterdir = INVALID_DIAGDIR; exitdir = INVALID_DIAGDIR; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index f6372cbb22..54b2106ed1 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -1664,15 +1664,14 @@ void ReverseTrainSwapVeh(Train *v, int l, int r) } } - /** * Check if the vehicle is a train * @param v vehicle on tile - * @return v if it is a train, nullptr otherwise + * @return true if v is a train */ -static Vehicle *TrainOnTileEnum(Vehicle *v, void *) +static bool IsTrain(const Vehicle *v) { - return (v->type == VEH_TRAIN) ? v : nullptr; + return v->type == VEH_TRAIN; } /** @@ -1685,28 +1684,23 @@ bool TrainOnCrossing(TileIndex tile) { assert(IsLevelCrossingTile(tile)); - return HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum); + return HasVehicleOnTile(tile, IsTrain); } - /** * Checks if a train is approaching a rail-road crossing * @param v vehicle on tile - * @param data tile with crossing we are testing - * @return v if it is approaching a crossing, nullptr otherwise + * @param tile tile with crossing we are testing + * @return true if v is approaching a crossing */ -static Vehicle *TrainApproachingCrossingEnum(Vehicle *v, void *data) +static bool TrainApproachingCrossingEnum(const Vehicle *v, TileIndex tile) { - if (v->type != VEH_TRAIN || v->vehstatus.Test(VehState::Crashed)) return nullptr; + if (v->type != VEH_TRAIN || v->vehstatus.Test(VehState::Crashed)) return false; - Train *t = Train::From(v); - if (!t->IsFrontEngine()) return nullptr; + const Train *t = Train::From(v); + if (!t->IsFrontEngine()) return false; - TileIndex tile = *(TileIndex *)data; - - if (TrainApproachingCrossingTile(t) != tile) return nullptr; - - return t; + return TrainApproachingCrossingTile(t) == tile; } @@ -1723,12 +1717,16 @@ static bool TrainApproachingCrossing(TileIndex tile) DiagDirection dir = AxisToDiagDir(GetCrossingRailAxis(tile)); TileIndex tile_from = tile + TileOffsByDiagDir(dir); - if (HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum)) return true; + if (HasVehicleOnTile(tile_from, [&](const Vehicle *v) { + return TrainApproachingCrossingEnum(v, tile); + })) return true; dir = ReverseDiagDir(dir); tile_from = tile + TileOffsByDiagDir(dir); - return HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum); + return HasVehicleOnTile(tile_from, [&](const Vehicle *v) { + return TrainApproachingCrossingEnum(v, tile); + }); } /** @@ -3252,21 +3250,6 @@ static bool CheckTrainCollision(Train *v) return true; } -static Vehicle *CheckTrainAtSignal(Vehicle *v, void *data) -{ - if (v->type != VEH_TRAIN || v->vehstatus.Test(VehState::Crashed)) return nullptr; - - Train *t = Train::From(v); - DiagDirection exitdir = *(DiagDirection *)data; - - /* not front engine of a train, inside wormhole or depot, crashed */ - if (!t->IsFrontEngine() || !(t->track & TRACK_BIT_MASK)) return nullptr; - - if (t->cur_speed > 5 || VehicleExitDir(t->direction, t->track) != exitdir) return nullptr; - - return t; -} - /** * Move a vehicle chain one movement stop forwards. * @param v First vehicle to move. @@ -3384,7 +3367,17 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) exitdir = ReverseDiagDir(exitdir); /* check if a train is waiting on the other side */ - if (!HasVehicleOnPos(o_tile, &exitdir, &CheckTrainAtSignal)) return false; + if (!HasVehicleOnTile(o_tile, [&exitdir](const Vehicle *u) { + if (u->type != VEH_TRAIN || u->vehstatus.Test(VehState::Crashed)) return false; + const Train *t = Train::From(u); + + /* not front engine of a train, inside wormhole or depot, crashed */ + if (!t->IsFrontEngine() || !(t->track & TRACK_BIT_MASK)) return false; + + if (t->cur_speed > 5 || VehicleExitDir(t->direction, t->track) != exitdir) return false; + + return true; + })) return false; } } @@ -3617,10 +3610,10 @@ static bool IsRailStationPlatformOccupied(TileIndex tile) TileIndexDiff delta = TileOffsByAxis(GetRailStationAxis(tile)); for (TileIndex t = tile; IsCompatibleTrainStationTile(t, tile); t -= delta) { - if (HasVehicleOnPos(t, nullptr, &TrainOnTileEnum)) return true; + if (HasVehicleOnTile(t, IsTrain)) return true; } for (TileIndex t = tile + delta; IsCompatibleTrainStationTile(t, tile); t += delta) { - if (HasVehicleOnPos(t, nullptr, &TrainOnTileEnum)) return true; + if (HasVehicleOnTile(t, IsTrain)) return true; } return false; diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 5ad7891098..9ad6eb775f 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -544,21 +544,6 @@ void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc) VehicleFromPos(tile, data, proc, false); } -/** - * Checks whether a vehicle is on a specific location. It will call \a proc for - * vehicles until it returns non-nullptr. - * @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 \a proc. - * @param proc The \a proc that determines whether a vehicle will be "found". - * @return True if proc returned non-nullptr. - */ -bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc) -{ - return VehicleFromPos(tile, data, proc, true) != nullptr; -} - /** * Callback that returns 'real' vehicles lower or at height \c *(int*)data . * @param v Vehicle to examine. diff --git a/src/vehicle_func.h b/src/vehicle_func.h index 7f3feb436a..f91d76851d 100644 --- a/src/vehicle_func.h +++ b/src/vehicle_func.h @@ -98,13 +98,25 @@ private: Iterator start; }; +/** + * Loop over vehicles on a tile, and check whether a predicate is true for any of them. + * The predicate must have the signature: bool Predicate(const Vehicle *); + */ +template +bool HasVehicleOnTile(TileIndex tile, UnaryPred &&predicate) +{ + for (const auto *v : VehiclesOnTile(tile)) { + if (predicate(v)) return true; + } + return false; +} + 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 HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc); bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc); void CallVehicleTicks(); uint8_t CalcPercentVehicleFilled(const Vehicle *v, StringID *colour);