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
pull/59/head
Jonathan G Rennison 6 years ago
parent 7aab49e282
commit 2821599f6b

@ -1675,8 +1675,9 @@ static void LoadUnloadVehicle(Vehicle *front)
StationID last_visited = front->last_station_visited;
Station *st = Station::Get(last_visited);
TileIndex station_tile = front->tile;
if (front->type == VEH_TRAIN) station_tile = Train::From(front)->GetStationLoadingVehicle()->tile;
Vehicle *station_vehicle = front;
if (front->type == VEH_TRAIN) station_vehicle = Train::From(front)->GetStationLoadingVehicle();
TileIndex station_tile = station_vehicle->tile;
bool pull_through_mode = false;
bool load_unload_not_yet_in_station = false;
@ -1691,12 +1692,17 @@ static void LoadUnloadVehicle(Vehicle *front)
pull_through_mode = false;
break;
}
/* Disallow through-load when any part of train is in a depot, to prevent cheating */
if (Train::From(v)->IsInDepot()) {
pull_through_mode = false;
break;
}
}
}
}
int platform_length_left = 0;
if (pull_through_mode) {
platform_length_left = st->GetPlatformLength(station_tile) * TILE_SIZE;
platform_length_left = st->GetPlatformLength(station_tile, ReverseDiagDir(DirToDiagDir(station_vehicle->direction))) * TILE_SIZE - GetTileMarginInFrontOfTrain(Train::From(station_vehicle));
} else if (front->type == VEH_TRAIN) {
platform_length_left = st->GetPlatformLength(station_tile) * TILE_SIZE - front->GetGroundVehicleCache()->cached_total_length;
}
@ -1707,10 +1713,10 @@ static void LoadUnloadVehicle(Vehicle *front)
CargoArray consist_capleft;
bool should_reserve_consist = false;
bool reserve_consist_cargo_type_loading = false;
if ((_settings_game.order.improved_load && use_autorefit) || pull_through_mode) {
if (_settings_game.order.improved_load && use_autorefit) {
if (front->cargo_payment == NULL) should_reserve_consist = true;
} else {
if ((front->current_order.GetLoadType() & OLFB_FULL_LOAD) || (front->current_order.GetLoadType() == OLFB_CARGO_TYPE_LOAD)) {
if ((front->current_order.GetLoadType() & OLFB_FULL_LOAD) || (front->current_order.GetLoadType() == OLFB_CARGO_TYPE_LOAD) || pull_through_mode) {
should_reserve_consist = true;
reserve_consist_cargo_type_loading = (front->current_order.GetLoadType() == OLFB_CARGO_TYPE_LOAD);
}

@ -418,8 +418,6 @@ protected:
}
}
if (this->current_order.IsType(OT_LOADING_ADVANCE)) tempmax = min(tempmax, 15);
if (this->cur_speed > max_speed) {
tempmax = max(this->cur_speed - (this->cur_speed / 10) - 1, max_speed);
}

@ -4270,6 +4270,9 @@ STR_VEHICLE_DETAILS_AIRCRAFT_RENAME :{BLACK}Name air
STR_VEHICLE_INFO_AGE_RUNNING_COST_YR :{BLACK}Age: {LTBLUE}{STRING2}{BLACK} Running Cost: {LTBLUE}{CURRENCY_LONG}/yr
STR_VEHICLE_LOAD_THROUGH_ABORTED_INSUFFICIENT_TRACK :{WHITE}{VEHICLE}: through load aborted due to insufficient track at {STATION}
STR_VEHICLE_LOAD_THROUGH_ABORTED_DEPOT :{WHITE}{VEHICLE}: through load aborted due to depot at {STATION}
STR_RUNNING :{LTBLUE}Running
STR_NEED_REPAIR :{ORANGE}Vehicle needs repair - max speed reduced to {VELOCITY}
STR_CURRENT_STATUS :{BLACK}Current status: {STRING3}

@ -38,6 +38,7 @@
#include "programmable_signals.h"
#include "spritecache.h"
#include "core/container_func.hpp"
#include "news_func.h"
#include "table/strings.h"
#include "table/railtypes.h"
@ -3180,10 +3181,28 @@ static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int
/* this routine applies only to trains in depot tiles */
if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
if (u->current_order.IsType(OT_LOADING_ADVANCE)) u->LeaveStation();
Train *v = Train::From(u);
auto abort_load_through = [&](bool leave_station) {
if (_local_company == v->owner) {
SetDParam(0, v->index);
SetDParam(1, v->current_order.GetDestination());
AddNewsItem(STR_VEHICLE_LOAD_THROUGH_ABORTED_DEPOT, NT_ADVICE, NF_INCOLOUR | NF_SMALL | NF_VEHICLE_PARAM0,
NR_VEHICLE, v->index,
NR_STATION, v->current_order.GetDestination());
}
if (leave_station) {
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();
}
}
};
if (v->IsFrontEngine() && v->current_order.IsType(OT_LOADING_ADVANCE)) abort_load_through(true);
/* depot direction */
DiagDirection dir = GetRailDepotDirection(tile);
@ -3204,6 +3223,13 @@ static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int
} else if (_fractcoords_enter[dir] == fract_coord) {
if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
/* enter the depot */
if (v->IsFrontEngine() && v->current_order.IsType(OT_LOADING_ADVANCE)) {
abort_load_through(true);
} else if (v->IsFrontEngine() && HasBit(v->flags, VRF_BEYOND_PLATFORM_END)) {
abort_load_through(false);
}
v->track = TRACK_BIT_DEPOT,
v->vehstatus |= VS_HIDDEN; // hide it
v->direction = ReverseDir(v->direction);

@ -3309,7 +3309,7 @@ static VehicleEnterTileStatus VehicleEnter_Station(Vehicle *v, TileIndex tile, i
int station_ahead;
int station_length;
int stop = GetTrainStopLocation(station_id, tile, Train::From(v), &station_ahead, &station_length);
int stop = GetTrainStopLocation(station_id, tile, Train::From(v), &station_ahead, &station_length, x, y);
/* Stop whenever that amount of station ahead + the distance from the
* begin of the platform to the stop location is longer than the length

@ -79,7 +79,6 @@ bool TryPathReserve(Train *v, bool mark_as_stuck = false, bool first_tile_okay =
void DeleteVisibleTrain(Train *v);
int GetTrainStopLocation(StationID station_id, TileIndex tile, Train *v, int *station_ahead, int *station_length);
void CheckBreakdownFlags(Train *v);
void GetTrainSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type);
@ -406,6 +405,20 @@ CommandCost CmdMoveVirtualRailVehicle(TileIndex, DoCommandFlag, uint32, uint32,
Train* CmdBuildVirtualRailWagon(const Engine*);
Train* CmdBuildVirtualRailVehicle(EngineID, bool lax_engine_check, StringID &error);
int GetTileMarginInFrontOfTrain(const Train *v, int x_pos, int y_pos);
inline int GetTileMarginInFrontOfTrain(const Train *v)
{
return GetTileMarginInFrontOfTrain(v, v->x_pos, v->y_pos);
}
int GetTrainStopLocation(StationID station_id, TileIndex tile, Train *v, int *station_ahead, int *station_length, int x_pos, int y_pos);
inline int GetTrainStopLocation(StationID station_id, TileIndex tile, Train *v, int *station_ahead, int *station_length)
{
return GetTrainStopLocation(station_id, tile, v, station_ahead, station_length, v->x_pos, v->y_pos);
}
#define FOR_ALL_TRAINS(var) FOR_ALL_VEHICLES_OF_TYPE(Train, var)
#endif /* TRAIN_H */

@ -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();
}
}

Loading…
Cancel
Save