From 4108672cf6e60f368f0e5e406c5062e9bdb6129f Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Fri, 28 Feb 2020 22:21:10 +0000 Subject: [PATCH] Use separate tile hash for each vehicle type --- src/pathfinder/npf/npf.cpp | 4 +- src/pathfinder/yapf/yapf_ship.cpp | 4 +- src/pbs.cpp | 17 ++-- src/rail_cmd.cpp | 12 ++- src/road_cmd.cpp | 8 +- src/roadstop.cpp | 4 +- src/roadveh_cmd.cpp | 18 ++-- src/ship_cmd.cpp | 18 ++-- src/signal.cpp | 26 +++--- src/station_cmd.cpp | 20 ++--- src/train_cmd.cpp | 36 ++++---- src/vehicle.cpp | 137 +++++++++--------------------- src/vehicle_func.h | 77 ++++++++++++++++- src/water_cmd.cpp | 67 ++++++++------- 14 files changed, 227 insertions(+), 221 deletions(-) diff --git a/src/pathfinder/npf/npf.cpp b/src/pathfinder/npf/npf.cpp index b6fe8c4f78..2d9268ec2c 100644 --- a/src/pathfinder/npf/npf.cpp +++ b/src/pathfinder/npf/npf.cpp @@ -307,7 +307,7 @@ 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 & VS_HIDDEN) == 0) (*count)++; + if ((v->vehstatus & VS_HIDDEN) == 0) (*count)++; return nullptr; } @@ -331,7 +331,7 @@ static int32 NPFWaterPathCost(AyStar *as, AyStarNode *current, OpenListNode *par if (IsDockingTile(current->tile)) { /* Check docking tile for occupancy */ uint count = 1; - HasVehicleOnPos(current->tile, &count, &CountShipProc); + HasVehicleOnPos(current->tile, VEH_SHIP, &count, &CountShipProc); cost += count * 3 * _trackdir_length[trackdir]; } diff --git a/src/pathfinder/yapf/yapf_ship.cpp b/src/pathfinder/yapf/yapf_ship.cpp index 2f2ed7e441..f1ec0aec02 100644 --- a/src/pathfinder/yapf/yapf_ship.cpp +++ b/src/pathfinder/yapf/yapf_ship.cpp @@ -268,7 +268,7 @@ public: { uint *count = (uint *)data; /* Ignore other vehicles (aircraft) and ships inside depot. */ - if (v->type == VEH_SHIP && (v->vehstatus & VS_HIDDEN) == 0) (*count)++; + if ((v->vehstatus & VS_HIDDEN) == 0) (*count)++; return nullptr; } @@ -288,7 +288,7 @@ public: if (IsDockingTile(n.GetTile())) { /* Check docking tile for occupancy */ uint count = 1; - HasVehicleOnPos(n.GetTile(), &count, &CountShipProc); + HasVehicleOnPos(n.GetTile(), VEH_SHIP, &count, &CountShipProc); c += count * 3 * YAPF_TILE_LENGTH; } diff --git a/src/pbs.cpp b/src/pbs.cpp index a8befd0f7f..6d6a7cc2c8 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -330,7 +330,7 @@ static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data) { FindTrainOnTrackInfo *info = (FindTrainOnTrackInfo *)data; - if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return nullptr; + if ((v->vehstatus & VS_CRASHED)) return nullptr; Train *t = Train::From(v); if (t->track & TRACK_BIT_WORMHOLE) { @@ -372,7 +372,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); + FindVehicleOnPos(ftoti.res.tile, VEH_TRAIN, &ftoti, FindTrainOnTrackEnum); 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 @@ -381,13 +381,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); + FindVehicleOnPos(st_tile, VEH_TRAIN, &ftoti, FindTrainOnTrackEnum); if (ftoti.best != nullptr) *train_on_res = ftoti.best->First(); } } if (*train_on_res == nullptr && IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE) && IsTrackAcrossTunnelBridge(ftoti.res.tile, TrackdirToTrack(ftoti.res.trackdir)) && !IsTunnelBridgeWithSignalSimulation(ftoti.res.tile)) { /* The target tile is a bridge/tunnel, also check the other end tile. */ - FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum); + FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), VEH_TRAIN, &ftoti, FindTrainOnTrackEnum); if (ftoti.best != nullptr) *train_on_res = ftoti.best->First(); } } @@ -419,21 +419,21 @@ Train *GetTrainForReservation(TileIndex tile, Track track) FindTrainOnTrackInfo ftoti; ftoti.res = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true); - FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum); + FindVehicleOnPos(ftoti.res.tile, VEH_TRAIN, &ftoti, FindTrainOnTrackEnum); 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); + FindVehicleOnPos(st_tile, VEH_TRAIN, &ftoti, FindTrainOnTrackEnum); 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) && IsTrackAcrossTunnelBridge(ftoti.res.tile, TrackdirToTrack(ftoti.res.trackdir))) { - FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum); + FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), VEH_TRAIN, &ftoti, FindTrainOnTrackEnum); if (ftoti.best != nullptr) return ftoti.best; } } @@ -608,8 +608,7 @@ bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bo TileIndex other_end = GetOtherTunnelBridgeEnd(tile); if (HasAcrossTunnelBridgeReservation(other_end) && GetTunnelBridgeExitSignalState(other_end) == SIGNAL_STATE_RED) return false; Direction dir = DiagDirToDir(GetTunnelBridgeDirection(other_end)); - if (HasVehicleOnPos(other_end, &dir, [](Vehicle *v, void *data) -> Vehicle * { - if (v->type != VEH_TRAIN) return nullptr; + if (HasVehicleOnPos(other_end, VEH_TRAIN, &dir, [](Vehicle *v, void *data) -> Vehicle * { DirDiff diff = DirDifference(v->direction, *((Direction *) data)); if (diff == DIRDIFF_SAME) return v; if (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT) { diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 9534f8403e..f5dc035a35 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -2015,8 +2015,6 @@ CommandCost CmdRemoveSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, /** 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(data); include(*affected_trains, Train::From(v)->First()); @@ -2148,7 +2146,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP); /* update power of train on this tile */ - FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc); + FindVehicleOnPos(tile, VEH_TRAIN, &affected_trains, &UpdateTrainPowerProc); } } @@ -2224,8 +2222,8 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 SetSecondaryRailType(tile, totype); SetSecondaryRailType(endtile, totype); - FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc); - FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc); + FindVehicleOnPos(tile, VEH_TRAIN, &affected_trains, &UpdateTrainPowerProc); + FindVehicleOnPos(endtile, VEH_TRAIN, &affected_trains, &UpdateTrainPowerProc); /* notify YAPF about the track layout change */ yapf_notify_track_change(tile, GetTunnelBridgeTrackBits(tile)); @@ -3808,7 +3806,7 @@ static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, int z_old */ static Vehicle *EnsureNoShipProc(Vehicle *v, void *data) { - return v->type == VEH_SHIP ? v : nullptr; + return v; } static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new) @@ -3821,7 +3819,7 @@ static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag 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_cmd_error(STR_ERROR_SHIP_IN_THE_WAY); + if (was_water && HasVehicleOnPos(tile, VEH_SHIP, nullptr, &EnsureNoShipProc)) return_cmd_error(STR_ERROR_SHIP_IN_THE_WAY); if (was_water && _game_mode != GM_EDITOR && !_settings_game.construction.enable_remove_water && !(flags & DC_ALLOW_REMOVE_WATER)) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER); diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index 235a571961..89045cc347 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -2479,8 +2479,6 @@ static CommandCost TerraformTile_Road(TileIndex tile, DoCommandFlag flags, int z /** 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(data); include(*affected_rvs, RoadVehicle::From(v)->First()); @@ -2637,7 +2635,7 @@ CommandCost CmdConvertRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 MarkTileDirtyByTile(tile); /* update power of train on this tile */ - FindVehicleOnPos(tile, &affected_rvs, &UpdateRoadVehPowerProc); + FindVehicleOnPos(tile, VEH_ROAD, &affected_rvs, &UpdateRoadVehPowerProc); if (IsRoadDepotTile(tile)) { /* Update build vehicle window related to this depot */ @@ -2710,8 +2708,8 @@ CommandCost CmdConvertRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 SetRoadType(tile, rtt, to_type); if (include_middle) SetRoadType(endtile, rtt, to_type); - FindVehicleOnPos(tile, &affected_rvs, &UpdateRoadVehPowerProc); - FindVehicleOnPos(endtile, &affected_rvs, &UpdateRoadVehPowerProc); + FindVehicleOnPos(tile, VEH_ROAD, &affected_rvs, &UpdateRoadVehPowerProc); + FindVehicleOnPos(endtile, VEH_ROAD, &affected_rvs, &UpdateRoadVehPowerProc); if (IsBridge(tile)) { MarkBridgeDirty(tile); diff --git a/src/roadstop.cpp b/src/roadstop.cpp index a7f25fe0c3..924280bc38 100644 --- a/src/roadstop.cpp +++ b/src/roadstop.cpp @@ -329,7 +329,7 @@ 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 & VS_CRASHED) != 0) return nullptr; + if (DirToDiagDir(v->direction) != rserh->dir || !v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0) return nullptr; RoadVehicle *rv = RoadVehicle::From(v); /* Don't add ones not in a road stop */ @@ -363,7 +363,7 @@ void RoadStop::Entry::Rebuild(const RoadStop *rs, int side) TileIndexDiff offset = abs(TileOffsByDiagDir(dir)); for (TileIndex tile = rs->xy; IsDriveThroughRoadStopContinuation(rs->xy, tile); tile += offset) { this->length += TILE_SIZE; - FindVehicleOnPos(tile, &rserh, FindVehiclesInRoadStop); + FindVehicleOnPos(tile, VEH_ROAD, &rserh, FindVehiclesInRoadStop); } this->occupied = 0; diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 253a973f97..135ed5e343 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -560,8 +560,7 @@ static Vehicle *EnumCheckRoadVehCrashTrain(Vehicle *v, void *data) { CheckRoadVehCrashTrainInfo *info = (CheckRoadVehCrashTrainInfo*) data; - if (v->type == VEH_TRAIN && - abs(v->z_pos - info->u->z_pos) <= 6 && + if (abs(v->z_pos - info->u->z_pos) <= 6 && abs(v->x_pos - info->u->x_pos) <= 4 && abs(v->y_pos - info->u->y_pos) <= 4) { info->found = true; @@ -617,7 +616,7 @@ static bool RoadVehCheckTrainCrash(RoadVehicle *v) if (!IsLevelCrossingTile(tile)) continue; CheckRoadVehCrashTrainInfo info(u); - FindVehicleOnPosXY(v->x_pos, v->y_pos, &info, EnumCheckRoadVehCrashTrain); + FindVehicleOnPosXY(v->x_pos, v->y_pos, VEH_TRAIN, &info, EnumCheckRoadVehCrashTrain); if (info.found) { RoadVehCrash(v); return true; @@ -671,8 +670,7 @@ static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data) short x_diff = v->x_pos - rvf->x; short y_diff = v->y_pos - rvf->y; - if (v->type == VEH_ROAD && - !v->IsInDepot() && + if (!v->IsInDepot() && abs(v->z_pos - rvf->veh->z_pos) < 6 && v->direction == rvf->dir && rvf->veh->First() != v->First() && @@ -705,10 +703,10 @@ 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); + FindVehicleOnPos(v->tile, VEH_ROAD, &rvf, EnumCheckRoadVehClose); + FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), VEH_ROAD, &rvf, EnumCheckRoadVehClose); } else { - FindVehicleOnPosXY(x, y, &rvf, EnumCheckRoadVehClose); + FindVehicleOnPosXY(x, y, VEH_ROAD, &rvf, EnumCheckRoadVehClose); } /* This code protects a roadvehicle from being blocked for ever @@ -822,7 +820,7 @@ 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; + return (v->First() == v && v != od->u && v != od->v) ? v : nullptr; } /** @@ -843,7 +841,7 @@ 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 HasVehicleOnPos(od->tile, VEH_ROAD, od, EnumFindVehBlockingOvertake); } static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u) diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index b2e3fce6c6..bd7f8c03d5 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -343,7 +343,7 @@ void Ship::UpdateDeltaXY() */ static Vehicle *EnsureNoVisibleShipProc(Vehicle *v, void *data) { - return v->type == VEH_SHIP && (v->vehstatus & VS_HIDDEN) == 0 ? v : nullptr; + return (v->vehstatus & VS_HIDDEN) == 0 ? v : nullptr; } static bool CheckShipLeaveDepot(Ship *v) @@ -369,7 +369,7 @@ 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, &EnsureNoVisibleShipProc)) return true; + if (HasVehicleOnPos(v->tile, VEH_SHIP, nullptr, &EnsureNoVisibleShipProc)) return true; TileIndex tile = v->tile; Axis axis = GetShipDepotAxis(tile); @@ -588,8 +588,6 @@ struct ShipCollideChecker { /** Helper function for collision avoidance. */ static Vehicle *FindShipOnTile(Vehicle *v, void *data) { - if (v->type != VEH_SHIP) return nullptr; - ShipCollideChecker *scc = (ShipCollideChecker*)data; /* Don't detect vehicles on different parallel tracks. */ @@ -624,8 +622,8 @@ static bool HandleSpeedOnAqueduct(Ship *v, TileIndex tile, TileIndex ramp) if (scc.search_tile == INVALID_TILE) return false; if (IsValidTile(scc.search_tile) && - (HasVehicleOnPos(ramp, &scc, FindShipOnTile) || - HasVehicleOnPos(GetOtherTunnelBridgeEnd(ramp), &scc, FindShipOnTile))) { + (HasVehicleOnPos(ramp, VEH_SHIP, &scc, FindShipOnTile) || + HasVehicleOnPos(GetOtherTunnelBridgeEnd(ramp), VEH_SHIP, &scc, FindShipOnTile))) { v->cur_speed /= 4; } return false; @@ -664,7 +662,7 @@ static void CheckDistanceBetweenShips(TileIndex tile, Ship *v, TrackBits tracks, scc.track_bits = track_bits; scc.search_tile = tile; - bool found = HasVehicleOnPos(tile, &scc, FindShipOnTile); + bool found = HasVehicleOnPos(tile, VEH_SHIP, &scc, FindShipOnTile); if (!found) { /* Bridge entrance */ @@ -675,7 +673,7 @@ static void CheckDistanceBetweenShips(TileIndex tile, Ship *v, TrackBits tracks, scc.search_tile = TileAddWrap(tile, ti.x, ti.y); if (scc.search_tile == INVALID_TILE) return; - found = HasVehicleOnPos(scc.search_tile, &scc, FindShipOnTile); + found = HasVehicleOnPos(scc.search_tile, VEH_SHIP, &scc, FindShipOnTile); } if (!found) { scc.track_bits = track_bits; @@ -683,7 +681,7 @@ static void CheckDistanceBetweenShips(TileIndex tile, Ship *v, TrackBits tracks, scc.search_tile = TileAddWrap(scc.search_tile, ti.x, ti.y); if (scc.search_tile == INVALID_TILE) return; - found = HasVehicleOnPos(scc.search_tile, &scc, FindShipOnTile); + found = HasVehicleOnPos(scc.search_tile, VEH_SHIP, &scc, FindShipOnTile); } if (found) { @@ -701,7 +699,7 @@ static void CheckDistanceBetweenShips(TileIndex tile, Ship *v, TrackBits tracks, TileIndex tile_check = TileAddWrap(tile, ti.x, ti.y); if (tile_check == INVALID_TILE) continue; - if (HasVehicleOnPos(tile_check, &scc, FindShipOnTile)) continue; + if (HasVehicleOnPos(tile_check, VEH_SHIP, &scc, FindShipOnTile)) continue; TrackBits bits = GetTileShipTrackStatus(tile_check) & DiagdirReachesTracks(_ship_search_directions[track][diagdir]); if (!IsDiagonalTrack(track)) bits &= TRACK_BIT_CROSS; // No 90 degree turns. diff --git a/src/signal.cpp b/src/signal.cpp index c9eb234536..b9a10feaf1 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -205,7 +205,7 @@ static uint _num_signals_evaluated; ///< Number of programmable pre-signals eval /** Check whether there is a train on rail, not in a depot */ static Vehicle *TrainOnTileEnum(Vehicle *v, void *) { - if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return nullptr; + if (Train::From(v)->track == TRACK_BIT_DEPOT) return nullptr; return v; } @@ -214,8 +214,8 @@ static Vehicle *TrainOnTileEnum(Vehicle *v, void *) static Vehicle *TrainInWormholeTileEnum(Vehicle *v, void *data) { /* Only look for front engine or last wagon. */ - if (v->type != VEH_TRAIN || (v->Previous() != nullptr && v->Next() != nullptr)) return nullptr; - TileIndex tile = *(TileIndex *)data; + if ((v->Previous() != nullptr && v->Next() != nullptr)) return nullptr; + TileIndex tile = (TileIndex) reinterpret_cast(data); if (tile != TileVirtXY(v->x_pos, v->y_pos)) return nullptr; if (!(Train::From(v)->track & TRACK_BIT_WORMHOLE) && !(Train::From(v)->track & GetAcrossTunnelBridgeTrackBits(tile))) return nullptr; return v; @@ -313,13 +313,13 @@ static SigInfo ExploreSegment(Owner owner) if (IsRailDepot(tile)) { if (enterdir == INVALID_DIAGDIR) { // from 'inside' - train just entered or left the depot - if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) info.flags |= SF_TRAIN; + if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, VEH_TRAIN, nullptr, &TrainOnTileEnum)) info.flags |= SF_TRAIN; exitdir = GetRailDepotDirection(tile); tile += TileOffsByDiagDir(exitdir); enterdir = ReverseDiagDir(exitdir); break; } else if (enterdir == GetRailDepotDirection(tile)) { // entered a depot - if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) info.flags |= SF_TRAIN; + if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, VEH_TRAIN, nullptr, &TrainOnTileEnum)) info.flags |= SF_TRAIN; continue; } else { continue; @@ -336,7 +336,7 @@ static SigInfo ExploreSegment(Owner owner) if (!(info.flags & SF_TRAIN) && EnsureNoTrainOnTrackBits(tile, tracks).Failed()) info.flags |= SF_TRAIN; } else { if (tracks_masked == TRACK_BIT_NONE) continue; // no incidating track - if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) info.flags |= SF_TRAIN; + if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, VEH_TRAIN, nullptr, &TrainOnTileEnum)) info.flags |= SF_TRAIN; } if (HasSignals(tile)) { // there is exactly one track - not zero, because there is exit from this tile @@ -390,7 +390,7 @@ static SigInfo ExploreSegment(Owner owner) if (DiagDirToAxis(enterdir) != GetRailStationAxis(tile)) continue; // different axis if (IsStationTileBlocked(tile)) continue; // 'eye-candy' station tile - if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) info.flags |= SF_TRAIN; + if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, VEH_TRAIN, nullptr, &TrainOnTileEnum)) info.flags |= SF_TRAIN; tile += TileOffsByDiagDir(exitdir); break; @@ -399,7 +399,7 @@ static SigInfo ExploreSegment(Owner owner) if (!IsOneSignalBlock(owner, GetTileOwner(tile))) continue; if (DiagDirToAxis(enterdir) == GetCrossingRoadAxis(tile)) continue; // different axis - if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) info.flags |= SF_TRAIN; + if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, VEH_TRAIN, nullptr, &TrainOnTileEnum)) info.flags |= SF_TRAIN; if (_settings_game.vehicle.safer_crossings) info.flags |= SF_PBS; tile += TileOffsByDiagDir(exitdir); break; @@ -422,7 +422,7 @@ static SigInfo ExploreSegment(Owner owner) return EnsureNoTrainOnTrackBits(tile, tracks & (~across_tracks)).Failed(); } } else { - return HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum); + return HasVehicleOnPos(tile, VEH_TRAIN, nullptr, &TrainOnTileEnum); } }; @@ -433,8 +433,8 @@ static SigInfo ExploreSegment(Owner owner) if (enterdir == INVALID_DIAGDIR) { // incoming from the wormhole, onto signal if (!(info.flags & SF_TRAIN) && IsTunnelBridgeSignalSimulationExit(tile)) { // tunnel entrance is ignored - if (HasVehicleOnPos(GetOtherTunnelBridgeEnd(tile), &tile, &TrainInWormholeTileEnum)) info.flags |= SF_TRAIN; - if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, &tile, &TrainInWormholeTileEnum)) info.flags |= SF_TRAIN; + if (HasVehicleOnPos(GetOtherTunnelBridgeEnd(tile), VEH_TRAIN, reinterpret_cast(tile), &TrainInWormholeTileEnum)) info.flags |= SF_TRAIN; + if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, VEH_TRAIN, reinterpret_cast(tile), &TrainInWormholeTileEnum)) info.flags |= SF_TRAIN; } if (IsTunnelBridgeSignalSimulationExit(tile) && !_tbuset.Add(tile, INVALID_TRACKDIR)) { info.flags |= SF_FULL; @@ -456,9 +456,9 @@ static SigInfo ExploreSegment(Owner owner) } } if (!(info.flags & SF_TRAIN)) { - if (HasVehicleOnPos(tile, &tile, &TrainInWormholeTileEnum)) info.flags |= SF_TRAIN; + if (HasVehicleOnPos(tile, VEH_TRAIN, reinterpret_cast(tile), &TrainInWormholeTileEnum)) info.flags |= SF_TRAIN; if (!(info.flags & SF_TRAIN) && IsTunnelBridgeSignalSimulationExit(tile)) { - if (HasVehicleOnPos(GetOtherTunnelBridgeEnd(tile), &tile, &TrainInWormholeTileEnum)) info.flags |= SF_TRAIN; + if (HasVehicleOnPos(GetOtherTunnelBridgeEnd(tile), VEH_TRAIN, reinterpret_cast(tile), &TrainInWormholeTileEnum)) info.flags |= SF_TRAIN; } } continue; diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index efe1e16095..2dcd32fac7 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -2092,16 +2092,14 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin 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; - } + /* 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; } @@ -2139,7 +2137,7 @@ static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags) /* 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) FindVehicleOnPos(tile, nullptr, &ClearRoadStopStatusEnum); + if (flags & DC_EXEC) FindVehicleOnPos(tile, VEH_ROAD, nullptr, &ClearRoadStopStatusEnum); } else { CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 951b1ac7e9..52aecf3fc4 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -1914,7 +1914,7 @@ void ReverseTrainSwapVeh(Train *v, int l, int r) */ static Vehicle *TrainOnTileEnum(Vehicle *v, void *) { - return (v->type == VEH_TRAIN) ? v : nullptr; + return v; } @@ -1926,12 +1926,12 @@ static Vehicle *TrainOnTileEnum(Vehicle *v, void *) */ static Vehicle *TrainApproachingCrossingEnum(Vehicle *v, void *data) { - if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return nullptr; + if ((v->vehstatus & VS_CRASHED)) return nullptr; Train *t = Train::From(v); if (!t->IsFrontEngine()) return nullptr; - TileIndex tile = *(TileIndex *)data; + TileIndex tile = (TileIndex) reinterpret_cast(data); if (TrainApproachingCrossingTile(t) != tile) return nullptr; @@ -1952,12 +1952,12 @@ 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 (HasVehicleOnPos(tile_from, VEH_TRAIN, reinterpret_cast(tile), &TrainApproachingCrossingEnum)) return true; dir = ReverseDiagDir(dir); tile_from = tile + TileOffsByDiagDir(dir); - return HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum); + return HasVehicleOnPos(tile_from, VEH_TRAIN, reinterpret_cast(tile), &TrainApproachingCrossingEnum); } /** Check if the crossing should be closed @@ -1966,7 +1966,7 @@ static bool TrainApproachingCrossing(TileIndex tile) static inline bool CheckLevelCrossing(TileIndex tile) { /* reserved || train on crossing || train approaching crossing */ - return HasCrossingReservation(tile) || HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum) || TrainApproachingCrossing(tile); + return HasCrossingReservation(tile) || HasVehicleOnPos(tile, VEH_TRAIN, nullptr, &TrainOnTileEnum) || TrainApproachingCrossing(tile); } /** @@ -3676,8 +3676,8 @@ static Vehicle *FindTrainCollideEnum(Vehicle *v, void *data) { TrainCollideChecker *tcc = (TrainCollideChecker*)data; - /* not a train or in depot */ - if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return nullptr; + /* not in depot */ + if (Train::From(v)->track == TRACK_BIT_DEPOT) return nullptr; if (_settings_game.vehicle.no_train_crash_other_company) { /* do not crash into trains of another company. */ @@ -3734,10 +3734,10 @@ 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); + FindVehicleOnPos(v->tile, VEH_TRAIN, &tcc, FindTrainCollideEnum); + FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), VEH_TRAIN, &tcc, FindTrainCollideEnum); } else { - FindVehicleOnPosXY(v->x_pos, v->y_pos, &tcc, FindTrainCollideEnum); + FindVehicleOnPosXY(v->x_pos, v->y_pos, VEH_TRAIN, &tcc, FindTrainCollideEnum); } /* any dead -> no crash */ @@ -3753,7 +3753,7 @@ static bool CheckTrainCollision(Train *v) static Vehicle *CheckTrainAtSignal(Vehicle *v, void *data) { - if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return nullptr; + if ((v->vehstatus & VS_CRASHED)) return nullptr; Train *t = Train::From(v); DiagDirection exitdir = *(DiagDirection *)data; @@ -3776,7 +3776,7 @@ struct FindSpaceBetweenTrainsChecker { static Vehicle *FindSpaceBetweenTrainsEnum(Vehicle *v, void *data) { /* Don't look at wagons between front and back of train. */ - if (v->type != VEH_TRAIN || (v->Previous() != nullptr && v->Next() != nullptr)) return nullptr; + if ((v->Previous() != nullptr && v->Next() != nullptr)) return nullptr; if (!IsDiagonalDirection(v->direction)) { /* Check for vehicles on non-across track pieces of custom bridge head */ @@ -3815,7 +3815,7 @@ static bool IsTooCloseBehindTrain(Vehicle *v, TileIndex tile, uint16 distance, b case DIAGDIR_NW: checker.pos = (TileY(tile) * TILE_SIZE) + TILE_UNIT_MASK; break; } - if (HasVehicleOnPos(t->tile, &checker, &FindSpaceBetweenTrainsEnum)) { + if (HasVehicleOnPos(t->tile, VEH_TRAIN, &checker, &FindSpaceBetweenTrainsEnum)) { /* Revert train if not going with tunnel direction. */ if (checker.direction != GetTunnelBridgeDirection(t->tile)) { SetBit(t->flags, VRF_REVERSING); @@ -3824,7 +3824,7 @@ static bool IsTooCloseBehindTrain(Vehicle *v, TileIndex tile, uint16 distance, b } /* Cover blind spot at end of tunnel bridge. */ if (check_endtile){ - if (HasVehicleOnPos(GetOtherTunnelBridgeEnd(t->tile), &checker, &FindSpaceBetweenTrainsEnum)) { + if (HasVehicleOnPos(GetOtherTunnelBridgeEnd(t->tile), VEH_TRAIN, &checker, &FindSpaceBetweenTrainsEnum)) { /* Revert train if not going with tunnel direction. */ if (checker.direction != GetTunnelBridgeDirection(t->tile)) { SetBit(t->flags, VRF_REVERSING); @@ -4097,7 +4097,7 @@ 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 (!HasVehicleOnPos(o_tile, VEH_TRAIN, &exitdir, &CheckTrainAtSignal)) return false; } } @@ -4546,7 +4546,7 @@ static Vehicle *CollectTrackbitsFromCrashedVehiclesEnum(Vehicle *v, void *data) { TrackBits *trackbits = (TrackBits *)data; - if (v->type == VEH_TRAIN && (v->vehstatus & VS_CRASHED) != 0) { + if ((v->vehstatus & VS_CRASHED) != 0) { if (Train::From(v)->track != TRACK_BIT_DEPOT) { *trackbits |= GetTrackbitsFromCrashedVehicle(Train::From(v)); } @@ -4619,7 +4619,7 @@ 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); + FindVehicleOnPos(tile, VEH_TRAIN, &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); diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 49827ca4d6..e701b54970 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -468,13 +468,13 @@ const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1; * Profiling results show that 0 is fastest. */ const int HASH_RES = 0; -static Vehicle *_vehicle_tile_hash[TOTAL_HASH_SIZE]; +static Vehicle *_vehicle_tile_hash[TOTAL_HASH_SIZE * 4]; -static Vehicle *VehicleFromTileHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc, bool find_first) +static Vehicle *VehicleFromTileHash(int xl, int yl, int xu, int yu, VehicleType type, 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 = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK]; + Vehicle *v = _vehicle_tile_hash[((x + y) & TOTAL_HASH_MASK) + (TOTAL_HASH_SIZE * type)]; for (; v != nullptr; v = v->hash_tile_next) { Vehicle *a = proc(v, data); if (find_first && a != nullptr) return a; @@ -499,7 +499,7 @@ static Vehicle *VehicleFromTileHash(int xl, int yl, int xu, int yu, void *data, * 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) +Vehicle *VehicleFromPosXY(int x, int y, VehicleType type, void *data, VehicleFromPosProc *proc, bool find_first) { const int COLL_DIST = 6; @@ -509,42 +509,7 @@ static Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *p 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 VehicleFromTileHash(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); -} - -/** - * Checks whether a vehicle in on a specific location. It will call proc for - * vehicles until it returns non-nullptr. - * @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-nullptr. - */ -bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc) -{ - return VehicleFromPosXY(x, y, data, proc, true) != nullptr; + return VehicleFromTileHash(xl, yl, xu, yu, type, data, proc, find_first); } /** @@ -557,12 +522,12 @@ bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc) * 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) +Vehicle *VehicleFromPos(TileIndex tile, VehicleType type, 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]; + Vehicle *v = _vehicle_tile_hash[((x + y) & TOTAL_HASH_MASK) + (TOTAL_HASH_SIZE * type)]; for (; v != nullptr; v = v->hash_tile_next) { if (v->tile != tile) continue; @@ -574,36 +539,18 @@ static Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *p } /** - * 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". + * 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. */ -void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc) +static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data) { - VehicleFromPos(tile, data, proc, false); -} + int z = static_cast(reinterpret_cast(data)); -/** - * 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; + if (v->z_pos > z) return nullptr; + + return v; } /** @@ -612,11 +559,11 @@ bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc) * @param data Pointer to height data. * @return \a v if conditions are met, else \c nullptr. */ -static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data) +static Vehicle *EnsureNoAircraftProcZ(Vehicle *v, void *data) { - int z = *(int*)data; + int z = static_cast(reinterpret_cast(data)); - if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return nullptr; + if (v->subtype == AIR_SHADOW) return nullptr; if (v->z_pos > z) return nullptr; return v; @@ -635,27 +582,21 @@ 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_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type); + if (VehicleFromPos(tile, VEH_TRAIN, reinterpret_cast(static_cast(z)), &EnsureNoVehicleProcZ, true) != nullptr) { + return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY); + } + if (VehicleFromPos(tile, VEH_ROAD, reinterpret_cast(static_cast(z)), &EnsureNoVehicleProcZ, true) != nullptr) { + return_cmd_error(STR_ERROR_ROAD_VEHICLE_IN_THE_WAY); + } + if (VehicleFromPos(tile, VEH_SHIP, reinterpret_cast(static_cast(z)), &EnsureNoVehicleProcZ, true) != nullptr) { + return_cmd_error(STR_ERROR_SHIP_IN_THE_WAY); + } + if (VehicleFromPos(tile, VEH_AIRCRAFT, reinterpret_cast(static_cast(z)), &EnsureNoAircraftProcZ, true) != nullptr) { + return_cmd_error(STR_ERROR_AIRCRAFT_IN_THE_WAY); + } return CommandCost(); } -/** - * Callback that returns 'real' vehicles lower or at height \c *(int*)data, for road vehicles. - * @param v Vehicle to examine. - * @param data Pointer to height data. - * @return \a v if conditions are met, else \c nullptr. - */ -static Vehicle *EnsureNoRoadVehicleProcZ(Vehicle *v, void *data) -{ - int z = *(int*)data; - - if (v->type != VEH_ROAD) return nullptr; - if (v->z_pos > z) return nullptr; - - return v; -} - /** * Ensure there is no road vehicle at the ground at the given position. * @param tile Position to examine. @@ -669,7 +610,7 @@ CommandCost EnsureNoRoadVehicleOnGround(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, &EnsureNoRoadVehicleProcZ, true); + Vehicle *v = VehicleFromPos(tile, VEH_ROAD, reinterpret_cast(static_cast(z)), &EnsureNoVehicleProcZ, true); if (v != nullptr) return_cmd_error(STR_ERROR_ROAD_VEHICLE_IN_THE_WAY); return CommandCost(); } @@ -684,7 +625,6 @@ struct GetVehicleTunnelBridgeProcData { static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data) { const GetVehicleTunnelBridgeProcData *info = (GetVehicleTunnelBridgeProcData*) data; - if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return nullptr; if (v == info->v) return nullptr; if (v->type == VEH_TRAIN && info->across_only && IsBridge(info->t)) { @@ -713,10 +653,11 @@ CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle data.v = ignore; data.t = tile; data.across_only = across_only; - Vehicle *v = VehicleFromPos(tile, &data, &GetVehicleTunnelBridgeProc, true); + VehicleType type = static_cast(GetTunnelBridgeTransportType(tile)); + Vehicle *v = VehicleFromPos(tile, type, &data, &GetVehicleTunnelBridgeProc, true); if (v == nullptr) { data.t = endtile; - v = VehicleFromPos(endtile, &data, &GetVehicleTunnelBridgeProc, true); + v = VehicleFromPos(endtile, type, &data, &GetVehicleTunnelBridgeProc, true); } if (v != nullptr) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type); @@ -727,8 +668,6 @@ 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 (rail_bits & TRACK_BIT_WORMHOLE) { if (t->track & TRACK_BIT_WORMHOLE) return v; @@ -755,7 +694,7 @@ 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); + Vehicle *v = VehicleFromPos(tile, VEH_TRAIN, &track_bits, &EnsureNoTrainOnTrackProc, true); if (v != nullptr) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type); return CommandCost(); } @@ -770,7 +709,7 @@ void UpdateVehicleTileHash(Vehicle *v, bool remove) } else { int x = GB(TileX(v->tile), HASH_RES, HASH_BITS); int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS; - new_hash = &_vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK]; + new_hash = &_vehicle_tile_hash[((x + y) & TOTAL_HASH_MASK) + (TOTAL_HASH_SIZE * v->type)]; } if (old_hash == new_hash) return; @@ -799,7 +738,7 @@ bool ValidateVehicleTileHash(const Vehicle *v) int x = GB(TileX(v->tile), HASH_RES, HASH_BITS); int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS; - return v->hash_tile_current == &_vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK]; + return v->hash_tile_current == &_vehicle_tile_hash[((x + y) & TOTAL_HASH_MASK) + (TOTAL_HASH_SIZE * v->type)]; } static Vehicle *_vehicle_viewport_hash[1 << (GEN_HASHX_BITS + GEN_HASHY_BITS)]; diff --git a/src/vehicle_func.h b/src/vehicle_func.h index 2c889dde15..4927edfdfe 100644 --- a/src/vehicle_func.h +++ b/src/vehicle_func.h @@ -40,10 +40,79 @@ 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); + +/** + * 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". + */ +inline void FindVehicleOnPos(TileIndex tile, VehicleType type, void *data, VehicleFromPosProc *proc) +{ + extern Vehicle *VehicleFromPos(TileIndex tile, VehicleType type, void *data, VehicleFromPosProc *proc, bool find_first); + VehicleFromPos(tile, type, 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. + */ +inline bool HasVehicleOnPos(TileIndex tile, VehicleType type, void *data, VehicleFromPosProc *proc) +{ + extern Vehicle *VehicleFromPos(TileIndex tile, VehicleType type, void *data, VehicleFromPosProc *proc, bool find_first); + return VehicleFromPos(tile, type, data, proc, true) != nullptr; +} + +/** + * 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". + */ +inline void FindVehicleOnPosXY(int x, int y, VehicleType type, void *data, VehicleFromPosProc *proc) +{ + extern Vehicle *VehicleFromPosXY(int x, int y, VehicleType type, void *data, VehicleFromPosProc *proc, bool find_first); + VehicleFromPosXY(x, y, type, data, proc, false); +} + +/** + * Checks whether a vehicle in on a specific location. It will call proc for + * vehicles until it returns non-nullptr. + * @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-nullptr. + */ +inline bool HasVehicleOnPosXY(int x, int y, VehicleType type, void *data, VehicleFromPosProc *proc) +{ + extern Vehicle *VehicleFromPosXY(int x, int y, VehicleType type, void *data, VehicleFromPosProc *proc, bool find_first); + return VehicleFromPosXY(x, y, type, data, proc, true) != nullptr; +} + void CallVehicleTicks(); uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *colour); uint8 CalcPercentVehicleFilledOfCargo(const Vehicle *v, CargoID cargo); diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp index ab6fbdcce5..4b345fdfe4 100644 --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -1004,6 +1004,30 @@ static void FloodVehicle(Vehicle *v) if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, 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. + */ +static Vehicle *FloodAircraftProc(Vehicle *v, void *data) +{ + if ((v->vehstatus & VS_CRASHED) != 0) return nullptr; + + if (!IsAirportTile(v->tile) || GetTileMaxZ(v->tile) != 0) return nullptr; + if (v->subtype == AIR_SHADOW) return nullptr; + + /* We compare v->z_pos against delta_z + 1 because the shadow + * is at delta_z and the actual aircraft at delta_z + 1. */ + const Station *st = Station::GetByTile(v->tile); + const AirportFTAClass *airport = st->airport.GetFTA(); + if (v->z_pos != airport->delta_z + 1) return nullptr; + + FloodVehicle(v); + + return nullptr; +} + /** * 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. @@ -1014,35 +1038,20 @@ static Vehicle *FloodVehicleProc(Vehicle *v, void *data) { if ((v->vehstatus & VS_CRASHED) != 0) return nullptr; - switch (v->type) { - default: break; - - case VEH_AIRCRAFT: { - if (!IsAirportTile(v->tile) || GetTileMaxZ(v->tile) != 0) break; - if (v->subtype == AIR_SHADOW) break; - - /* We compare v->z_pos against delta_z + 1 because the shadow - * is at delta_z and the actual aircraft at delta_z + 1. */ - const Station *st = Station::GetByTile(v->tile); - const AirportFTAClass *airport = st->airport.GetFTA(); - if (v->z_pos != airport->delta_z + 1) break; - - FloodVehicle(v); - break; - } - - case VEH_TRAIN: - case VEH_ROAD: { - int z = *(int*)data; - if (v->z_pos > z) break; - FloodVehicle(v->First()); - break; - } - } + int z = static_cast(reinterpret_cast(data)); + if (v->z_pos > z) return nullptr; + FloodVehicle(v->First()); return nullptr; } +static void FindFloodVehicle(TileIndex tile, int z) +{ + FindVehicleOnPos(tile, VEH_AIRCRAFT, reinterpret_cast(static_cast(z)), &FloodAircraftProc); + FindVehicleOnPos(tile, VEH_TRAIN, reinterpret_cast(static_cast(z)), &FloodVehicleProc); + FindVehicleOnPos(tile, VEH_ROAD, reinterpret_cast(static_cast(z)), &FloodVehicleProc); +} + /** * Finds a vehicle to flood. * It does not find vehicles that are already crashed on bridges, i.e. flooded. @@ -1055,7 +1064,7 @@ static void FloodVehicles(TileIndex tile) if (IsAirportTile(tile)) { const Station *st = Station::GetByTile(tile); TILE_AREA_LOOP(tile, st->airport) { - if (st->TileBelongsToAirport(tile)) FindVehicleOnPos(tile, &z, &FloodVehicleProc); + if (st->TileBelongsToAirport(tile)) FindFloodVehicle(tile, z); } /* No vehicle could be flooded on this airport anymore */ @@ -1063,15 +1072,15 @@ static void FloodVehicles(TileIndex tile) } if (!IsBridgeTile(tile)) { - FindVehicleOnPos(tile, &z, &FloodVehicleProc); + FindFloodVehicle(tile, z); return; } TileIndex end = GetOtherBridgeEnd(tile); z = GetBridgePixelHeight(tile); - FindVehicleOnPos(tile, &z, &FloodVehicleProc); - FindVehicleOnPos(end, &z, &FloodVehicleProc); + FindFloodVehicle(tile, z); + FindFloodVehicle(end, z); } /**