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:
@@ -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
|
||||
|
15
src/train.h
15
src/train.h
@@ -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();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user