Initial implementation of tracerestrict speed restriction feature

pull/121/head
Jonathan G Rennison 5 years ago
parent 030e8bf762
commit aa8aae9a62

@ -385,6 +385,7 @@ CommandCost CopyHeadSpecificThings(Vehicle *old_head, Vehicle *new_head, DoComma
ChangeVehicleNews(old_head->index, new_head->index);
if (old_head->type == VEH_TRAIN) {
Train::From(new_head)->speed_restriction = Train::From(old_head)->speed_restriction;
/* Transfer any acquired trace restrict slots to the new vehicle */
if (HasBit(Train::From(old_head)->flags, VRF_HAVE_SLOT)) {
TraceRestrictTransferVehicleOccupantInAllSlots(old_head->index, new_head->index);

@ -2748,6 +2748,7 @@ STR_TRACE_RESTRICT_COMPANY :Company
STR_TRACE_RESTRICT_UNDEFINED_COMPANY :Undefined company
STR_TRACE_RESTRICT_SLOT_OP :Slot operation
STR_TRACE_RESTRICT_REVERSE :Reverse
STR_TRACE_RESTRICT_SPEED_RESTRICTION :Speed restriction
STR_TRACE_RESTRICT_SLOT_ACQUIRE_WAIT :Acquire or wait
STR_TRACE_RESTRICT_SLOT_TRY_ACQUIRE :Try to acquire
STR_TRACE_RESTRICT_SLOT_RELEASE_FRONT :Release (front)
@ -2778,6 +2779,8 @@ STR_TRACE_RESTRICT_TRAIN_STATUS_LOST :lost
STR_TRACE_RESTRICT_TRAIN_STATUS_REQUIRES_SERVICE :requires service
STR_TRACE_RESTRICT_REVERSE_SIG :Reverse behind signal
STR_TRACE_RESTRICT_REVERSE_SIG_CANCEL :Cancel reverse behind signal
STR_TRACE_RESTRICT_SET_SPEED_RESTRICTION :Restrict train speed to: {VELOCITY}
STR_TRACE_RESTRICT_REMOVE_SPEED_RESTRICTION :Remove train speed restriction
STR_TRACE_RESTRICT_VALUE_CAPTION :{WHITE}Value
STR_TRACE_RESTRICT_CAPTION :{WHITE}Routefinding restriction
STR_TRACE_RESTRICT_CAPTION_SHARED :{WHITE}Routefinding restriction - shared by {COMMA} signals
@ -4566,6 +4569,8 @@ STR_VEHICLE_INFO_CAPACITY_CAPACITY :{BLACK}Capacity
STR_VEHICLE_INFO_FEEDER_CARGO_VALUE :{BLACK}Transfer Credits: {LTBLUE}{CURRENCY_LONG}
STR_VEHICLE_INFO_SPEED_RESTRICTION :{BLACK}Speed restriction: {LTBLUE}{VELOCITY}
STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS :{BLACK}Servicing interval: {LTBLUE}{COMMA}{NBSP}days{BLACK} Last service: {LTBLUE}{DATE_LONG}
STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT :{BLACK}Servicing interval: {LTBLUE}{COMMA}%{BLACK} Last service: {LTBLUE}{DATE_LONG}
STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Increase servicing interval by 10. Ctrl+Click increases servicing interval by 5

@ -3357,6 +3357,13 @@ bool AfterLoadGame()
}
}
if (SlXvIsFeatureMissing(XSLFI_SPEED_RESTRICTION)) {
Train *t;
FOR_ALL_TRAINS(t) {
t->speed_restriction = 0;
}
}
/*
* Only keep order-backups for network clients (and when replaying).
* If we are a network server or not networking, then we just loaded a previously

@ -110,6 +110,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_STATE_CHECKSUM, XSCF_NULL, 1, 1, "state_checksum", nullptr, nullptr, nullptr },
{ XSLFI_DEBUG, XSCF_IGNORABLE_ALL, 1, 1, "debug", nullptr, nullptr, "DBGL" },
{ XSLFI_FLOW_STAT_FLAGS, XSCF_NULL, 1, 1, "flow_stat_flags", nullptr, nullptr, nullptr },
{ XSLFI_SPEED_RESTRICTION, XSCF_NULL, 1, 1, "speed_restriction", nullptr, nullptr, "VESR" },
{ XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker
};

@ -76,6 +76,7 @@ enum SlXvFeatureIndex {
XSLFI_STATE_CHECKSUM, ///< State checksum
XSLFI_DEBUG, ///< Debugging info
XSLFI_FLOW_STAT_FLAGS, ///< FlowStat flags
XSLFI_SPEED_RESTRICTION, ///< Train speed restrictions
XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit
XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk

@ -796,6 +796,7 @@ const SaveLoad *GetVehicleDescription(VehicleType vt)
SLE_CONDVAR(Train, gv_flags, SLE_UINT16, SLV_139, SL_MAX_VERSION),
SLE_CONDNULL(11, SLV_2, SLV_144), // old reserved space
SLE_CONDVAR_X(Train, reverse_distance, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_REVERSE_AT_WAYPOINT)),
SLE_CONDVAR_X(Train, speed_restriction, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPEED_RESTRICTION)),
SLE_CONDVAR_X(Train, critical_breakdown_count, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_IMPROVED_BREAKDOWNS, 2)),
SLE_END()
@ -1076,7 +1077,46 @@ void Load_VEOX()
}
}
const SaveLoad *GetVehicleSpeedRestrictionDescription()
{
static const SaveLoad _vehicle_speed_restriction_desc[] = {
SLE_VAR(PendingSpeedRestrictionChange, distance, SLE_UINT16),
SLE_VAR(PendingSpeedRestrictionChange, new_speed, SLE_UINT16),
SLE_VAR(PendingSpeedRestrictionChange, prev_speed, SLE_UINT16),
SLE_VAR(PendingSpeedRestrictionChange, flags, SLE_UINT16),
SLE_END()
};
return _vehicle_speed_restriction_desc;
}
void Save_VESR()
{
Train *t;
FOR_ALL_TRAINS(t) {
if (HasBit(t->flags, VRF_PENDING_SPEED_RESTRICTION)) {
auto range = pending_speed_restriction_change_map.equal_range(t->index);
for (auto it = range.first; it != range.second; ++it) {
SlSetArrayIndex(t->index);
PendingSpeedRestrictionChange *ptr = &(it->second);
SlObject(ptr, GetVehicleSpeedRestrictionDescription());
}
}
}
}
void Load_VESR()
{
int index;
while ((index = SlIterateArray()) != -1) {
auto iter = pending_speed_restriction_change_map.insert({ index, {} });
PendingSpeedRestrictionChange *ptr = &(iter->second);
SlObject(ptr, GetVehicleSpeedRestrictionDescription());
}
}
extern const ChunkHandler _veh_chunk_handlers[] = {
{ 'VEHS', Save_VEHS, Load_VEHS, Ptrs_VEHS, nullptr, CH_SPARSE_ARRAY},
{ 'VEOX', Save_VEOX, Load_VEOX, nullptr, nullptr, CH_SPARSE_ARRAY | CH_LAST},
{ 'VEOX', Save_VEOX, Load_VEOX, nullptr, nullptr, CH_SPARSE_ARRAY},
{ 'VESR', Save_VESR, Load_VESR, nullptr, nullptr, CH_SPARSE_ARRAY | CH_LAST},
};

@ -635,6 +635,12 @@ void TraceRestrictProgram::Execute(const Train* v, const TraceRestrictProgramInp
}
break;
case TRIT_SPEED_RESTRICTION: {
out.speed_restriction = GetTraceRestrictValue(item);
out.flags |= TRPRF_SPEED_RETRICTION_SET;
break;
}
default:
NOT_REACHED();
}
@ -804,6 +810,10 @@ CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem>
actions_used_flags |= TRPAUF_REVERSE;
break;
case TRIT_SPEED_RESTRICTION:
actions_used_flags |= TRPAUF_SPEED_RESTRICTION;
break;
default:
return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_UNKNOWN_INSTRUCTION);
}

@ -142,6 +142,7 @@ enum TraceRestrictItemType {
TRIT_COND_END = 48, ///< End (exclusive) of conditional item types, note that this has the same value as TRIT_REVERSE
TRIT_REVERSE = 48, ///< Reverse behind signal
TRIT_SPEED_RESTRICTION = 49, ///< Speed restriction
/* space up to 63 */
};
@ -308,6 +309,7 @@ enum TraceRestrictProgramResultFlags {
TRPRF_WAIT_AT_PBS = 1 << 3, ///< Wait at PBS signal is set
TRPRF_PBS_RES_END_WAIT = 1 << 4, ///< PBS reservations ending at this signal wait is set
TRPRF_REVERSE = 1 << 5, ///< Reverse behind signal
TRPRF_SPEED_RETRICTION_SET = 1 << 6, ///< Speed restriction field set
};
DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramResultFlags)
@ -325,11 +327,12 @@ enum TraceRestrictProgramActionsUsedFlags {
TRPAUF_PBS_RES_END_WAIT = 1 << 7, ///< PBS reservations ending at this signal wait action is present
TRPAUF_PBS_RES_END_SLOT = 1 << 8, ///< PBS reservations ending at this signal slot action is present
TRPAUF_REVERSE = 1 << 9, ///< Reverse behind signal
TRPAUF_SPEED_RESTRICTION = 1 << 10, ///< Speed restriction
};
DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramActionsUsedFlags)
/**
* Enumeration for TraceRestrictProgram::actions_used_flags
* Enumeration for TraceRestrictProgramInput::permitted_slot_operations
*/
enum TraceRestrictProgramInputSlotPermissions {
TRPISP_ACQUIRE = 1 << 0, ///< Slot acquire is permitted
@ -364,6 +367,7 @@ struct TraceRestrictProgramInput {
struct TraceRestrictProgramResult {
uint32 penalty; ///< Total additional pathfinder penalty
TraceRestrictProgramResultFlags flags; ///< Flags of other actions to take
uint16 speed_restriction; ///> Speed restriction to apply (if TRPRF_SPEED_RETRICTION_SET flag present)
TraceRestrictProgramResult()
: penalty(0), flags(static_cast<TraceRestrictProgramResultFlags>(0)) { }
@ -703,6 +707,8 @@ static inline TraceRestrictTypePropertySet GetTraceRestrictTypeProperties(TraceR
out.value_type = TRVT_SLOT_INDEX;
} else if (GetTraceRestrictType(item) == TRIT_REVERSE) {
out.value_type = TRVT_REVERSE;
} else if (GetTraceRestrictType(item) == TRIT_SPEED_RESTRICTION) {
out.value_type = TRVT_SPEED;
} else {
out.value_type = TRVT_NONE;
}

@ -151,6 +151,7 @@ static const StringID _program_insert_str[] = {
STR_TRACE_RESTRICT_WAIT_AT_PBS,
STR_TRACE_RESTRICT_SLOT_OP,
STR_TRACE_RESTRICT_REVERSE,
STR_TRACE_RESTRICT_SPEED_RESTRICTION,
INVALID_STRING_ID
};
static const uint32 _program_insert_else_hide_mask = 8; ///< disable bitmask for else
@ -159,6 +160,7 @@ static const uint32 _program_insert_else_if_hide_mask = 2; ///< disable bitm
static const uint32 _program_wait_pbs_hide_mask = 0x100; ///< disable bitmask for wait at PBS
static const uint32 _program_slot_hide_mask = 0x200; ///< disable bitmask for slot
static const uint32 _program_reverse_hide_mask = 0x400; ///< disable bitmask for reverse
static const uint32 _program_speed_res_hide_mask = 0x800; ///< disable bitmask for speed restriction
static const uint _program_insert_val[] = {
TRIT_COND_UNDEFINED, // if block
TRIT_COND_UNDEFINED | (TRCF_ELSE << 16), // elif block
@ -171,6 +173,7 @@ static const uint _program_insert_val[] = {
TRIT_WAIT_AT_PBS, // wait at PBS signal
TRIT_SLOT, // slot operation
TRIT_REVERSE, // reverse
TRIT_SPEED_RESTRICTION, // speed restriction
};
/** insert drop down list strings and values */
@ -370,6 +373,7 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictG
STR_TRACE_RESTRICT_WAIT_AT_PBS,
STR_TRACE_RESTRICT_SLOT_OP,
STR_TRACE_RESTRICT_REVERSE,
STR_TRACE_RESTRICT_SPEED_RESTRICTION,
INVALID_STRING_ID,
};
static const uint val_action[] = {
@ -380,6 +384,7 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictG
TRIT_WAIT_AT_PBS,
TRIT_SLOT,
TRIT_REVERSE,
TRIT_SPEED_RESTRICTION,
};
static const TraceRestrictDropDownListSet set_action = {
str_action, val_action,
@ -441,7 +446,7 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictG
if (_settings_client.gui.show_adv_tracerestrict_features) {
*hide_mask = 0;
} else {
*hide_mask = is_conditional ? 0xE0000 : 0x70;
*hide_mask = is_conditional ? 0xE0000 : 0xF0;
}
}
return is_conditional ? &set_cond : &set_action;
@ -1230,6 +1235,15 @@ static void DrawInstructionString(const TraceRestrictProgram *prog, TraceRestric
}
break;
case TRIT_SPEED_RESTRICTION:
if (GetTraceRestrictValue(item) != 0) {
SetDParam(0, GetTraceRestrictValue(item));
instruction_string = STR_TRACE_RESTRICT_SET_SPEED_RESTRICTION;
} else {
instruction_string = STR_TRACE_RESTRICT_REMOVE_SPEED_RESTRICTION;
}
break;
default:
NOT_REACHED();
break;
@ -1353,7 +1367,7 @@ public:
if (ElseIfInsertionDryRun(false)) disabled &= ~_program_insert_or_if_hide_mask;
}
}
if (!_settings_client.gui.show_adv_tracerestrict_features) hidden |= _program_slot_hide_mask | _program_wait_pbs_hide_mask | _program_reverse_hide_mask;
if (!_settings_client.gui.show_adv_tracerestrict_features) hidden |= _program_slot_hide_mask | _program_wait_pbs_hide_mask | _program_reverse_hide_mask | _program_speed_res_hide_mask;
this->ShowDropDownListWithValue(&_program_insert, 0, true, TR_WIDGET_INSERT, disabled, hidden, 0);
break;

@ -44,6 +44,7 @@ enum VehicleRailFlags {
VRF_ADVANCE_IN_PLATFORM = 18,
VRF_CONSIST_BREAKDOWN = 19,///< one or more vehicles in this consist have a breakdown of some sort (breakdown_ctr != 0)
VRF_CONSIST_SPEED_REDUCTION = 20,///< one or more vehicles in this consist may be in a depot or on a bridge (may be false positive but not false negative)
VRF_PENDING_SPEED_RESTRICTION = 21,///< This vehicle has one or more pending speed restriction changes
VRF_IS_BROKEN = (1 << VRF_BREAKDOWN_POWER) | (1 << VRF_BREAKDOWN_SPEED) | (1 << VRF_BREAKDOWN_STOPPED), ///< Bitmask of all flags that indicate a broken train (braking is not included)
};
@ -120,6 +121,7 @@ struct Train FINAL : public GroundVehicle<Train, VEH_TRAIN> {
uint16 reverse_distance;
uint16 tunnel_bridge_signal_num;
uint16 speed_restriction;
/** We don't want GCC to zero our struct! It already is zeroed and has an index! */
Train() : GroundVehicleBase() {}

@ -617,6 +617,9 @@ int Train::GetCurrentMaxSpeed() const
if (HasBit(this->flags, VRF_BREAKDOWN_SPEED)) {
max_speed = min(max_speed, this->GetBreakdownSpeed());
}
if (this->speed_restriction != 0) {
max_speed = min(max_speed, this->speed_restriction);
}
if (this->current_order.IsType(OT_LOADING_ADVANCE)) max_speed = min(max_speed, 15);
@ -824,6 +827,7 @@ static CommandCost CmdBuildRailWagon(TileIndex tile, DoCommandFlag flags, const
v->track = TRACK_BIT_DEPOT;
v->vehstatus = VS_HIDDEN | VS_DEFPAL;
v->reverse_distance = 0;
v->speed_restriction = 0;
v->SetWagon();
@ -969,6 +973,7 @@ CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, const Engin
v->last_station_visited = INVALID_STATION;
v->last_loading_station = INVALID_STATION;
v->reverse_distance = 0;
v->speed_restriction = 0;
v->engine_type = e->index;
v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback
@ -1668,6 +1673,7 @@ CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data, uint3
/* Copy other important data from the front engine */
new_head->CopyVehicleConfigAndStatistics(first);
new_head->speed_restriction = first->speed_restriction;
GroupStatistics::CountVehicle(new_head, 1); // after copying over the profit
} else if (v->IsPrimaryVehicle() && data & (MAKE_ORDER_BACKUP_FLAG >> 20)) {
OrderBackup::Backup(v, user);
@ -2268,6 +2274,20 @@ void ReverseTrainDirection(Train *v)
TryPathReserve(re_reserve_trains[i], true);
}
if (HasBit(v->flags, VRF_PENDING_SPEED_RESTRICTION)) {
auto range = pending_speed_restriction_change_map.equal_range(v->index);
for (auto it = range.first; it != range.second;) {
it->second.distance = (v->gcache.cached_total_length + (HasBit(it->second.flags, PSRCF_DIAGONAL) ? 8 : 4)) - it->second.distance;
if (it->second.distance == 0) {
v->speed_restriction = it->second.prev_speed;
it = pending_speed_restriction_change_map.erase(it);
} else {
std::swap(it->second.prev_speed, it->second.new_speed);
++it;
}
}
}
/* If we are inside a depot after reversing, don't bother with path reserving. */
if (v->track == TRACK_BIT_DEPOT) {
/* Can't be stuck here as inside a depot is always a safe tile. */
@ -4099,7 +4119,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
const Trackdir dir = FindFirstTrackdir(trackdirbits);
if (HasSignalOnTrack(gp.new_tile, TrackdirToTrack(dir))) {
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(gp.new_tile, TrackdirToTrack(dir));
if (prog && prog->actions_used_flags & (TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_RELEASE_FRONT | TRPAUF_REVERSE)) {
if (prog && prog->actions_used_flags & (TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_RELEASE_FRONT | TRPAUF_REVERSE | TRPAUF_SPEED_RESTRICTION)) {
TraceRestrictProgramResult out;
TraceRestrictProgramInput input(gp.new_tile, dir, nullptr, nullptr);
input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_RELEASE_FRONT;
@ -4109,6 +4129,17 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
v->reverse_distance = v->gcache.cached_total_length + (IsDiagonalTrack(TrackdirToTrack(dir)) ? 16 : 8);
SetWindowDirty(WC_VEHICLE_VIEW, v->index);
}
if (out.flags & TRPRF_SPEED_RETRICTION_SET) {
SetBit(v->flags, VRF_PENDING_SPEED_RESTRICTION);
auto range = pending_speed_restriction_change_map.equal_range(v->index);
for (auto it = range.first; it != range.second; ++it) {
if ((uint16) (out.speed_restriction + 0xFFFF) < (uint16) (it->second.new_speed + 0xFFFF)) it->second.new_speed = out.speed_restriction;
}
uint16 flags = 0;
if (IsDiagonalTrack(TrackdirToTrack(dir))) SetBit(flags, PSRCF_DIAGONAL);
pending_speed_restriction_change_map.insert({ v->index, { (uint16) (v->gcache.cached_total_length + (HasBit(flags, PSRCF_DIAGONAL) ? 8 : 4)), out.speed_restriction, v->speed_restriction, flags } });
if ((uint16) (out.speed_restriction + 0xFFFF) < (uint16) (v->speed_restriction + 0xFFFF)) v->speed_restriction = out.speed_restriction;
}
}
}
}
@ -4370,6 +4401,18 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
if (v->reverse_distance > 1) {
v->reverse_distance--;
}
if (HasBit(v->flags, VRF_PENDING_SPEED_RESTRICTION)) {
auto range = pending_speed_restriction_change_map.equal_range(v->index);
if (range.first == range.second) ClrBit(v->flags, VRF_PENDING_SPEED_RESTRICTION);
for (auto it = range.first; it != range.second;) {
if (--it->second.distance == 0) {
v->speed_restriction = it->second.new_speed;
it = pending_speed_restriction_change_map.erase(it);
} else {
++it;
}
}
}
/* update the Z position of the vehicle */
int old_z = v->UpdateInclination(gp.new_tile != gp.old_tile, false, v->track == TRACK_BIT_WORMHOLE);

@ -103,6 +103,8 @@ INSTANTIATE_POOL_METHODS(Vehicle)
static btree::btree_set<VehicleID> _vehicles_to_pay_repair;
static btree::btree_set<VehicleID> _vehicles_to_sell;
std::unordered_multimap<VehicleID, PendingSpeedRestrictionChange> pending_speed_restriction_change_map;
/**
* Determine shared bounds of all sprites.
* @param[out] bounds Shared bounds.
@ -985,6 +987,10 @@ void Vehicle::PreDestructor()
TraceRestrictRemoveVehicleFromAllSlots(this->index);
ClrBit(Train::From(this)->flags, VRF_HAVE_SLOT);
}
if (this->type == VEH_TRAIN && HasBit(Train::From(this)->flags, VRF_PENDING_SPEED_RESTRICTION)) {
pending_speed_restriction_change_map.erase(this->index);
ClrBit(Train::From(this)->flags, VRF_PENDING_SPEED_RESTRICTION);
}
if (this->Previous() == nullptr) {
InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
@ -1049,6 +1055,14 @@ Vehicle::~Vehicle()
DeleteNewGRFInspectWindow(GetGrfSpecFeature(this->type), this->index);
}
/**
* Vehicle pool is about to be cleaned
*/
void Vehicle::PreCleanPool()
{
pending_speed_restriction_change_map.clear();
}
/**
* Adds a vehicle to the list of vehicles that visited a depot this tick
* @param *v vehicle to add

@ -25,6 +25,7 @@
#include "network/network.h"
#include <list>
#include <map>
#include <unordered_map>
CommandCost CmdRefitVehicle(TileIndex, DoCommandFlag, uint32, uint32, const char*);
@ -202,6 +203,18 @@ struct VehicleSpriteSeq {
void Draw(int x, int y, PaletteID default_pal, bool force_pal) const;
};
enum PendingSpeedRestrictionChangeFlags {
PSRCF_DIAGONAL = 0,
};
struct PendingSpeedRestrictionChange {
uint16 distance;
uint16 new_speed;
uint16 prev_speed;
uint16 flags;
};
extern std::unordered_multimap<VehicleID, PendingSpeedRestrictionChange> pending_speed_restriction_change_map;
/** A vehicle pool for a little over 1 million vehicles. */
typedef Pool<Vehicle, VehicleID, 512, 0xFF000> VehiclePool;
extern VehiclePool _vehicle_pool;
@ -237,6 +250,8 @@ public:
friend void AfterLoadVehicles(bool part_of_load); ///< So we can set the #previous and #first pointers while loading
friend bool LoadOldVehicle(LoadgameState *ls, int num); ///< So we can set the proper next pointer while loading
static void PreCleanPool();
TileIndex tile; ///< Current tile index
/**

@ -2364,6 +2364,7 @@ struct VehicleDetailsWindow : Window {
bool vehicle_group_line_shown;
bool vehicle_weight_ratio_line_shown;
bool vehicle_slots_line_shown;
bool vehicle_speed_restriction_line_shown;
/** Initialize a newly created vehicle details window */
VehicleDetailsWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
@ -2460,6 +2461,12 @@ struct VehicleDetailsWindow : Window {
return HasBit(Train::From(v)->flags, VRF_HAVE_SLOT);
}
bool ShouldShowSpeedRestrictionLine(const Vehicle *v) const
{
if (v->type != VEH_TRAIN) return false;
return Train::From(v)->speed_restriction != 0;
}
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
{
switch (widget) {
@ -2469,10 +2476,12 @@ struct VehicleDetailsWindow : Window {
this->vehicle_group_line_shown = ShouldShowGroupLine(v);
this->vehicle_weight_ratio_line_shown = ShouldShowWeightRatioLine(v);
this->vehicle_slots_line_shown = ShouldShowSlotsLine(v);
this->vehicle_speed_restriction_line_shown = ShouldShowSpeedRestrictionLine(v);
int lines = 4;
if (this->vehicle_group_line_shown) lines++;
if (this->vehicle_weight_ratio_line_shown) lines++;
if (this->vehicle_slots_line_shown) lines++;
if (this->vehicle_speed_restriction_line_shown) lines++;
size->height = WD_FRAMERECT_TOP + lines * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM;
for (uint i = 0; i < 5; i++) SetDParamMaxValue(i, INT16_MAX);
@ -2723,9 +2732,17 @@ struct VehicleDetailsWindow : Window {
y += FONT_HEIGHT_NORMAL;
}
bool should_show_speed_restriction = this->ShouldShowSpeedRestrictionLine(v);
if (should_show_speed_restriction) {
SetDParam(0, Train::From(v)->speed_restriction);
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_SPEED_RESTRICTION);
y += FONT_HEIGHT_NORMAL;
}
if (this->vehicle_weight_ratio_line_shown != should_show_weight_ratio ||
this->vehicle_weight_ratio_line_shown != should_show_weight_ratio ||
this->vehicle_slots_line_shown != should_show_slots) {
this->vehicle_slots_line_shown != should_show_slots ||
this->vehicle_speed_restriction_line_shown != should_show_speed_restriction) {
const_cast<VehicleDetailsWindow *>(this)->ReInit();
}
break;

Loading…
Cancel
Save