diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 8e9b750c8c..fe8ccf1adf 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -511,22 +511,6 @@ static bool RoadVehIsCrashed(RoadVehicle *v) return true; } -/** - * Check routine whether a road and a train vehicle have collided. - * @param v %Train vehicle to test. - * @param data Road vehicle to test. - * @return %Train vehicle if the vehicles collided, else \c nullptr. - */ -static Vehicle *EnumCheckRoadVehCrashTrain(Vehicle *v, void *data) -{ - const Vehicle *u = (Vehicle*)data; - - return (v->type == VEH_TRAIN && - abs(v->z_pos - u->z_pos) <= 6 && - abs(v->x_pos - u->x_pos) <= 4 && - abs(v->y_pos - u->y_pos) <= 4) ? v : nullptr; -} - uint RoadVehicle::Crash(bool flooded) { uint victims = this->GroundVehicleBase::Crash(flooded); @@ -569,7 +553,10 @@ static bool RoadVehCheckTrainCrash(RoadVehicle *v) if (!IsLevelCrossingTile(tile)) continue; - if (HasVehicleOnPosXY(v->x_pos, v->y_pos, u, EnumCheckRoadVehCrashTrain)) { + if (HasVehicleNearTileXY(v->x_pos, v->y_pos, [&u](const Vehicle *t) { + return t->type == VEH_TRAIN && abs(t->z_pos - u->z_pos) <= 6 && + abs(t->x_pos - u->x_pos) <= 4 && abs(t->y_pos - u->y_pos) <= 4; + })) { RoadVehCrash(v); return true; } @@ -612,25 +599,23 @@ struct RoadVehFindData { Direction dir; }; -static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data) +static void FindClosestBlockingRoadVeh(Vehicle *v, RoadVehFindData *rvf) { static const int8_t dist_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 }; static const int8_t dist_y[] = { -4, -1, 4, 8, 4, 1, -4, -8 }; - RoadVehFindData *rvf = (RoadVehFindData*)data; - int x_diff = v->x_pos - rvf->x; int y_diff = v->y_pos - rvf->y; /* Not a close Road vehicle when it's not a road vehicle, in the depot, or ourself. */ - if (v->type != VEH_ROAD || v->IsInDepot() || rvf->veh->First() == v->First()) return nullptr; + if (v->type != VEH_ROAD || v->IsInDepot() || rvf->veh->First() == v->First()) return; /* Not close when at a different height or when going in a different direction. */ - if (abs(v->z_pos - rvf->veh->z_pos) >= 6 || v->direction != rvf->dir) return nullptr; + if (abs(v->z_pos - rvf->veh->z_pos) >= 6 || v->direction != rvf->dir) return; /* We 'return' the closest vehicle, in distance and then VehicleID as tie-breaker. */ uint diff = abs(x_diff) + abs(y_diff); - if (diff > rvf->best_diff || (diff == rvf->best_diff && v->index > rvf->best->index)) return nullptr; + if (diff > rvf->best_diff || (diff == rvf->best_diff && v->index > rvf->best->index)) return; auto IsCloseOnAxis = [](int dist, int diff) { if (dist < 0) return diff > dist && diff <= 0; @@ -641,8 +626,6 @@ static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data) rvf->best = v; rvf->best_diff = diff; } - - return nullptr; } static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction dir, bool update_blocked_ctr = true) @@ -660,13 +643,15 @@ static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction d if (front->state == RVSB_WORMHOLE) { for (Vehicle *u : VehiclesOnTile(v->tile)) { - EnumCheckRoadVehClose(u, &rvf); + FindClosestBlockingRoadVeh(u, &rvf); } for (Vehicle *u : VehiclesOnTile(GetOtherTunnelBridgeEnd(v->tile))) { - EnumCheckRoadVehClose(u, &rvf); + FindClosestBlockingRoadVeh(u, &rvf); } } else { - FindVehicleOnPosXY(x, y, &rvf, EnumCheckRoadVehClose); + for (Vehicle *u : VehiclesNearTileXY(x, y)) { + FindClosestBlockingRoadVeh(u, &rvf); + } } /* This code protects a roadvehicle from being blocked for ever diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 2332656dd7..765e084ba8 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -3162,56 +3162,45 @@ static uint TrainCrashed(Train *v) return victims; } -/** Temporary data storage for testing collisions. */ -struct TrainCollideChecker { - Train *v; ///< %Vehicle we are testing for collision. - uint num; ///< Total number of victims if train collided. -}; - /** * Collision test function. * @param v %Train vehicle to test collision with. - * @param data %Train being examined. - * @return \c nullptr (always continue search) + * @param t %Train being examined. + * @return Number of victims. */ -static Vehicle *FindTrainCollideEnum(Vehicle *v, void *data) +static uint CheckTrainCollision(Vehicle *v, Train *t) { - TrainCollideChecker *tcc = (TrainCollideChecker*)data; - /* not a train or in depot */ - if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return nullptr; + if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return 0; /* do not crash into trains of another company. */ - if (v->owner != tcc->v->owner) return nullptr; + if (v->owner != t->owner) return 0; /* get first vehicle now to make most usual checks faster */ Train *coll = Train::From(v)->First(); /* can't collide with own wagons */ - if (coll == tcc->v) return nullptr; + if (coll == t) return 0; - int x_diff = v->x_pos - tcc->v->x_pos; - int y_diff = v->y_pos - tcc->v->y_pos; + int x_diff = v->x_pos - t->x_pos; + int y_diff = v->y_pos - t->y_pos; /* Do fast calculation to check whether trains are not in close vicinity * and quickly reject trains distant enough for any collision. * Differences are shifted by 7, mapping range [-7 .. 8] into [0 .. 15] * Differences are then ORed and then we check for any higher bits */ uint hash = (y_diff + 7) | (x_diff + 7); - if (hash & ~15) return nullptr; + if (hash & ~15) return 0; /* Slower check using multiplication */ - int min_diff = (Train::From(v)->gcache.cached_veh_length + 1) / 2 + (tcc->v->gcache.cached_veh_length + 1) / 2 - 1; - if (x_diff * x_diff + y_diff * y_diff > min_diff * min_diff) return nullptr; + int min_diff = (Train::From(v)->gcache.cached_veh_length + 1) / 2 + (t->gcache.cached_veh_length + 1) / 2 - 1; + if (x_diff * x_diff + y_diff * y_diff > min_diff * min_diff) return 0; /* Happens when there is a train under bridge next to bridge head */ - if (abs(v->z_pos - tcc->v->z_pos) > 5) return nullptr; + if (abs(v->z_pos - t->z_pos) > 5) return 0; /* crash both trains */ - tcc->num += TrainCrashed(tcc->v); - tcc->num += TrainCrashed(coll); - - return nullptr; // continue searching + return TrainCrashed(t) + TrainCrashed(coll); } /** @@ -3228,26 +3217,26 @@ static bool CheckTrainCollision(Train *v) assert(v->track == TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile); - TrainCollideChecker tcc; - tcc.v = v; - tcc.num = 0; + uint num_victims = 0; /* find colliding vehicles */ if (v->track == TRACK_BIT_WORMHOLE) { for (Vehicle *u : VehiclesOnTile(v->tile)) { - FindTrainCollideEnum(u, &tcc); + num_victims += CheckTrainCollision(u, v); } for (Vehicle *u : VehiclesOnTile(GetOtherTunnelBridgeEnd(v->tile))) { - FindTrainCollideEnum(u, &tcc); + num_victims += CheckTrainCollision(u, v); } } else { - FindVehicleOnPosXY(v->x_pos, v->y_pos, &tcc, FindTrainCollideEnum); + for (Vehicle *u : VehiclesNearTileXY(v->x_pos, v->y_pos)) { + num_victims += CheckTrainCollision(u, v); + } } /* any dead -> no crash */ - if (tcc.num == 0) return false; + if (num_victims == 0) return false; - AddTileNewsItem(GetEncodedString(STR_NEWS_TRAIN_CRASH, tcc.num), NewsType::Accident, v->tile); + AddTileNewsItem(GetEncodedString(STR_NEWS_TRAIN_CRASH, num_victims), NewsType::Accident, v->tile); ModifyStationRatingAround(v->tile, v->owner, -160, 30); if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_13_TRAIN_COLLISION, v);