Mercurial > hg > openttd
comparison src/train_cmd.cpp @ 12237:52ee820c1243 draft
(svn r16652) -Codechange: use less strict, but faster check for quickly bailing out in FindTrainCollideEnum() (Bilbo)
-Codechange: shuffle the code a bit
author | smatz <smatz@openttd.org> |
---|---|
date | Wed, 24 Jun 2009 23:59:20 +0000 |
parents | 2f16fe37d1b8 |
children | 75aa2b403c34 |
comparison
equal
deleted
inserted
replaced
12236:cc6e71b54c8a | 12237:52ee820c1243 |
---|---|
3528 * @param v first vehicle of chain | 3528 * @param v first vehicle of chain |
3529 * @return number of victims (including 2 drivers; zero if train was already crashed) | 3529 * @return number of victims (including 2 drivers; zero if train was already crashed) |
3530 */ | 3530 */ |
3531 static uint TrainCrashed(Train *v) | 3531 static uint TrainCrashed(Train *v) |
3532 { | 3532 { |
3533 /* Try to re-reserve track under already crashed train too */ | |
3534 for (const Train *u = v; u != NULL; u = u->Next()) { | |
3535 TrackBits trackbits = u->track; | |
3536 if (trackbits == TRACK_BIT_WORMHOLE) { | |
3537 /* Vehicle is inside a wormhole, v->track contains no useful value then. */ | |
3538 trackbits = DiagDirToDiagTrackBits(GetTunnelBridgeDirection(u->tile)); | |
3539 } | |
3540 TryReserveRailTrack(u->tile, TrackBitsToTrack(trackbits)); | |
3541 } | |
3542 | |
3533 /* do not crash train twice */ | 3543 /* do not crash train twice */ |
3534 if (v->vehstatus & VS_CRASHED) return 0; | 3544 if (v->vehstatus & VS_CRASHED) return 0; |
3535 | 3545 |
3536 /* two drivers + passengers */ | 3546 /* two drivers + passengers */ |
3537 uint num = 2 + CountPassengersInTrain(v); | 3547 uint num = 2 + CountPassengersInTrain(v); |
3541 | 3551 |
3542 return num; | 3552 return num; |
3543 } | 3553 } |
3544 | 3554 |
3545 struct TrainCollideChecker { | 3555 struct TrainCollideChecker { |
3546 Vehicle *v; ///< vehicle we are testing for collision | 3556 Train *v; ///< vehicle we are testing for collision |
3547 uint num; ///< number of dead if train collided | 3557 uint num; ///< number of victims if train collided |
3548 }; | 3558 }; |
3549 | 3559 |
3550 static Vehicle *FindTrainCollideEnum(Vehicle *v, void *data) | 3560 static Vehicle *FindTrainCollideEnum(Vehicle *v, void *data) |
3551 { | 3561 { |
3552 TrainCollideChecker *tcc = (TrainCollideChecker*)data; | 3562 TrainCollideChecker *tcc = (TrainCollideChecker*)data; |
3553 | 3563 |
3554 if (v->type != VEH_TRAIN) return NULL; | 3564 /* not a train or in depot */ |
3565 if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return NULL; | |
3555 | 3566 |
3556 /* get first vehicle now to make most usual checks faster */ | 3567 /* get first vehicle now to make most usual checks faster */ |
3557 Vehicle *coll = v->First(); | 3568 Train *coll = Train::From(v)->First(); |
3558 | 3569 |
3559 /* can't collide with own wagons && can't crash in depot && the same height level */ | 3570 /* can't collide with own wagons */ |
3560 if (coll != tcc->v && Train::From(v)->track != TRACK_BIT_DEPOT && abs(v->z_pos - tcc->v->z_pos) < 6) { | 3571 if (coll == tcc->v) return NULL; |
3561 int x_diff = v->x_pos - tcc->v->x_pos; | 3572 |
3562 int y_diff = v->y_pos - tcc->v->y_pos; | 3573 int x_diff = v->x_pos - tcc->v->x_pos; |
3563 | 3574 int y_diff = v->y_pos - tcc->v->y_pos; |
3564 /* Needed to disable possible crash of competitor train in station by building diagonal track at its end. | 3575 |
3565 * The second check is false when (abs(first), abs(second)) is: a) 5, 0 b) 4, <=3 c) 3, <=4, d) 2-, <=5 | 3576 /* Do fast calculation to check whether trains are not in close vicinity |
3566 * 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 | 3577 * and quickly reject trains distant enough for any collision. |
3567 * multiplying. Simply, when sum of abs() is >= 8, the sum of squares can't be <= 25. | 3578 * Differences are shifted by 7, mapping range [-7 .. 8] into [0 .. 15] |
3568 * Even gcc3.4 seems to do abs() branchless (using arithmetics or conditional moves). */ | 3579 * Differences are then ORed and then we check for any higher bits */ |
3569 if (abs(x_diff) + abs(y_diff) > 7 || x_diff * x_diff + y_diff * y_diff > 25) return NULL; | 3580 uint hash = (y_diff + 7) | (x_diff + 7); |
3570 | 3581 if (hash & ~15) return NULL; |
3571 /* crash both trains */ | 3582 |
3572 tcc->num += TrainCrashed(Train::From(tcc->v)); | 3583 /* Slower check using multiplication */ |
3573 tcc->num += TrainCrashed(Train::From(coll)); | 3584 if (x_diff * x_diff + y_diff * y_diff > 25) return NULL; |
3574 | 3585 |
3575 /* Try to reserve all tiles directly under the crashed trains. | 3586 /* Happens when there is a train under bridge next to bridge head */ |
3576 * As there might be more than two trains involved, we have to do that for all vehicles */ | 3587 if (abs(v->z_pos - tcc->v->z_pos) > 5) return NULL; |
3577 const Train *u; | 3588 |
3578 FOR_ALL_TRAINS(u) { | 3589 /* crash both trains */ |
3579 if ((u->vehstatus & VS_CRASHED) && u->track != TRACK_BIT_DEPOT) { | 3590 tcc->num += TrainCrashed(tcc->v); |
3580 TrackBits trackbits = u->track; | 3591 tcc->num += TrainCrashed(coll); |
3581 if (trackbits == TRACK_BIT_WORMHOLE) { | 3592 |
3582 /* Vehicle is inside a wormhole, v->track contains no useful value then. */ | 3593 return NULL; // continue searching |
3583 trackbits = DiagDirToDiagTrackBits(GetTunnelBridgeDirection(u->tile)); | |
3584 } | |
3585 TryReserveRailTrack(u->tile, TrackBitsToTrack(trackbits)); | |
3586 } | |
3587 } | |
3588 } | |
3589 | |
3590 return NULL; | |
3591 } | 3594 } |
3592 | 3595 |
3593 /** | 3596 /** |
3594 * Checks whether the specified train has a collision with another vehicle. If | 3597 * Checks whether the specified train has a collision with another vehicle. If |
3595 * so, destroys this vehicle, and the other vehicle if its subtype has TS_Front. | 3598 * so, destroys this vehicle, and the other vehicle if its subtype has TS_Front. |