mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-09-02 03:19:10 +00:00
(svn r23290) -Fix [FS#2379,FS#3569]: Change the centre of train vehicles to depend on the vehicle length instead of being fixed at 4/8th of the original vehicle length to make sure shortened vehicles don't block tiles they shouldn't block.
This commit is contained in:
@@ -41,8 +41,8 @@
|
||||
#include "table/train_cmd.h"
|
||||
|
||||
static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck);
|
||||
static bool TrainCheckIfLineEnds(Train *v);
|
||||
static void TrainController(Train *v, Vehicle *nomove);
|
||||
static bool TrainCheckIfLineEnds(Train *v, bool reverse = true);
|
||||
bool TrainController(Train *v, Vehicle *nomove, bool reverse = true); // Also used in vehicle_sl.cpp.
|
||||
static TileIndex TrainApproachingCrossingTile(const Train *v);
|
||||
static void CheckIfTrainNeedsService(Train *v);
|
||||
static void CheckNextTrainTile(Train *v);
|
||||
@@ -95,7 +95,7 @@ void CheckTrainsLengths()
|
||||
for (const Train *u = v, *w = v->Next(); w != NULL; u = w, w = w->Next()) {
|
||||
if (u->track != TRACK_BIT_DEPOT) {
|
||||
if ((w->track != TRACK_BIT_DEPOT &&
|
||||
max(abs(u->x_pos - w->x_pos), abs(u->y_pos - w->y_pos)) != u->gcache.cached_veh_length) ||
|
||||
max(abs(u->x_pos - w->x_pos), abs(u->y_pos - w->y_pos)) != u->CalcNextVehicleOffset()) ||
|
||||
(w->track == TRACK_BIT_DEPOT && TicksToLeaveDepot(u) <= 0)) {
|
||||
SetDParam(0, v->index);
|
||||
SetDParam(1, v->owner);
|
||||
@@ -305,11 +305,8 @@ int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, i
|
||||
}
|
||||
|
||||
/* Subtract half the front vehicle length of the train so we get the real
|
||||
* stop location of the train.
|
||||
* Actually, the center of all vehicles is half a normal vehicle's length
|
||||
* from the front of the vehicle, so even in case the vehicle is 1/8th
|
||||
* long, the center is still at 1/2 of VEHICLE_LENGTH. Basically FS#3569. */
|
||||
return stop - VEHICLE_LENGTH / 2;
|
||||
* stop location of the train. */
|
||||
return stop - (v->gcache.cached_veh_length + 1) / 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -1382,25 +1379,66 @@ CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data, uint3
|
||||
|
||||
void Train::UpdateDeltaXY(Direction direction)
|
||||
{
|
||||
#define MKIT(a, b, c, d) ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | ((d & 0xFF) << 0)
|
||||
static const uint32 _delta_xy_table[8] = {
|
||||
MKIT(3, 3, -1, -1),
|
||||
MKIT(3, 7, -1, -3),
|
||||
MKIT(3, 3, -1, -1),
|
||||
MKIT(7, 3, -3, -1),
|
||||
MKIT(3, 3, -1, -1),
|
||||
MKIT(3, 7, -1, -3),
|
||||
MKIT(3, 3, -1, -1),
|
||||
MKIT(7, 3, -3, -1),
|
||||
};
|
||||
#undef MKIT
|
||||
/* Set common defaults. */
|
||||
this->x_offs = -1;
|
||||
this->y_offs = -1;
|
||||
this->x_extent = 3;
|
||||
this->y_extent = 3;
|
||||
this->z_extent = 6;
|
||||
this->x_bb_offs = 0;
|
||||
this->y_bb_offs = 0;
|
||||
|
||||
uint32 x = _delta_xy_table[direction];
|
||||
this->x_offs = GB(x, 0, 8);
|
||||
this->y_offs = GB(x, 8, 8);
|
||||
this->x_extent = GB(x, 16, 8);
|
||||
this->y_extent = GB(x, 24, 8);
|
||||
this->z_extent = 6;
|
||||
if (!IsDiagonalDirection(direction)) {
|
||||
static const int _sign_table[] =
|
||||
{
|
||||
// x, y
|
||||
-1, -1, // DIR_N
|
||||
-1, 1, // DIR_E
|
||||
1, 1, // DIR_S
|
||||
1, -1, // DIR_W
|
||||
};
|
||||
|
||||
int half_shorten = (VEHICLE_LENGTH - this->gcache.cached_veh_length) / 2;
|
||||
|
||||
/* For all straight directions, move the bound box to the centre of the vehicle, but keep the size. */
|
||||
this->x_offs -= half_shorten * _sign_table[direction];
|
||||
this->y_offs -= half_shorten * _sign_table[direction + 1];
|
||||
this->x_extent += this->x_bb_offs = half_shorten * _sign_table[direction];
|
||||
this->y_extent += this->y_bb_offs = half_shorten * _sign_table[direction + 1];
|
||||
} else {
|
||||
switch (direction) {
|
||||
/* Shorten southern corner of the bounding box according the vehicle length
|
||||
* and center the bounding box on the vehicle. */
|
||||
case DIR_NE:
|
||||
this->x_offs = 1 - (this->gcache.cached_veh_length + 1) / 2;
|
||||
this->x_extent = this->gcache.cached_veh_length - 1;
|
||||
this->x_bb_offs = -1;
|
||||
break;
|
||||
|
||||
case DIR_NW:
|
||||
this->y_offs = 1 - (this->gcache.cached_veh_length + 1) / 2;
|
||||
this->y_extent = this->gcache.cached_veh_length - 1;
|
||||
this->y_bb_offs = -1;
|
||||
break;
|
||||
|
||||
/* Move northern corner of the bounding box down according to vehicle length
|
||||
* and center the bounding box on the vehicle. */
|
||||
case DIR_SW:
|
||||
this->x_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH;
|
||||
this->x_extent = VEHICLE_LENGTH - 1;
|
||||
this->x_bb_offs = VEHICLE_LENGTH - this->gcache.cached_veh_length - 1;
|
||||
break;
|
||||
|
||||
case DIR_SE:
|
||||
this->y_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH;
|
||||
this->y_extent = VEHICLE_LENGTH - 1;
|
||||
this->y_bb_offs = VEHICLE_LENGTH - this->gcache.cached_veh_length - 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Mark a train as stuck and stop it if it isn't stopped right now. */
|
||||
@@ -1478,7 +1516,7 @@ static void UpdateStatusAfterSwap(Train *v)
|
||||
v->UpdateViewport(true, true);
|
||||
}
|
||||
|
||||
static void ReverseTrainSwapVeh(Train *v, int l, int r)
|
||||
void ReverseTrainSwapVeh(Train *v, int l, int r)
|
||||
{
|
||||
Train *a, *b;
|
||||
|
||||
@@ -1626,7 +1664,7 @@ static void AdvanceWagonsBeforeSwap(Train *v)
|
||||
last = last->Previous();
|
||||
first = first->Next();
|
||||
|
||||
int differential = base->gcache.cached_veh_length - last->gcache.cached_veh_length;
|
||||
int differential = base->CalcNextVehicleOffset() - last->CalcNextVehicleOffset();
|
||||
|
||||
/* do not update images now
|
||||
* negative differential will be handled in AdvanceWagonsAfterSwap() */
|
||||
@@ -1686,7 +1724,7 @@ static void AdvanceWagonsAfterSwap(Train *v)
|
||||
last = last->Previous();
|
||||
first = first->Next();
|
||||
|
||||
int differential = last->gcache.cached_veh_length - base->gcache.cached_veh_length;
|
||||
int differential = last->CalcNextVehicleOffset() - base->CalcNextVehicleOffset();
|
||||
|
||||
/* do not update images now */
|
||||
for (int i = 0; i < differential; i++) TrainController(first, (nomove ? last->Next() : NULL));
|
||||
@@ -1697,7 +1735,7 @@ static void AdvanceWagonsAfterSwap(Train *v)
|
||||
}
|
||||
|
||||
|
||||
static void ReverseTrainDirection(Train *v)
|
||||
void ReverseTrainDirection(Train *v)
|
||||
{
|
||||
if (IsRailDepotTile(v->tile)) {
|
||||
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
|
||||
@@ -2840,7 +2878,8 @@ static Vehicle *FindTrainCollideEnum(Vehicle *v, void *data)
|
||||
if (hash & ~15) return NULL;
|
||||
|
||||
/* Slower check using multiplication */
|
||||
if (x_diff * x_diff + y_diff * y_diff > 25) return NULL;
|
||||
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 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;
|
||||
@@ -2906,7 +2945,14 @@ static Vehicle *CheckTrainAtSignal(Vehicle *v, void *data)
|
||||
return t;
|
||||
}
|
||||
|
||||
static void TrainController(Train *v, Vehicle *nomove)
|
||||
/**
|
||||
* Move a vehicle chain one movement stop forwards.
|
||||
* @param v First vehicle to move.
|
||||
* @param nomove Stop moving this and all following vehicles.
|
||||
* @param reverse Set to false to not execute the vehicle reversing. This does not change any other logic.
|
||||
* @return True if the vehicle could be moved forward, false otherwise.
|
||||
*/
|
||||
bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
{
|
||||
Train *first = v->First();
|
||||
Train *prev;
|
||||
@@ -2930,7 +2976,7 @@ static void TrainController(Train *v, Vehicle *nomove)
|
||||
/* Not inside depot */
|
||||
|
||||
/* Reverse when we are at the end of the track already, do not move to the new position */
|
||||
if (v->IsFrontEngine() && !TrainCheckIfLineEnds(v)) return;
|
||||
if (v->IsFrontEngine() && !TrainCheckIfLineEnds(v, reverse)) return false;
|
||||
|
||||
uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
|
||||
if (HasBit(r, VETS_CANNOT_ENTER)) {
|
||||
@@ -2997,13 +3043,13 @@ static void TrainController(Train *v, Vehicle *nomove)
|
||||
Trackdir i = FindFirstTrackdir(trackdirbits);
|
||||
|
||||
/* Don't handle stuck trains here. */
|
||||
if (HasBit(v->flags, VRF_TRAIN_STUCK)) return;
|
||||
if (HasBit(v->flags, VRF_TRAIN_STUCK)) return false;
|
||||
|
||||
if (!HasSignalOnTrackdir(gp.new_tile, ReverseTrackdir(i))) {
|
||||
v->cur_speed = 0;
|
||||
v->subspeed = 0;
|
||||
v->progress = 255 - 100;
|
||||
if (!_settings_game.pf.reverse_at_signals || ++v->wait_counter < _settings_game.pf.wait_oneway_signal * 20) return;
|
||||
if (!_settings_game.pf.reverse_at_signals || ++v->wait_counter < _settings_game.pf.wait_oneway_signal * 20) return false;
|
||||
} else if (HasSignalOnTrackdir(gp.new_tile, i)) {
|
||||
v->cur_speed = 0;
|
||||
v->subspeed = 0;
|
||||
@@ -3015,7 +3061,7 @@ static void TrainController(Train *v, Vehicle *nomove)
|
||||
exitdir = ReverseDiagDir(exitdir);
|
||||
|
||||
/* check if a train is waiting on the other side */
|
||||
if (!HasVehicleOnPos(o_tile, &exitdir, &CheckTrainAtSignal)) return;
|
||||
if (!HasVehicleOnPos(o_tile, &exitdir, &CheckTrainAtSignal)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3026,7 +3072,7 @@ static void TrainController(Train *v, Vehicle *nomove)
|
||||
if (!_settings_game.pf.reverse_at_signals && !HasOnewaySignalBlockingTrackdir(gp.new_tile, i) &&
|
||||
UpdateSignalsOnSegment(v->tile, enterdir, v->owner) == SIGSEG_PBS) {
|
||||
v->wait_counter = 0;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
goto reverse_train_direction;
|
||||
} else {
|
||||
@@ -3209,17 +3255,21 @@ static void TrainController(Train *v, Vehicle *nomove)
|
||||
|
||||
if (direction_changed) first->tcache.cached_max_curve_speed = first->GetCurveSpeedLimit();
|
||||
|
||||
return;
|
||||
return true;
|
||||
|
||||
invalid_rail:
|
||||
/* We've reached end of line?? */
|
||||
if (prev != NULL) error("Disconnecting train");
|
||||
|
||||
reverse_train_direction:
|
||||
v->wait_counter = 0;
|
||||
v->cur_speed = 0;
|
||||
v->subspeed = 0;
|
||||
ReverseTrainDirection(v);
|
||||
if (reverse) {
|
||||
v->wait_counter = 0;
|
||||
v->cur_speed = 0;
|
||||
v->subspeed = 0;
|
||||
ReverseTrainDirection(v);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3389,9 +3439,10 @@ static const uint16 _breakdown_speeds[16] = {
|
||||
*
|
||||
* @param v front train engine
|
||||
* @param signal not line end, just a red signal
|
||||
* @param reverse Set to false to not execute the vehicle reversing. This does not change any other logic.
|
||||
* @return true iff we did NOT have to reverse
|
||||
*/
|
||||
static bool TrainApproachingLineEnd(Train *v, bool signal)
|
||||
static bool TrainApproachingLineEnd(Train *v, bool signal, bool reverse)
|
||||
{
|
||||
/* Calc position within the current tile */
|
||||
uint x = v->x_pos & 0xF;
|
||||
@@ -3413,13 +3464,12 @@ static bool TrainApproachingLineEnd(Train *v, bool signal)
|
||||
/* Do not reverse when approaching red signal. Make sure the vehicle's front
|
||||
* does not cross the tile boundary when we do reverse, but as the vehicle's
|
||||
* location is based on their center, use half a vehicle's length as offset.
|
||||
* Actually, the center of all vehicles is half a normal vehicle's length
|
||||
* from the front of the vehicle, so even in case the vehicle is 1/8th
|
||||
* long, the center is still at 1/2 of VEHICLE_LENGTH. Basically FS#3569. */
|
||||
if (!signal && x + VEHICLE_LENGTH / 2 >= TILE_SIZE) {
|
||||
* Multiply the half-length by two for straight directions to compensate that
|
||||
* we only get odd x offsets there. */
|
||||
if (!signal && x + (v->gcache.cached_veh_length + 1) / 2 * (IsDiagonalDirection(v->direction) ? 1 : 2) >= TILE_SIZE) {
|
||||
/* we are too near the tile end, reverse now */
|
||||
v->cur_speed = 0;
|
||||
ReverseTrainDirection(v);
|
||||
if (reverse) ReverseTrainDirection(v);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3491,9 +3541,10 @@ static TileIndex TrainApproachingCrossingTile(const Train *v)
|
||||
* Checks for line end. Also, bars crossing at next tile if needed
|
||||
*
|
||||
* @param v vehicle we are checking
|
||||
* @param reverse Set to false to not execute the vehicle reversing. This does not change any other logic.
|
||||
* @return true iff we did NOT have to reverse
|
||||
*/
|
||||
static bool TrainCheckIfLineEnds(Train *v)
|
||||
static bool TrainCheckIfLineEnds(Train *v, bool reverse)
|
||||
{
|
||||
/* First, handle broken down train */
|
||||
|
||||
@@ -3531,11 +3582,11 @@ static bool TrainCheckIfLineEnds(Train *v)
|
||||
|
||||
/* no suitable trackbits at all || unusable rail (wrong type or owner) */
|
||||
if (bits == TRACK_BIT_NONE || !CheckCompatibleRail(v, tile)) {
|
||||
return TrainApproachingLineEnd(v, false);
|
||||
return TrainApproachingLineEnd(v, false, reverse);
|
||||
}
|
||||
|
||||
/* approaching red signal */
|
||||
if ((trackdirbits & red_signals) != 0) return TrainApproachingLineEnd(v, true);
|
||||
if ((trackdirbits & red_signals) != 0) return TrainApproachingLineEnd(v, true, reverse);
|
||||
|
||||
/* approaching a rail/road crossing? then make it red */
|
||||
if (IsLevelCrossingTile(tile)) MaybeBarCrossingWithSound(tile);
|
||||
|
Reference in New Issue
Block a user