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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue