Better handle out of track and depot through load cases

Add advice messages for when loading is aborted due to out of track/depot
Handle non-aligned use of platform
Fix full-load behaviour
Fix speed limiting whilst advancing
This commit is contained in:
Jonathan G Rennison
2018-03-29 19:16:44 +01:00
parent 7aab49e282
commit 2821599f6b
7 changed files with 158 additions and 15 deletions

View File

@@ -51,11 +51,14 @@
static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *p_got_reservation, bool mark_stuck);
static bool TrainApproachingLineEnd(Train *v, bool signal, bool reverse);
static bool TrainCheckIfLineEnds(Train *v, bool reverse = true);
static bool TrainCanLeaveTile(const Train *v);
static inline bool CheckCompatibleRail(const Train *v, TileIndex tile);
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);
TileIndex VehiclePosTraceRestrictPreviousSignalCallback(const Train *v, const void *);
static void TrainEnterStation(Train *v, StationID station);
static const byte _vehicle_initial_x_fract[4] = {10, 8, 4, 8};
static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10};
@@ -331,17 +334,57 @@ void Train::ConsistChanged(ConsistChangeFlags allowed_changes)
}
}
/**
* Get the fraction of the vehicle's current tile which is in front of it.
* This is equal to how many more steps it could travel without having to stop/reverse if it was an end of line.
*
* See also wrapper without x_pos, y_pos in train.h
*
* @param v the vehicle to use (not required to be the front)
* @param x_pos vehicle x position
* @param y_pos vehicle y position
* @return the fraction of the current tile in front of the vehicle
*/
int GetTileMarginInFrontOfTrain(const Train *v, int x_pos, int y_pos)
{
if (IsDiagonalDirection(v->direction)) {
DiagDirection dir = DirToDiagDir(v->direction);
int offset = ((DiagDirToAxis(dir) == AXIS_X) ? x_pos : y_pos) & 0xF;
return ((dir == DIAGDIR_SE || dir == DIAGDIR_SW) ? TILE_SIZE - 1 - offset : offset) - ((v->gcache.cached_veh_length + 1) / 2);
} else {
/* Calc position within the current tile */
uint x = x_pos & 0xF;
uint y = y_pos & 0xF;
/* for non-diagonal directions, x will be 1, 3, 5, ..., 15 */
switch (v->direction) {
case DIR_N : x = ~x + ~y + 25; break;
case DIR_E : x = ~x + y + 9; break;
case DIR_S : x = x + y - 7; break;
case DIR_W : x = ~y + x + 9; break;
default: break;
}
x >>= 1; // x is now in range 0 ... 7
return (TILE_SIZE / 2) - 1 - x - (v->gcache.cached_veh_length + 1) / 2;
}
}
/**
* Get the stop location of (the center) of the front vehicle of a train at
* a platform of a station.
*
* See also wrapper without x_pos, y_pos in train.h
*
* @param station_id the ID of the station where we're stopping
* @param tile the tile where the vehicle currently is
* @param v the vehicle to get the stop location of
* @param station_ahead 'return' the amount of 1/16th tiles in front of the train
* @param station_length 'return' the station length in 1/16th tiles
* @param x_pos vehicle x position
* @param y_pos vehicle y position
* @return the location, calculated from the begin of the station to stop at.
*/
int GetTrainStopLocation(StationID station_id, TileIndex tile, Train *v, int *station_ahead, int *station_length)
int GetTrainStopLocation(StationID station_id, TileIndex tile, Train *v, int *station_ahead, int *station_length, int x_pos, int y_pos)
{
Train *front = v->First();
const Station *st = Station::Get(station_id);
@@ -419,7 +462,38 @@ int GetTrainStopLocation(StationID station_id, TileIndex tile, Train *v, int *st
/* Subtract half the front vehicle length of the train so we get the real
* stop location of the train. */
return stop - ((v->gcache.cached_veh_length + 1) / 2) + adjust;
int result = stop - ((v->gcache.cached_veh_length + 1) / 2) + adjust;
if (osl == OSL_PLATFORM_THROUGH && v != front) {
/* Check front of train for obstructions */
if (TrainCanLeaveTile(front)) {
/* Determine the non-diagonal direction in which we will exit this tile */
DiagDirection dir = TrainExitDir(front->direction, front->track);
/* Calculate next tile */
TileIndex tile = front->tile + TileOffsByDiagDir(dir);
/* Determine the track status on the next tile */
TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0, ReverseDiagDir(dir));
TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & DiagdirReachesTrackdirs(dir);
/* mask unreachable track bits if we are forbidden to do 90deg turns */
TrackBits bits = TrackdirBitsToTrackBits(trackdirbits);
if (_settings_game.pf.forbid_90_deg) {
bits &= ~TrackCrossesTracks(FindFirstTrack(front->track));
}
if (bits == TRACK_BIT_NONE || !CheckCompatibleRail(front, tile) || IsRailDepotTile(tile) ||
(KillFirstBit(trackdirbits) == TRACKDIR_BIT_NONE && HasOnewaySignalBlockingTrackdir(tile, FindFirstTrackdir(trackdirbits)))) {
/* next tile is an effective dead end */
int current_platform_remaining = *station_ahead - TILE_SIZE + GetTileMarginInFrontOfTrain(v);
int limit = GetTileMarginInFrontOfTrain(front) + (*station_length - current_platform_remaining) - ((v->gcache.cached_veh_length + 1) / 2);
result = min(limit, result);
}
}
}
return result;
}
@@ -548,6 +622,8 @@ int Train::GetCurrentMaxSpeed() const
max_speed = min(max_speed, this->GetBreakdownSpeed());
}
if (this->current_order.IsType(OT_LOADING_ADVANCE)) max_speed = min(max_speed, 15);
return min(max_speed, this->gcache.cached_max_track_speed);
}
@@ -2054,7 +2130,27 @@ void ReverseTrainDirection(Train *v)
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
}
if (v->current_order.IsType(OT_LOADING_ADVANCE)) v->LeaveStation();
if (_local_company == v->owner && (v->current_order.IsType(OT_LOADING_ADVANCE) || HasBit(v->flags, VRF_BEYOND_PLATFORM_END))) {
SetDParam(0, v->index);
SetDParam(1, v->current_order.GetDestination());
AddNewsItem(STR_VEHICLE_LOAD_THROUGH_ABORTED_INSUFFICIENT_TRACK, NT_ADVICE, NF_INCOLOUR | NF_SMALL | NF_VEHICLE_PARAM0,
NR_VEHICLE, v->index,
NR_STATION, v->current_order.GetDestination());
}
if (v->current_order.IsType(OT_LOADING_ADVANCE)) {
v->LeaveStation();
/* Only advance to next order if we are loading at the current one */
const Order *order = v->GetOrder(v->cur_implicit_order_index);
if (order != NULL && order->IsType(OT_GOTO_STATION) && order->GetDestination() == v->last_station_visited) {
v->IncrementImplicitOrderIndex();
}
}
for (Train *u = v; u != nullptr; u = u->Next()) {
ClrBit(u->flags, VRF_BEYOND_PLATFORM_END);
ClrBit(u->flags, VRF_NOT_YET_IN_PLATFORM);
}
v->reverse_distance = 0;
@@ -2200,7 +2296,8 @@ CommandCost CmdReverseTrainDirection(TileIndex tile, DoCommandFlag flags, uint32
/* not a station || different station --> leave the station */
if (!IsTileType(last->tile, MP_STATION) || !IsTileType(v->tile, MP_STATION) ||
GetStationIndex(last->tile) != GetStationIndex(v->tile) ||
HasBit(v->flags, VRF_BEYOND_PLATFORM_END)) {
HasBit(v->flags, VRF_BEYOND_PLATFORM_END) ||
v->current_order.IsType(OT_LOADING_ADVANCE)) {
v->LeaveStation();
}
}