|
@@ -3335,76 +3335,48 @@ static byte AfterSetTrainPos(Vehicle *v,
|
|
|
|
|
|
if (v->u.rail.track == TRACK_BIT_X || v->u.rail.track == TRACK_BIT_Y) {
|
|
|
/* Any track that isn't TRACK_BIT_X or TRACK_BIT_Y cannot be sloped.
|
|
|
* To check whether the current tile is sloped, and in which
|
|
|
* direction it is sloped, we get the 'z' at the center of
|
|
|
* the tile (middle_z) and the edge of the tile (old_z),
|
|
|
* which we then can compare. */
|
|
|
static const int HALF_TILE_SIZE = TILE_SIZE / 2;
|
|
|
static const int INV_TILE_SIZE_MASK = ~(TILE_SIZE - 1);
|
|
|
|
|
|
byte middle_z = GetSlopeZ((v->x_pos & INV_TILE_SIZE_MASK) | HALF_TILE_SIZE, (v->y_pos & INV_TILE_SIZE_MASK) | HALF_TILE_SIZE);
|
|
|
|
|
|
/* For some reason tunnel tiles are always given as sloped :(
|
|
|
* But they are not sloped... */
|
|
|
if (middle_z != v->z_pos && !IsTunnelTile(TileVirtXY(v->x_pos, v->y_pos))) {
|
|
|
SetBit(v->u.rail.flags, (middle_z > old_z) ? VRF_GOINGUP : VRF_GOINGDOWN);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
VehicleMove(v, true);
|
|
|
return old_z;
|
|
|
}
|
|
|
|
|
|
static const Direction _new_vehicle_direction_table[11] = {
|
|
|
DIR_N , DIR_NW, DIR_W , INVALID_DIR,
|
|
|
DIR_NE, DIR_N , DIR_SW, INVALID_DIR,
|
|
|
DIR_E , DIR_SE, DIR_S
|
|
|
};
|
|
|
|
|
|
static inline int GetDirectionToVehicle(const Vehicle *v, int x, int y)
|
|
|
{
|
|
|
byte offs;
|
|
|
|
|
|
x -= v->x_pos;
|
|
|
if (x >= 0) {
|
|
|
offs = (x > 2) ? 0 : 1;
|
|
|
} else {
|
|
|
offs = (x < -2) ? 2 : 1;
|
|
|
}
|
|
|
|
|
|
y -= v->y_pos;
|
|
|
if (y >= 0) {
|
|
|
offs += ((y > 2) ? 0 : 1) * 4;
|
|
|
} else {
|
|
|
offs += ((y < -2) ? 2 : 1) * 4;
|
|
|
}
|
|
|
|
|
|
assert(offs < 11);
|
|
|
return _new_vehicle_direction_table[offs];
|
|
|
}
|
|
|
|
|
|
/* Check if the vehicle is compatible with the specified tile */
|
|
|
static inline bool CheckCompatibleRail(const Vehicle *v, TileIndex tile)
|
|
|
{
|
|
|
return
|
|
|
IsTileOwner(tile, v->owner) && (
|
|
|
!IsFrontEngine(v) ||
|
|
|
HasBit(v->u.rail.compatible_railtypes, GetRailType(tile))
|
|
|
);
|
|
|
}
|
|
|
|
|
|
struct RailtypeSlowdownParams {
|
|
|
byte small_turn, large_turn;
|
|
|
byte z_up; // fraction to remove when moving up
|
|
|
byte z_down; // fraction to remove when moving down
|
|
|
};
|
|
|
|
|
|
static const RailtypeSlowdownParams _railtype_slowdown[] = {
|
|
|
/* normal accel */
|
|
|
{256 / 4, 256 / 2, 256 / 4, 2}, ///< normal
|
|
|
{256 / 4, 256 / 2, 256 / 4, 2}, ///< electrified
|
|
|
{256 / 4, 256 / 2, 256 / 4, 2}, ///< monorail
|
|
|
{0, 256 / 2, 256 / 4, 2}, ///< maglev
|
|
|
};
|
|
|
|
|
@@ -3705,57 +3677,72 @@ static void TrainController(Vehicle *v,
|
|
|
v->subspeed = 0;
|
|
|
v->progress = 255 - 10;
|
|
|
if (_settings_game.pf.wait_twoway_signal == 255 || ++v->load_unload_time_rem < _settings_game.pf.wait_twoway_signal * 73) {
|
|
|
DiagDirection exitdir = TrackdirToExitdir(i);
|
|
|
TileIndex o_tile = TileAddByDiagDir(gp.new_tile, exitdir);
|
|
|
|
|
|
exitdir = ReverseDiagDir(exitdir);
|
|
|
|
|
|
/* check if a train is waiting on the other side */
|
|
|
if (!HasVehicleOnPos(o_tile, &exitdir, &CheckVehicleAtSignal)) return;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* If we would reverse but are currently in a PBS block and
|
|
|
* reversing of stuck trains is disabled, don't reverse. */
|
|
|
if (_settings_game.pf.wait_for_pbs_path == 255 && UpdateSignalsOnSegment(v->tile, enterdir, v->owner) == SIGSEG_PBS) {
|
|
|
v->load_unload_time_rem = 0;
|
|
|
return;
|
|
|
}
|
|
|
goto reverse_train_direction;
|
|
|
} else {
|
|
|
TryReserveRailTrack(gp.new_tile, TrackBitsToTrack(chosen_track));
|
|
|
}
|
|
|
} else {
|
|
|
static const TrackBits _matching_tracks[8] = {
|
|
|
TRACK_BIT_LEFT | TRACK_BIT_RIGHT, TRACK_BIT_X,
|
|
|
TRACK_BIT_UPPER | TRACK_BIT_LOWER, TRACK_BIT_Y,
|
|
|
TRACK_BIT_LEFT | TRACK_BIT_RIGHT, TRACK_BIT_X,
|
|
|
TRACK_BIT_UPPER | TRACK_BIT_LOWER, TRACK_BIT_Y
|
|
|
};
|
|
|
|
|
|
/* The wagon is active, simply follow the prev vehicle. */
|
|
|
chosen_track = (TrackBits)(byte)(_matching_tracks[GetDirectionToVehicle(prev, gp.x, gp.y)] & bits);
|
|
|
if (prev->tile == gp.new_tile) {
|
|
|
/* Choose the same track as prev */
|
|
|
if (prev->u.rail.track == TRACK_BIT_WORMHOLE) {
|
|
|
/* Vehicles entering tunnels enter the wormhole earlier than for bridges.
|
|
|
* However, just choose the track into the wormhole. */
|
|
|
assert(IsTunnel(prev->tile));
|
|
|
chosen_track = bits;
|
|
|
} else {
|
|
|
chosen_track = prev->u.rail.track;
|
|
|
}
|
|
|
} else {
|
|
|
/* Choose the track that leads to the tile where prev is. */
|
|
|
static const TrackBits _connecting_track[DIAGDIR_END][DIAGDIR_END] = {
|
|
|
{TRACK_BIT_Y, TRACK_BIT_LOWER, TRACK_BIT_NONE, TRACK_BIT_LEFT },
|
|
|
{TRACK_BIT_UPPER, TRACK_BIT_X, TRACK_BIT_LEFT, TRACK_BIT_NONE },
|
|
|
{TRACK_BIT_NONE, TRACK_BIT_RIGHT, TRACK_BIT_Y, TRACK_BIT_UPPER},
|
|
|
{TRACK_BIT_RIGHT, TRACK_BIT_NONE, TRACK_BIT_LOWER, TRACK_BIT_X }
|
|
|
};
|
|
|
DiagDirection exitdir = DiagdirBetweenTiles(gp.new_tile, prev->tile);
|
|
|
assert(IsValidDiagDirection(exitdir));
|
|
|
chosen_track = _connecting_track[enterdir][exitdir];
|
|
|
}
|
|
|
chosen_track &= bits;
|
|
|
}
|
|
|
|
|
|
/* Make sure chosen track is a valid track */
|
|
|
assert(
|
|
|
chosen_track == TRACK_BIT_X || chosen_track == TRACK_BIT_Y ||
|
|
|
chosen_track == TRACK_BIT_UPPER || chosen_track == TRACK_BIT_LOWER ||
|
|
|
chosen_track == TRACK_BIT_LEFT || chosen_track == TRACK_BIT_RIGHT);
|
|
|
|
|
|
/* Update XY to reflect the entrance to the new tile, and select the direction to use */
|
|
|
const byte *b = _initial_tile_subcoord[FIND_FIRST_BIT(chosen_track)][enterdir];
|
|
|
gp.x = (gp.x & ~0xF) | b[0];
|
|
|
gp.y = (gp.y & ~0xF) | b[1];
|
|
|
Direction chosen_dir = (Direction)b[2];
|
|
|
|
|
|
/* Call the landscape function and tell it that the vehicle entered the tile */
|
|
|
uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
|
|
|
if (HasBit(r, VETS_CANNOT_ENTER)) {
|
|
|
goto invalid_rail;
|
|
|
}
|
|
|
|
|
|
if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
|
|
|
Track track = FindFirstTrack(chosen_track);
|
|
|
Trackdir tdir = TrackDirectionToTrackdir(track, chosen_dir);
|
|
|
if (IsFrontEngine(v) && HasPbsSignalOnTrackdir(gp.new_tile, tdir)) {
|