Merge branch 'tracerestrict-sx' into jgrpp
Conflicts: src/saveload/extended_ver_sl.cpp
This commit is contained in:
@@ -2520,6 +2520,8 @@ STR_TRACE_RESTRICT_END :End
|
|||||||
STR_TRACE_RESTRICT_PF_DENY :Deny
|
STR_TRACE_RESTRICT_PF_DENY :Deny
|
||||||
STR_TRACE_RESTRICT_PF_ALLOW :Allow
|
STR_TRACE_RESTRICT_PF_ALLOW :Allow
|
||||||
STR_TRACE_RESTRICT_PF_ALLOW_LONG :Allow (cancel previous Deny)
|
STR_TRACE_RESTRICT_PF_ALLOW_LONG :Allow (cancel previous Deny)
|
||||||
|
STR_TRACE_RESTRICT_RESERVE_THROUGH :Reserve through
|
||||||
|
STR_TRACE_RESTRICT_RESERVE_THROUGH_CANCEL :Cancel reserve through
|
||||||
STR_TRACE_RESTRICT_PF_PENALTY :Penalty
|
STR_TRACE_RESTRICT_PF_PENALTY :Penalty
|
||||||
STR_TRACE_RESTRICT_PF_VALUE_SMALL :small
|
STR_TRACE_RESTRICT_PF_VALUE_SMALL :small
|
||||||
STR_TRACE_RESTRICT_PF_VALUE_MEDIUM :medium
|
STR_TRACE_RESTRICT_PF_VALUE_MEDIUM :medium
|
||||||
@@ -2567,6 +2569,7 @@ STR_TRACE_RESTRICT_ERROR_VALIDATE_END_CONDSTACK :Validation fail
|
|||||||
STR_TRACE_RESTRICT_ERROR_VALIDATE_NO_IF :Validation failed: else/endif without opening if
|
STR_TRACE_RESTRICT_ERROR_VALIDATE_NO_IF :Validation failed: else/endif without opening if
|
||||||
STR_TRACE_RESTRICT_ERROR_VALIDATE_DUP_ELSE :Validation failed: duplicate else
|
STR_TRACE_RESTRICT_ERROR_VALIDATE_DUP_ELSE :Validation failed: duplicate else
|
||||||
STR_TRACE_RESTRICT_ERROR_VALIDATE_ELIF_NO_IF :Validation failed: else if without opening if
|
STR_TRACE_RESTRICT_ERROR_VALIDATE_ELIF_NO_IF :Validation failed: else if without opening if
|
||||||
|
STR_TRACE_RESTRICT_ERROR_VALIDATE_UNKNOWN_INSTRUCTION :Validation failed: unknown instruction
|
||||||
STR_TRACE_RESTRICT_ERROR_SOURCE_SAME_AS_TARGET :Source and target signals are the same
|
STR_TRACE_RESTRICT_ERROR_SOURCE_SAME_AS_TARGET :Source and target signals are the same
|
||||||
STR_TRACE_RESTRICT_ERROR_CAN_T_RESET_SIGNAL :{WHITE}Can't reset signal
|
STR_TRACE_RESTRICT_ERROR_CAN_T_RESET_SIGNAL :{WHITE}Can't reset signal
|
||||||
STR_TRACE_RESTRICT_ERROR_CAN_T_COPY_PROGRAM :{WHITE}Can't copy program
|
STR_TRACE_RESTRICT_ERROR_CAN_T_COPY_PROGRAM :{WHITE}Can't copy program
|
||||||
|
@@ -264,7 +264,7 @@ private:
|
|||||||
inline bool ExecuteTraceRestrict(Node& n, TileIndex tile, Trackdir trackdir, int& cost, TraceRestrictProgramResult &out)
|
inline bool ExecuteTraceRestrict(Node& n, TileIndex tile, Trackdir trackdir, int& cost, TraceRestrictProgramResult &out)
|
||||||
{
|
{
|
||||||
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(trackdir));
|
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(trackdir));
|
||||||
if (prog) {
|
if (prog && prog->actions_used_flags & TRPAUF_PF) {
|
||||||
prog->Execute(Yapf().GetVehicle(), TraceRestrictProgramInput(tile, trackdir, &TraceRestrictPreviousSignalCallback, &n), out);
|
prog->Execute(Yapf().GetVehicle(), TraceRestrictProgramInput(tile, trackdir, &TraceRestrictPreviousSignalCallback, &n), out);
|
||||||
if (out.flags & TRPRF_DENY) {
|
if (out.flags & TRPRF_DENY) {
|
||||||
n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
|
n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
|
||||||
|
@@ -97,7 +97,7 @@ private:
|
|||||||
m_res_fail_td = td;
|
m_res_fail_td = td;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!TryReserveRailTrack(tile, TrackdirToTrack(td))) {
|
if (!TryReserveRailTrackdir(tile, td)) {
|
||||||
/* Tile couldn't be reserved, undo. */
|
/* Tile couldn't be reserved, undo. */
|
||||||
m_res_fail_tile = tile;
|
m_res_fail_tile = tile;
|
||||||
m_res_fail_td = td;
|
m_res_fail_td = td;
|
||||||
|
75
src/pbs.cpp
75
src/pbs.cpp
@@ -14,6 +14,7 @@
|
|||||||
#include "vehicle_func.h"
|
#include "vehicle_func.h"
|
||||||
#include "newgrf_station.h"
|
#include "newgrf_station.h"
|
||||||
#include "pathfinder/follow_track.hpp"
|
#include "pathfinder/follow_track.hpp"
|
||||||
|
#include "tracerestrict.h"
|
||||||
|
|
||||||
#include "safeguards.h"
|
#include "safeguards.h"
|
||||||
|
|
||||||
@@ -71,6 +72,24 @@ void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool
|
|||||||
} while (IsCompatibleTrainStationTile(tile, start));
|
} while (IsCompatibleTrainStationTile(tile, start));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to reserve a specific track on a tile
|
||||||
|
* This also sets PBS signals to green if reserving through the facing track direction
|
||||||
|
* @param tile the tile
|
||||||
|
* @param t the track
|
||||||
|
* @param trigger_stations whether to call station randomisation trigger
|
||||||
|
* @return \c true if reservation was successful, i.e. the track was
|
||||||
|
* free and didn't cross any other reserved tracks.
|
||||||
|
*/
|
||||||
|
bool TryReserveRailTrackdir(TileIndex tile, Trackdir td, bool trigger_stations)
|
||||||
|
{
|
||||||
|
bool success = TryReserveRailTrack(tile, TrackdirToTrack(td), trigger_stations);
|
||||||
|
if (success && HasPbsSignalOnTrackdir(tile, td)) {
|
||||||
|
SetSignalStateByTrackdir(tile, td, SIGNAL_STATE_GREEN);
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to reserve a specific track on a tile
|
* Try to reserve a specific track on a tile
|
||||||
* @param tile the tile
|
* @param tile the tile
|
||||||
@@ -369,6 +388,46 @@ Train *GetTrainForReservation(TileIndex tile, Track track)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is called to retrieve the previous signal, as required
|
||||||
|
* This is not run all the time as it is somewhat expensive and most restrictions will not test for the previous signal
|
||||||
|
*/
|
||||||
|
static TileIndex IsSafeWaitingPositionTraceRestrictPreviousSignalCallback(const Train *v, const void *)
|
||||||
|
{
|
||||||
|
// scan forwards from vehicle position, for the case that train is waiting at/approaching PBS signal
|
||||||
|
|
||||||
|
TileIndex tile = v->tile;
|
||||||
|
Trackdir trackdir = v->GetVehicleTrackdir();
|
||||||
|
|
||||||
|
CFollowTrackRail ft(v);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir)) {
|
||||||
|
if (HasPbsSignalOnTrackdir(tile, trackdir)) {
|
||||||
|
// found PBS signal
|
||||||
|
return tile;
|
||||||
|
} else {
|
||||||
|
// wrong type of signal
|
||||||
|
return INVALID_TILE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// advance to next tile
|
||||||
|
if (!ft.Follow(tile, trackdir)) {
|
||||||
|
// ran out of track
|
||||||
|
return INVALID_TILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) {
|
||||||
|
// reached a junction tile
|
||||||
|
return INVALID_TILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
tile = ft.m_new_tile;
|
||||||
|
trackdir = FindFirstTrackdir(ft.m_new_td_bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether a certain track on a tile is a safe position to end a path.
|
* Determine whether a certain track on a tile is a safe position to end a path.
|
||||||
*
|
*
|
||||||
@@ -404,8 +463,20 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo
|
|||||||
|
|
||||||
if (ft.m_new_td_bits != TRACKDIR_BIT_NONE && KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) {
|
if (ft.m_new_td_bits != TRACKDIR_BIT_NONE && KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) {
|
||||||
Trackdir td = FindFirstTrackdir(ft.m_new_td_bits);
|
Trackdir td = FindFirstTrackdir(ft.m_new_td_bits);
|
||||||
/* PBS signal on next trackdir? Safe position. */
|
/* PBS signal on next trackdir? Conditionally safe position. */
|
||||||
if (HasPbsSignalOnTrackdir(ft.m_new_tile, td)) return true;
|
if (HasPbsSignalOnTrackdir(ft.m_new_tile, td)) {
|
||||||
|
if (IsRestrictedSignal(ft.m_new_tile)) {
|
||||||
|
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(ft.m_new_tile, TrackdirToTrack(td));
|
||||||
|
if (prog && prog->actions_used_flags & TRPAUF_RESERVE_THROUGH) {
|
||||||
|
TraceRestrictProgramResult out;
|
||||||
|
prog->Execute(v, TraceRestrictProgramInput(tile, trackdir, &IsSafeWaitingPositionTraceRestrictPreviousSignalCallback, nullptr), out);
|
||||||
|
if (out.flags & TRPRF_RESERVE_THROUGH) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
/* One-way PBS signal against us? Safe if end-of-line is allowed. */
|
/* One-way PBS signal against us? Safe if end-of-line is allowed. */
|
||||||
if (IsTileType(ft.m_new_tile, MP_RAILWAY) && HasSignalOnTrackdir(ft.m_new_tile, ReverseTrackdir(td)) &&
|
if (IsTileType(ft.m_new_tile, MP_RAILWAY) && HasSignalOnTrackdir(ft.m_new_tile, ReverseTrackdir(td)) &&
|
||||||
GetSignalType(ft.m_new_tile, TrackdirToTrack(td)) == SIGTYPE_PBS_ONEWAY) {
|
GetSignalType(ft.m_new_tile, TrackdirToTrack(td)) == SIGTYPE_PBS_ONEWAY) {
|
||||||
|
@@ -22,6 +22,7 @@ TrackBits GetReservedTrackbits(TileIndex t);
|
|||||||
void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool b);
|
void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool b);
|
||||||
|
|
||||||
bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations = true);
|
bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations = true);
|
||||||
|
bool TryReserveRailTrackdir(TileIndex tile, Trackdir td, bool trigger_stations = true);
|
||||||
void UnreserveRailTrack(TileIndex tile, Track t);
|
void UnreserveRailTrack(TileIndex tile, Track t);
|
||||||
|
|
||||||
/** This struct contains information about the end of a reserved path. */
|
/** This struct contains information about the end of a reserved path. */
|
||||||
|
@@ -46,7 +46,7 @@ std::vector<uint32> _sl_xv_discardable_chunk_ids; ///< list of chunks
|
|||||||
static const uint32 _sl_xv_slxi_chunk_version = 0; ///< current version os SLXI chunk
|
static const uint32 _sl_xv_slxi_chunk_version = 0; ///< current version os SLXI chunk
|
||||||
|
|
||||||
const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
||||||
{ XSLFI_TRACE_RESTRICT, XSCF_NULL, 2, 2, "tracerestrict", NULL, NULL, "TRRM,TRRP" },
|
{ XSLFI_TRACE_RESTRICT, XSCF_NULL, 3, 3, "tracerestrict", NULL, NULL, "TRRM,TRRP" },
|
||||||
{ XSLFI_PROG_SIGS, XSCF_NULL, 1, 1, "programmable_signals", NULL, NULL, "SPRG" },
|
{ XSLFI_PROG_SIGS, XSCF_NULL, 1, 1, "programmable_signals", NULL, NULL, "SPRG" },
|
||||||
{ XSLFI_ADJACENT_CROSSINGS, XSCF_NULL, 1, 1, "adjacent_crossings", NULL, NULL, NULL },
|
{ XSLFI_ADJACENT_CROSSINGS, XSCF_NULL, 1, 1, "adjacent_crossings", NULL, NULL, NULL },
|
||||||
{ XSLFI_DEPARTURE_BOARDS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "departure_boards", NULL, NULL, NULL },
|
{ XSLFI_DEPARTURE_BOARDS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "departure_boards", NULL, NULL, NULL },
|
||||||
|
@@ -11,9 +11,10 @@
|
|||||||
|
|
||||||
#include "../stdafx.h"
|
#include "../stdafx.h"
|
||||||
#include "../tracerestrict.h"
|
#include "../tracerestrict.h"
|
||||||
|
#include "../strings_func.h"
|
||||||
|
#include "../string_func.h"
|
||||||
#include "saveload.h"
|
#include "saveload.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "saveload.h"
|
|
||||||
|
|
||||||
static const SaveLoad _trace_restrict_mapping_desc[] = {
|
static const SaveLoad _trace_restrict_mapping_desc[] = {
|
||||||
SLE_VAR(TraceRestrictMappingItem, program_id, SLE_UINT32),
|
SLE_VAR(TraceRestrictMappingItem, program_id, SLE_UINT32),
|
||||||
@@ -66,7 +67,20 @@ static void Load_TRRP()
|
|||||||
SlObject(&stub, _trace_restrict_program_stub_desc);
|
SlObject(&stub, _trace_restrict_program_stub_desc);
|
||||||
prog->items.resize(stub.length);
|
prog->items.resize(stub.length);
|
||||||
SlArray(&(prog->items[0]), stub.length, SLE_UINT32);
|
SlArray(&(prog->items[0]), stub.length, SLE_UINT32);
|
||||||
assert(prog->Validate().Succeeded());
|
CommandCost validation_result = prog->Validate();
|
||||||
|
if (validation_result.Failed()) {
|
||||||
|
char str[4096];
|
||||||
|
char *strend = str + seprintf(str, lastof(str), "Trace restrict program %d: %s\nProgram dump:",
|
||||||
|
index, GetStringPtr(validation_result.GetErrorMessage()));
|
||||||
|
for (unsigned int i = 0; i < prog->items.size(); i++) {
|
||||||
|
if (i % 3) {
|
||||||
|
strend += seprintf(strend, lastof(str), " %08X", prog->items[i]);
|
||||||
|
} else {
|
||||||
|
strend += seprintf(strend, lastof(str), "\n%4u: %08X", i, prog->items[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SlErrorCorrupt(str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -382,6 +382,14 @@ void TraceRestrictProgram::Execute(const Train* v, const TraceRestrictProgramInp
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TRIT_RESERVE_THROUGH:
|
||||||
|
if (GetTraceRestrictValue(item)) {
|
||||||
|
out.flags &= ~TRPRF_RESERVE_THROUGH;
|
||||||
|
} else {
|
||||||
|
out.flags |= TRPRF_RESERVE_THROUGH;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
NOT_REACHED();
|
NOT_REACHED();
|
||||||
}
|
}
|
||||||
@@ -405,18 +413,28 @@ void TraceRestrictProgram::DecrementRefCount() {
|
|||||||
/**
|
/**
|
||||||
* Validate a instruction list
|
* Validate a instruction list
|
||||||
* Returns successful result if program seems OK
|
* Returns successful result if program seems OK
|
||||||
* This only validates that conditional nesting is correct, at present
|
* This only validates that conditional nesting is correct,
|
||||||
|
* and that all instructions have a known type, at present
|
||||||
*/
|
*/
|
||||||
CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem> &items) {
|
CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem> &items, TraceRestrictProgramActionsUsedFlags &actions_used_flags) {
|
||||||
// static to avoid needing to re-alloc/resize on each execution
|
// static to avoid needing to re-alloc/resize on each execution
|
||||||
static std::vector<TraceRestrictCondStackFlags> condstack;
|
static std::vector<TraceRestrictCondStackFlags> condstack;
|
||||||
condstack.clear();
|
condstack.clear();
|
||||||
|
actions_used_flags = static_cast<TraceRestrictProgramActionsUsedFlags>(0);
|
||||||
|
|
||||||
size_t size = items.size();
|
size_t size = items.size();
|
||||||
for (size_t i = 0; i < size; i++) {
|
for (size_t i = 0; i < size; i++) {
|
||||||
TraceRestrictItem item = items[i];
|
TraceRestrictItem item = items[i];
|
||||||
TraceRestrictItemType type = GetTraceRestrictType(item);
|
TraceRestrictItemType type = GetTraceRestrictType(item);
|
||||||
|
|
||||||
|
// check multi-word instructions
|
||||||
|
if (IsTraceRestrictDoubleItem(item)) {
|
||||||
|
i++;
|
||||||
|
if (i >= size) {
|
||||||
|
return_cmd_error(STR_TRACE_RESTRICT_ERROR_OFFSET_TOO_LARGE); // instruction ran off end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (IsTraceRestrictConditional(item)) {
|
if (IsTraceRestrictConditional(item)) {
|
||||||
TraceRestrictCondFlags condflags = GetTraceRestrictCondFlags(item);
|
TraceRestrictCondFlags condflags = GetTraceRestrictCondFlags(item);
|
||||||
|
|
||||||
@@ -446,13 +464,36 @@ CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem>
|
|||||||
}
|
}
|
||||||
HandleCondition(condstack, condflags, true);
|
HandleCondition(condstack, condflags, true);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// check multi-word instructions
|
switch (GetTraceRestrictType(item)) {
|
||||||
if (IsTraceRestrictDoubleItem(item)) {
|
case TRIT_COND_ENDIF:
|
||||||
i++;
|
case TRIT_COND_UNDEFINED:
|
||||||
if (i >= size) {
|
case TRIT_COND_TRAIN_LENGTH:
|
||||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_OFFSET_TOO_LARGE); // instruction ran off end
|
case TRIT_COND_MAX_SPEED:
|
||||||
|
case TRIT_COND_CURRENT_ORDER:
|
||||||
|
case TRIT_COND_NEXT_ORDER:
|
||||||
|
case TRIT_COND_LAST_STATION:
|
||||||
|
case TRIT_COND_CARGO:
|
||||||
|
case TRIT_COND_ENTRY_DIRECTION:
|
||||||
|
case TRIT_COND_PBS_ENTRY_SIGNAL:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_UNKNOWN_INSTRUCTION);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
switch (GetTraceRestrictType(item)) {
|
||||||
|
case TRIT_PF_DENY:
|
||||||
|
case TRIT_PF_PENALTY:
|
||||||
|
actions_used_flags |= TRPAUF_PF;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRIT_RESERVE_THROUGH:
|
||||||
|
actions_used_flags |= TRPAUF_RESERVE_THROUGH;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_UNKNOWN_INSTRUCTION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -502,6 +543,7 @@ void SetTraceRestrictValueDefault(TraceRestrictItem &item, TraceRestrictValueTyp
|
|||||||
case TRVT_DENY:
|
case TRVT_DENY:
|
||||||
case TRVT_SPEED:
|
case TRVT_SPEED:
|
||||||
case TRVT_TILE_INDEX:
|
case TRVT_TILE_INDEX:
|
||||||
|
case TRVT_RESERVE_THROUGH:
|
||||||
SetTraceRestrictValue(item, 0);
|
SetTraceRestrictValue(item, 0);
|
||||||
SetTraceRestrictAuxField(item, 0);
|
SetTraceRestrictAuxField(item, 0);
|
||||||
break;
|
break;
|
||||||
@@ -807,7 +849,7 @@ CommandCost CmdProgramSignalTraceRestrict(TileIndex tile, DoCommandFlag flags, u
|
|||||||
|
|
||||||
case TRDCT_REMOVE_ITEM: {
|
case TRDCT_REMOVE_ITEM: {
|
||||||
TraceRestrictItem old_item = *TraceRestrictProgram::InstructionAt(items, offset);
|
TraceRestrictItem old_item = *TraceRestrictProgram::InstructionAt(items, offset);
|
||||||
if (IsTraceRestrictConditional(old_item)) {
|
if (IsTraceRestrictConditional(old_item) && GetTraceRestrictCondFlags(old_item) != TRCF_OR) {
|
||||||
bool remove_whole_block = false;
|
bool remove_whole_block = false;
|
||||||
if (GetTraceRestrictCondFlags(old_item) == 0) {
|
if (GetTraceRestrictCondFlags(old_item) == 0) {
|
||||||
if (GetTraceRestrictType(old_item) == TRIT_COND_ENDIF) {
|
if (GetTraceRestrictType(old_item) == TRIT_COND_ENDIF) {
|
||||||
@@ -878,7 +920,8 @@ CommandCost CmdProgramSignalTraceRestrict(TileIndex tile, DoCommandFlag flags, u
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandCost validation_result = TraceRestrictProgram::Validate(items);
|
TraceRestrictProgramActionsUsedFlags actions_used_flags;
|
||||||
|
CommandCost validation_result = TraceRestrictProgram::Validate(items, actions_used_flags);
|
||||||
if (validation_result.Failed()) {
|
if (validation_result.Failed()) {
|
||||||
return validation_result;
|
return validation_result;
|
||||||
}
|
}
|
||||||
@@ -888,6 +931,7 @@ CommandCost CmdProgramSignalTraceRestrict(TileIndex tile, DoCommandFlag flags, u
|
|||||||
|
|
||||||
// move in modified program
|
// move in modified program
|
||||||
prog->items.swap(items);
|
prog->items.swap(items);
|
||||||
|
prog->actions_used_flags = actions_used_flags;
|
||||||
|
|
||||||
if (prog->items.size() == 0 && prog->refcount == 1) {
|
if (prog->items.size() == 0 && prog->refcount == 1) {
|
||||||
// program is empty, and this tile is the only reference to it
|
// program is empty, and this tile is the only reference to it
|
||||||
|
@@ -97,6 +97,7 @@ enum TraceRestrictItemType {
|
|||||||
TRIT_NULL = 0, ///< Null-type, not in programs and not valid for execution, mainly used with TraceRestrictNullTypeSpecialValue for start/end
|
TRIT_NULL = 0, ///< Null-type, not in programs and not valid for execution, mainly used with TraceRestrictNullTypeSpecialValue for start/end
|
||||||
TRIT_PF_DENY = 1, ///< Pathfinder deny/allow
|
TRIT_PF_DENY = 1, ///< Pathfinder deny/allow
|
||||||
TRIT_PF_PENALTY = 2, ///< Add to pathfinder penalty
|
TRIT_PF_PENALTY = 2, ///< Add to pathfinder penalty
|
||||||
|
TRIT_RESERVE_THROUGH = 3, ///< Reserve through PBS signal
|
||||||
|
|
||||||
TRIT_COND_BEGIN = 8, ///< Start of conditional item types, note that this has the save value as TRIT_COND_ENDIF
|
TRIT_COND_BEGIN = 8, ///< Start of conditional item types, note that this has the save value as TRIT_COND_ENDIF
|
||||||
TRIT_COND_ENDIF = 8, ///< This is an endif block or an else block
|
TRIT_COND_ENDIF = 8, ///< This is an endif block or an else block
|
||||||
@@ -192,9 +193,19 @@ enum TraceRestrictPathfinderPenaltyPresetIndex {
|
|||||||
*/
|
*/
|
||||||
enum TraceRestrictProgramResultFlags {
|
enum TraceRestrictProgramResultFlags {
|
||||||
TRPRF_DENY = 1 << 0, ///< Pathfinder deny is set
|
TRPRF_DENY = 1 << 0, ///< Pathfinder deny is set
|
||||||
|
TRPRF_RESERVE_THROUGH = 1 << 1, ///< Reserve through is set
|
||||||
};
|
};
|
||||||
DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramResultFlags)
|
DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramResultFlags)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration for TraceRestrictProgram::actions_used_flags
|
||||||
|
*/
|
||||||
|
enum TraceRestrictProgramActionsUsedFlags {
|
||||||
|
TRPAUF_PF = 1 << 0, ///< Pathfinder deny or penalty are present
|
||||||
|
TRPAUF_RESERVE_THROUGH = 1 << 1, ///< Reserve through action is present
|
||||||
|
};
|
||||||
|
DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramActionsUsedFlags)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execution input of a TraceRestrictProgram
|
* Execution input of a TraceRestrictProgram
|
||||||
*/
|
*/
|
||||||
@@ -228,9 +239,10 @@ struct TraceRestrictProgramResult {
|
|||||||
struct TraceRestrictProgram : TraceRestrictProgramPool::PoolItem<&_tracerestrictprogram_pool> {
|
struct TraceRestrictProgram : TraceRestrictProgramPool::PoolItem<&_tracerestrictprogram_pool> {
|
||||||
std::vector<TraceRestrictItem> items;
|
std::vector<TraceRestrictItem> items;
|
||||||
uint32 refcount;
|
uint32 refcount;
|
||||||
|
TraceRestrictProgramActionsUsedFlags actions_used_flags;
|
||||||
|
|
||||||
TraceRestrictProgram()
|
TraceRestrictProgram()
|
||||||
: refcount(0) { }
|
: refcount(0), actions_used_flags(static_cast<TraceRestrictProgramActionsUsedFlags>(0)) { }
|
||||||
|
|
||||||
void Execute(const Train *v, const TraceRestrictProgramInput &input, TraceRestrictProgramResult &out) const;
|
void Execute(const Train *v, const TraceRestrictProgramInput &input, TraceRestrictProgramResult &out) const;
|
||||||
|
|
||||||
@@ -241,7 +253,7 @@ struct TraceRestrictProgram : TraceRestrictProgramPool::PoolItem<&_tracerestrict
|
|||||||
|
|
||||||
void DecrementRefCount();
|
void DecrementRefCount();
|
||||||
|
|
||||||
static CommandCost Validate(const std::vector<TraceRestrictItem> &items);
|
static CommandCost Validate(const std::vector<TraceRestrictItem> &items, TraceRestrictProgramActionsUsedFlags &actions_used_flags);
|
||||||
|
|
||||||
static size_t InstructionOffsetToArrayOffset(const std::vector<TraceRestrictItem> &items, size_t offset);
|
static size_t InstructionOffsetToArrayOffset(const std::vector<TraceRestrictItem> &items, size_t offset);
|
||||||
|
|
||||||
@@ -283,10 +295,11 @@ struct TraceRestrictProgram : TraceRestrictProgramPool::PoolItem<&_tracerestrict
|
|||||||
return items.begin() + TraceRestrictProgram::InstructionOffsetToArrayOffset(items, instruction_offset);
|
return items.begin() + TraceRestrictProgram::InstructionOffsetToArrayOffset(items, instruction_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Call validation function on current program instruction list and set actions_used_flags */
|
||||||
* Call validation function on current program instruction list
|
CommandCost Validate()
|
||||||
*/
|
{
|
||||||
CommandCost Validate() const { return TraceRestrictProgram::Validate(items); }
|
return TraceRestrictProgram::Validate(items, actions_used_flags);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Get TraceRestrictItem type field */
|
/** Get TraceRestrictItem type field */
|
||||||
@@ -392,6 +405,7 @@ enum TraceRestrictValueType {
|
|||||||
TRVT_DIRECTION = 7, ///< takes a TraceRestrictDirectionTypeSpecialValue
|
TRVT_DIRECTION = 7, ///< takes a TraceRestrictDirectionTypeSpecialValue
|
||||||
TRVT_TILE_INDEX = 8, ///< takes a TileIndex in the next item slot
|
TRVT_TILE_INDEX = 8, ///< takes a TileIndex in the next item slot
|
||||||
TRVT_PF_PENALTY = 9, ///< takes a pathfinder penalty value or preset index, as per the auxiliary field as type: TraceRestrictPathfinderPenaltyAuxField
|
TRVT_PF_PENALTY = 9, ///< takes a pathfinder penalty value or preset index, as per the auxiliary field as type: TraceRestrictPathfinderPenaltyAuxField
|
||||||
|
TRVT_RESERVE_THROUGH = 10,///< takes a value 0 = reserve through, 1 = cancel previous reserve through
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -463,6 +477,8 @@ static inline TraceRestrictTypePropertySet GetTraceRestrictTypeProperties(TraceR
|
|||||||
out.value_type = TRVT_PF_PENALTY;
|
out.value_type = TRVT_PF_PENALTY;
|
||||||
} else if (GetTraceRestrictType(item) == TRIT_PF_DENY) {
|
} else if (GetTraceRestrictType(item) == TRIT_PF_DENY) {
|
||||||
out.value_type = TRVT_DENY;
|
out.value_type = TRVT_DENY;
|
||||||
|
} else if (GetTraceRestrictType(item) == TRIT_RESERVE_THROUGH) {
|
||||||
|
out.value_type = TRVT_RESERVE_THROUGH;
|
||||||
} else {
|
} else {
|
||||||
out.value_type = TRVT_NONE;
|
out.value_type = TRVT_NONE;
|
||||||
}
|
}
|
||||||
|
@@ -115,20 +115,24 @@ struct TraceRestrictDropDownListSet {
|
|||||||
static const StringID _program_insert_str[] = {
|
static const StringID _program_insert_str[] = {
|
||||||
STR_TRACE_RESTRICT_CONDITIONAL_IF,
|
STR_TRACE_RESTRICT_CONDITIONAL_IF,
|
||||||
STR_TRACE_RESTRICT_CONDITIONAL_ELIF,
|
STR_TRACE_RESTRICT_CONDITIONAL_ELIF,
|
||||||
|
STR_TRACE_RESTRICT_CONDITIONAL_ORIF,
|
||||||
STR_TRACE_RESTRICT_CONDITIONAL_ELSE,
|
STR_TRACE_RESTRICT_CONDITIONAL_ELSE,
|
||||||
STR_TRACE_RESTRICT_PF_DENY,
|
STR_TRACE_RESTRICT_PF_DENY,
|
||||||
STR_TRACE_RESTRICT_PF_PENALTY,
|
STR_TRACE_RESTRICT_PF_PENALTY,
|
||||||
|
STR_TRACE_RESTRICT_RESERVE_THROUGH,
|
||||||
INVALID_STRING_ID
|
INVALID_STRING_ID
|
||||||
};
|
};
|
||||||
static const uint _program_insert_else_flag = 0x100; ///< flag to indicate that TRCF_ELSE should be set
|
static const uint32 _program_insert_else_hide_mask = 8; ///< disable bitmask for else
|
||||||
static const uint32 _program_insert_else_hide_mask = 4; ///< disable bitmask for else
|
static const uint32 _program_insert_or_if_hide_mask = 4; ///< disable bitmask for elif
|
||||||
static const uint32 _program_insert_else_if_hide_mask = 2; ///< disable bitmask for elif
|
static const uint32 _program_insert_else_if_hide_mask = 2; ///< disable bitmask for elif
|
||||||
static const uint _program_insert_val[] = {
|
static const uint _program_insert_val[] = {
|
||||||
TRIT_COND_UNDEFINED, // if block
|
TRIT_COND_UNDEFINED, // if block
|
||||||
TRIT_COND_UNDEFINED | _program_insert_else_flag, // elif block
|
TRIT_COND_UNDEFINED | (TRCF_ELSE << 16), // elif block
|
||||||
TRIT_COND_ENDIF | _program_insert_else_flag, // else block
|
TRIT_COND_UNDEFINED | (TRCF_OR << 16), // orif block
|
||||||
|
TRIT_COND_ENDIF | (TRCF_ELSE << 16), // else block
|
||||||
TRIT_PF_DENY, // deny
|
TRIT_PF_DENY, // deny
|
||||||
TRIT_PF_PENALTY, // penalty
|
TRIT_PF_PENALTY, // penalty
|
||||||
|
TRIT_RESERVE_THROUGH, // reserve through
|
||||||
};
|
};
|
||||||
|
|
||||||
/** insert drop down list strings and values */
|
/** insert drop down list strings and values */
|
||||||
@@ -151,6 +155,21 @@ static const TraceRestrictDropDownListSet _deny_value = {
|
|||||||
_deny_value_str, _deny_value_val,
|
_deny_value_str, _deny_value_val,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const StringID _reserve_through_value_str[] = {
|
||||||
|
STR_TRACE_RESTRICT_RESERVE_THROUGH,
|
||||||
|
STR_TRACE_RESTRICT_RESERVE_THROUGH_CANCEL,
|
||||||
|
INVALID_STRING_ID
|
||||||
|
};
|
||||||
|
static const uint _reserve_through_value_val[] = {
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** value drop down list for deny types strings and values */
|
||||||
|
static const TraceRestrictDropDownListSet _reserve_through_value = {
|
||||||
|
_reserve_through_value_str, _reserve_through_value_val,
|
||||||
|
};
|
||||||
|
|
||||||
static const StringID _direction_value_str[] = {
|
static const StringID _direction_value_str[] = {
|
||||||
STR_TRACE_RESTRICT_DIRECTION_FRONT,
|
STR_TRACE_RESTRICT_DIRECTION_FRONT,
|
||||||
STR_TRACE_RESTRICT_DIRECTION_BACK,
|
STR_TRACE_RESTRICT_DIRECTION_BACK,
|
||||||
@@ -209,11 +228,13 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictI
|
|||||||
static const StringID str_action[] = {
|
static const StringID str_action[] = {
|
||||||
STR_TRACE_RESTRICT_PF_DENY,
|
STR_TRACE_RESTRICT_PF_DENY,
|
||||||
STR_TRACE_RESTRICT_PF_PENALTY,
|
STR_TRACE_RESTRICT_PF_PENALTY,
|
||||||
|
STR_TRACE_RESTRICT_RESERVE_THROUGH,
|
||||||
INVALID_STRING_ID,
|
INVALID_STRING_ID,
|
||||||
};
|
};
|
||||||
static const uint val_action[] = {
|
static const uint val_action[] = {
|
||||||
TRIT_PF_DENY,
|
TRIT_PF_DENY,
|
||||||
TRIT_PF_PENALTY,
|
TRIT_PF_PENALTY,
|
||||||
|
TRIT_RESERVE_THROUGH,
|
||||||
};
|
};
|
||||||
static const TraceRestrictDropDownListSet set_action = {
|
static const TraceRestrictDropDownListSet set_action = {
|
||||||
str_action, val_action,
|
str_action, val_action,
|
||||||
@@ -640,6 +661,10 @@ static void DrawInstructionString(const TraceRestrictProgram *prog, TraceRestric
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TRIT_RESERVE_THROUGH:
|
||||||
|
instruction_string = GetTraceRestrictValue(item) ? STR_TRACE_RESTRICT_RESERVE_THROUGH_CANCEL : STR_TRACE_RESTRICT_RESERVE_THROUGH;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
NOT_REACHED();
|
NOT_REACHED();
|
||||||
break;
|
break;
|
||||||
@@ -732,7 +757,7 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 disabled = 0;
|
uint32 disabled = _program_insert_or_if_hide_mask;
|
||||||
TraceRestrictItem item = this->GetSelected();
|
TraceRestrictItem item = this->GetSelected();
|
||||||
if (GetTraceRestrictType(item) == TRIT_COND_ENDIF ||
|
if (GetTraceRestrictType(item) == TRIT_COND_ENDIF ||
|
||||||
(IsTraceRestrictConditional(item) && GetTraceRestrictCondFlags(item) != 0)) {
|
(IsTraceRestrictConditional(item) && GetTraceRestrictCondFlags(item) != 0)) {
|
||||||
@@ -744,6 +769,15 @@ public:
|
|||||||
// can't insert else/end if here
|
// can't insert else/end if here
|
||||||
disabled |= _program_insert_else_hide_mask | _program_insert_else_if_hide_mask;
|
disabled |= _program_insert_else_hide_mask | _program_insert_else_if_hide_mask;
|
||||||
}
|
}
|
||||||
|
if (this->selected_instruction > 1) {
|
||||||
|
TraceRestrictItem prev_item = this->GetItem(this->GetProgram(), this->selected_instruction - 1);
|
||||||
|
if (IsTraceRestrictConditional(prev_item) && GetTraceRestrictType(prev_item) != TRIT_COND_ENDIF) {
|
||||||
|
// previous item is either: an if, or an else/or if
|
||||||
|
|
||||||
|
// else if has same validation rules as or if, use it instead of creating another test function
|
||||||
|
if (ElseIfInsertionDryRun(false)) disabled &= ~_program_insert_or_if_hide_mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this->ShowDropDownListWithValue(&_program_insert, 0, true, TR_WIDGET_INSERT, disabled, 0, 0);
|
this->ShowDropDownListWithValue(&_program_insert, 0, true, TR_WIDGET_INSERT, disabled, 0, 0);
|
||||||
break;
|
break;
|
||||||
@@ -832,6 +866,10 @@ public:
|
|||||||
this->ShowDropDownListWithValue(&_pf_penalty_dropdown, GetPathfinderPenaltyDropdownIndex(item), false, TR_WIDGET_VALUE_DROPDOWN, 0, 0, 0);
|
this->ShowDropDownListWithValue(&_pf_penalty_dropdown, GetPathfinderPenaltyDropdownIndex(item), false, TR_WIDGET_VALUE_DROPDOWN, 0, 0, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TRVT_RESERVE_THROUGH:
|
||||||
|
this->ShowDropDownListWithValue(&_reserve_through_value, GetTraceRestrictValue(item), false, TR_WIDGET_VALUE_DROPDOWN, 0, 0, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -914,13 +952,10 @@ public:
|
|||||||
case TR_WIDGET_INSERT: {
|
case TR_WIDGET_INSERT: {
|
||||||
TraceRestrictItem insert_item = 0;
|
TraceRestrictItem insert_item = 0;
|
||||||
|
|
||||||
bool have_else = false;
|
TraceRestrictCondFlags cond_flags = static_cast<TraceRestrictCondFlags>(value >> 16);
|
||||||
if (value & _program_insert_else_flag) {
|
value &= 0xFFFF;
|
||||||
value &= ~_program_insert_else_flag;
|
|
||||||
have_else = true;
|
|
||||||
}
|
|
||||||
SetTraceRestrictTypeAndNormalise(insert_item, static_cast<TraceRestrictItemType>(value));
|
SetTraceRestrictTypeAndNormalise(insert_item, static_cast<TraceRestrictItemType>(value));
|
||||||
if (have_else) SetTraceRestrictCondFlags(insert_item, TRCF_ELSE); // this needs to happen after calling SetTraceRestrictTypeAndNormalise
|
SetTraceRestrictCondFlags(insert_item, cond_flags); // this needs to happen after calling SetTraceRestrictTypeAndNormalise
|
||||||
|
|
||||||
this->expecting_inserted_item = insert_item;
|
this->expecting_inserted_item = insert_item;
|
||||||
TraceRestrictDoCommandP(this->tile, this->track, TRDCT_INSERT_ITEM, this->selected_instruction - 1, insert_item, STR_TRACE_RESTRICT_ERROR_CAN_T_INSERT_ITEM);
|
TraceRestrictDoCommandP(this->tile, this->track, TRDCT_INSERT_ITEM, this->selected_instruction - 1, insert_item, STR_TRACE_RESTRICT_ERROR_CAN_T_INSERT_ITEM);
|
||||||
@@ -1573,6 +1608,13 @@ private:
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TRVT_RESERVE_THROUGH:
|
||||||
|
right_sel->SetDisplayedPlane(DPR_VALUE_DROPDOWN);
|
||||||
|
this->EnableWidget(TR_WIDGET_VALUE_DROPDOWN);
|
||||||
|
this->GetWidget<NWidgetCore>(TR_WIDGET_VALUE_DROPDOWN)->widget_data =
|
||||||
|
GetTraceRestrictValue(item) ? STR_TRACE_RESTRICT_RESERVE_THROUGH_CANCEL : STR_TRACE_RESTRICT_RESERVE_THROUGH;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1638,7 +1680,8 @@ private:
|
|||||||
items.insert(items.begin() + array_offset, item);
|
items.insert(items.begin() + array_offset, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TraceRestrictProgram::Validate(items).Succeeded();
|
TraceRestrictProgramActionsUsedFlags actions_used_flags;
|
||||||
|
return TraceRestrictProgram::Validate(items, actions_used_flags).Succeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -2526,7 +2526,7 @@ static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks,
|
|||||||
return PBSTileInfo(tile, cur_td, true);
|
return PBSTileInfo(tile, cur_td, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryReserveRailTrack(tile, TrackdirToTrack(cur_td))) break;
|
if (!TryReserveRailTrackdir(tile, cur_td)) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ft.m_err == CFollowTrackRail::EC_OWNER || ft.m_err == CFollowTrackRail::EC_NO_WAY) {
|
if (ft.m_err == CFollowTrackRail::EC_OWNER || ft.m_err == CFollowTrackRail::EC_NO_WAY) {
|
||||||
|
Reference in New Issue
Block a user