1
0
Fork 0

Codechange: Replace FindVehicleOnPosXY/HasVehicleOnPosXY with VehiclesNearTileXY/HasVehicleNearTileXY.

pull/12131/head
frosch 2025-04-25 17:47:25 +02:00 committed by frosch
parent 9f1c04c0e1
commit 98ac75e74f
2 changed files with 34 additions and 60 deletions

View File

@ -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

View File

@ -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);