summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsmatz <smatz@openttd.org>2009-06-24 23:59:20 +0000
committersmatz <smatz@openttd.org>2009-06-24 23:59:20 +0000
commit029fb9bdee86302f3265998577a7827690b86ac9 (patch)
tree841f3f461c42944447a79498520cde1171c83acc /src
parentd45b27c46be4f4d7662c9f7f21989246537f7ef1 (diff)
downloadopenttd-029fb9bdee86302f3265998577a7827690b86ac9.tar.xz
(svn r16652) -Codechange: use less strict, but faster check for quickly bailing out in FindTrainCollideEnum() (Bilbo)
-Codechange: shuffle the code a bit
Diffstat (limited to 'src')
-rw-r--r--src/train_cmd.cpp75
1 files changed, 39 insertions, 36 deletions
diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp
index 949f96625..ac518eb2b 100644
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -3530,6 +3530,16 @@ static uint CountPassengersInTrain(const Train *v)
*/
static uint TrainCrashed(Train *v)
{
+ /* Try to re-reserve track under already crashed train too */
+ for (const Train *u = v; u != NULL; u = u->Next()) {
+ TrackBits trackbits = u->track;
+ if (trackbits == TRACK_BIT_WORMHOLE) {
+ /* Vehicle is inside a wormhole, v->track contains no useful value then. */
+ trackbits = DiagDirToDiagTrackBits(GetTunnelBridgeDirection(u->tile));
+ }
+ TryReserveRailTrack(u->tile, TrackBitsToTrack(trackbits));
+ }
+
/* do not crash train twice */
if (v->vehstatus & VS_CRASHED) return 0;
@@ -3543,51 +3553,44 @@ static uint TrainCrashed(Train *v)
}
struct TrainCollideChecker {
- Vehicle *v; ///< vehicle we are testing for collision
- uint num; ///< number of dead if train collided
+ Train *v; ///< vehicle we are testing for collision
+ uint num; ///< number of victims if train collided
};
static Vehicle *FindTrainCollideEnum(Vehicle *v, void *data)
{
TrainCollideChecker *tcc = (TrainCollideChecker*)data;
- if (v->type != VEH_TRAIN) return NULL;
+ /* not a train or in depot */
+ if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return NULL;
/* get first vehicle now to make most usual checks faster */
- Vehicle *coll = v->First();
-
- /* can't collide with own wagons && can't crash in depot && the same height level */
- if (coll != tcc->v && Train::From(v)->track != TRACK_BIT_DEPOT && abs(v->z_pos - tcc->v->z_pos) < 6) {
- int x_diff = v->x_pos - tcc->v->x_pos;
- int y_diff = v->y_pos - tcc->v->y_pos;
-
- /* Needed to disable possible crash of competitor train in station by building diagonal track at its end.
- * The second check is false when (abs(first), abs(second)) is: a) 5, 0 b) 4, <=3 c) 3, <=4, d) 2-, <=5
- * Sum of these two is at most 2 + 5 == 4 + 3 == 7. So we can just test if sum of abs() is > 7 to prevent
- * multiplying. Simply, when sum of abs() is >= 8, the sum of squares can't be <= 25.
- * Even gcc3.4 seems to do abs() branchless (using arithmetics or conditional moves). */
- if (abs(x_diff) + abs(y_diff) > 7 || x_diff * x_diff + y_diff * y_diff > 25) return NULL;
-
- /* crash both trains */
- tcc->num += TrainCrashed(Train::From(tcc->v));
- tcc->num += TrainCrashed(Train::From(coll));
-
- /* Try to reserve all tiles directly under the crashed trains.
- * As there might be more than two trains involved, we have to do that for all vehicles */
- const Train *u;
- FOR_ALL_TRAINS(u) {
- if ((u->vehstatus & VS_CRASHED) && u->track != TRACK_BIT_DEPOT) {
- TrackBits trackbits = u->track;
- if (trackbits == TRACK_BIT_WORMHOLE) {
- /* Vehicle is inside a wormhole, v->track contains no useful value then. */
- trackbits = DiagDirToDiagTrackBits(GetTunnelBridgeDirection(u->tile));
- }
- TryReserveRailTrack(u->tile, TrackBitsToTrack(trackbits));
- }
- }
- }
+ Train *coll = Train::From(v)->First();
- return NULL;
+ /* can't collide with own wagons */
+ if (coll == tcc->v) return NULL;
+
+ int x_diff = v->x_pos - tcc->v->x_pos;
+ int y_diff = v->y_pos - tcc->v->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 NULL;
+
+ /* Slower check using multiplication */
+ if (x_diff * x_diff + y_diff * y_diff > 25) return NULL;
+
+ /* Happens when there is a train under bridge next to bridge head */
+ if (abs(v->z_pos - tcc->v->z_pos) > 5) return NULL;
+
+ /* crash both trains */
+ tcc->num += TrainCrashed(tcc->v);
+ tcc->num += TrainCrashed(coll);
+
+ return NULL; // continue searching
}
/**