mirror of https://github.com/OpenTTD/OpenTTD
Codechange: Replace FindVehicleOnPosXY/HasVehicleOnPosXY with VehiclesNearTileXY/HasVehicleNearTileXY.
parent
9f1c04c0e1
commit
98ac75e74f
|
@ -511,22 +511,6 @@ static bool RoadVehIsCrashed(RoadVehicle *v)
|
||||||
return true;
|
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 RoadVehicle::Crash(bool flooded)
|
||||||
{
|
{
|
||||||
uint victims = this->GroundVehicleBase::Crash(flooded);
|
uint victims = this->GroundVehicleBase::Crash(flooded);
|
||||||
|
@ -569,7 +553,10 @@ static bool RoadVehCheckTrainCrash(RoadVehicle *v)
|
||||||
|
|
||||||
if (!IsLevelCrossingTile(tile)) continue;
|
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);
|
RoadVehCrash(v);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -612,25 +599,23 @@ struct RoadVehFindData {
|
||||||
Direction dir;
|
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_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 };
|
||||||
static const int8_t dist_y[] = { -4, -1, 4, 8, 4, 1, -4, -8 };
|
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 x_diff = v->x_pos - rvf->x;
|
||||||
int y_diff = v->y_pos - rvf->y;
|
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. */
|
/* 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. */
|
/* 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. */
|
/* We 'return' the closest vehicle, in distance and then VehicleID as tie-breaker. */
|
||||||
uint diff = abs(x_diff) + abs(y_diff);
|
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) {
|
auto IsCloseOnAxis = [](int dist, int diff) {
|
||||||
if (dist < 0) return diff > dist && diff <= 0;
|
if (dist < 0) return diff > dist && diff <= 0;
|
||||||
|
@ -641,8 +626,6 @@ static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data)
|
||||||
rvf->best = v;
|
rvf->best = v;
|
||||||
rvf->best_diff = diff;
|
rvf->best_diff = diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction dir, bool update_blocked_ctr = true)
|
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) {
|
if (front->state == RVSB_WORMHOLE) {
|
||||||
for (Vehicle *u : VehiclesOnTile(v->tile)) {
|
for (Vehicle *u : VehiclesOnTile(v->tile)) {
|
||||||
EnumCheckRoadVehClose(u, &rvf);
|
FindClosestBlockingRoadVeh(u, &rvf);
|
||||||
}
|
}
|
||||||
for (Vehicle *u : VehiclesOnTile(GetOtherTunnelBridgeEnd(v->tile))) {
|
for (Vehicle *u : VehiclesOnTile(GetOtherTunnelBridgeEnd(v->tile))) {
|
||||||
EnumCheckRoadVehClose(u, &rvf);
|
FindClosestBlockingRoadVeh(u, &rvf);
|
||||||
}
|
}
|
||||||
} else {
|
} 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
|
/* This code protects a roadvehicle from being blocked for ever
|
||||||
|
|
|
@ -3162,56 +3162,45 @@ static uint TrainCrashed(Train *v)
|
||||||
return victims;
|
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.
|
* Collision test function.
|
||||||
* @param v %Train vehicle to test collision with.
|
* @param v %Train vehicle to test collision with.
|
||||||
* @param data %Train being examined.
|
* @param t %Train being examined.
|
||||||
* @return \c nullptr (always continue search)
|
* @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 */
|
/* 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. */
|
/* 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 */
|
/* get first vehicle now to make most usual checks faster */
|
||||||
Train *coll = Train::From(v)->First();
|
Train *coll = Train::From(v)->First();
|
||||||
|
|
||||||
/* can't collide with own wagons */
|
/* 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 x_diff = v->x_pos - t->x_pos;
|
||||||
int y_diff = v->y_pos - tcc->v->y_pos;
|
int y_diff = v->y_pos - t->y_pos;
|
||||||
|
|
||||||
/* Do fast calculation to check whether trains are not in close vicinity
|
/* Do fast calculation to check whether trains are not in close vicinity
|
||||||
* and quickly reject trains distant enough for any collision.
|
* and quickly reject trains distant enough for any collision.
|
||||||
* Differences are shifted by 7, mapping range [-7 .. 8] into [0 .. 15]
|
* Differences are shifted by 7, mapping range [-7 .. 8] into [0 .. 15]
|
||||||
* Differences are then ORed and then we check for any higher bits */
|
* Differences are then ORed and then we check for any higher bits */
|
||||||
uint hash = (y_diff + 7) | (x_diff + 7);
|
uint hash = (y_diff + 7) | (x_diff + 7);
|
||||||
if (hash & ~15) return nullptr;
|
if (hash & ~15) return 0;
|
||||||
|
|
||||||
/* Slower check using multiplication */
|
/* 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;
|
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 nullptr;
|
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 */
|
/* 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 */
|
/* crash both trains */
|
||||||
tcc->num += TrainCrashed(tcc->v);
|
return TrainCrashed(t) + TrainCrashed(coll);
|
||||||
tcc->num += TrainCrashed(coll);
|
|
||||||
|
|
||||||
return nullptr; // continue searching
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3228,26 +3217,26 @@ static bool CheckTrainCollision(Train *v)
|
||||||
|
|
||||||
assert(v->track == TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile);
|
assert(v->track == TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile);
|
||||||
|
|
||||||
TrainCollideChecker tcc;
|
uint num_victims = 0;
|
||||||
tcc.v = v;
|
|
||||||
tcc.num = 0;
|
|
||||||
|
|
||||||
/* find colliding vehicles */
|
/* find colliding vehicles */
|
||||||
if (v->track == TRACK_BIT_WORMHOLE) {
|
if (v->track == TRACK_BIT_WORMHOLE) {
|
||||||
for (Vehicle *u : VehiclesOnTile(v->tile)) {
|
for (Vehicle *u : VehiclesOnTile(v->tile)) {
|
||||||
FindTrainCollideEnum(u, &tcc);
|
num_victims += CheckTrainCollision(u, v);
|
||||||
}
|
}
|
||||||
for (Vehicle *u : VehiclesOnTile(GetOtherTunnelBridgeEnd(v->tile))) {
|
for (Vehicle *u : VehiclesOnTile(GetOtherTunnelBridgeEnd(v->tile))) {
|
||||||
FindTrainCollideEnum(u, &tcc);
|
num_victims += CheckTrainCollision(u, v);
|
||||||
}
|
}
|
||||||
} else {
|
} 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 */
|
/* 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);
|
ModifyStationRatingAround(v->tile, v->owner, -160, 30);
|
||||||
if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_13_TRAIN_COLLISION, v);
|
if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_13_TRAIN_COLLISION, v);
|
||||||
|
|
Loading…
Reference in New Issue