Merge branch 'tracerestrict-sx' into jgrpp
This commit is contained in:
@@ -1273,6 +1273,10 @@
|
||||
<ClCompile Include="..\src\os\windows\win32.cpp" />
|
||||
<ClInclude Include="..\src\thread\thread.h" />
|
||||
<ClCompile Include="..\src\thread\thread_win32.cpp" />
|
||||
<ClInclude Include="..\src\tracerestrict.h" />
|
||||
<ClCompile Include="..\src\tracerestrict.cpp" />
|
||||
<ClCompile Include="..\src\tracerestrict_gui.cpp" />
|
||||
<ClCompile Include="..\src\saveload\tracerestrict_sl.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\media\openttd.ico" />
|
||||
|
@@ -3048,6 +3048,18 @@
|
||||
<ClCompile Include="..\src\thread\thread_win32.cpp">
|
||||
<Filter>Threading</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\src\tracerestrict.h">
|
||||
<Filter>Threading</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\src\tracerestrict.cpp">
|
||||
<Filter>Threading</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\tracerestrict_gui.cpp">
|
||||
<Filter>Threading</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\saveload\tracerestrict_sl.cpp">
|
||||
<Filter>Threading</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\media\openttd.ico" />
|
||||
|
@@ -4490,6 +4490,22 @@
|
||||
RelativePath=".\..\src\thread\thread_win32.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\tracerestrict.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\tracerestrict.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\tracerestrict_gui.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\saveload\tracerestrict_sl.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\..\media\openttd.ico"
|
||||
|
@@ -4487,6 +4487,22 @@
|
||||
RelativePath=".\..\src\thread\thread_win32.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\tracerestrict.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\tracerestrict.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\tracerestrict_gui.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\saveload\tracerestrict_sl.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\..\media\openttd.ico"
|
||||
|
@@ -1195,3 +1195,8 @@ thread/thread.h
|
||||
#else
|
||||
thread/thread_none.cpp
|
||||
#end
|
||||
|
||||
tracerestrict.h
|
||||
tracerestrict.cpp
|
||||
tracerestrict_gui.cpp
|
||||
saveload/tracerestrict_sl.cpp
|
||||
|
@@ -198,6 +198,8 @@ CommandProc CmdSetTimetableStart;
|
||||
|
||||
CommandProc CmdOpenCloseAirport;
|
||||
|
||||
CommandProc CmdProgramSignalTraceRestrict;
|
||||
|
||||
#define DEF_CMD(proc, flags, type) {proc, #proc, (CommandFlags)flags, type}
|
||||
|
||||
/**
|
||||
@@ -354,6 +356,8 @@ static const Command _command_proc_table[] = {
|
||||
DEF_CMD(CmdSetTimetableStart, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_TIMETABLE_START
|
||||
|
||||
DEF_CMD(CmdOpenCloseAirport, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_OPEN_CLOSE_AIRPORT
|
||||
|
||||
DEF_CMD(CmdProgramSignalTraceRestrict, 0, CMDT_OTHER_MANAGEMENT ), // CMD_PROGRAM_TRACERESTRICT_SIGNAL
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@@ -329,6 +329,8 @@ enum Commands {
|
||||
|
||||
CMD_OPEN_CLOSE_AIRPORT, ///< open/close an airport to incoming aircraft
|
||||
|
||||
CMD_PROGRAM_TRACERESTRICT_SIGNAL, ///< modify a signal tracerestrict program
|
||||
|
||||
CMD_END, ///< Must ALWAYS be on the end of this list!! (period)
|
||||
};
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include "core/pool_func.hpp"
|
||||
#include "vehicle_gui.h"
|
||||
#include "vehiclelist.h"
|
||||
#include "tracerestrict.h"
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
@@ -42,6 +43,8 @@ Depot::~Depot()
|
||||
/* Clear the depot from all order-lists */
|
||||
RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, this->index);
|
||||
|
||||
TraceRestrictRemoveDestinationID(TROCAF_DEPOT, this->index);
|
||||
|
||||
/* Delete the depot-window */
|
||||
DeleteWindowById(WC_VEHICLE_DEPOT, this->xy);
|
||||
|
||||
|
@@ -2370,6 +2370,93 @@ STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Dragging
|
||||
STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}Decrease dragging signal density
|
||||
STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Increase dragging signal density
|
||||
|
||||
# Tracerestrict GUI
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_EQUALS :is
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_NOT_EQUALS :is not
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_LESS_THAN :<
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_LESS_EQUALS :<=
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_MORE_THAN :>
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_MORE_EQUALS :>=
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_CARGO_EQUALS :can carry
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_CARGO_NOT_EQUALS :can't carry
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_IF :If
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_ELIF :Else if
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_ORIF :Or if
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_ELSE :Else
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_ENDIF :End if
|
||||
STR_TRACE_RESTRICT_VARIABLE_TRAIN_LENGTH :train length
|
||||
STR_TRACE_RESTRICT_VARIABLE_MAX_SPEED :max speed
|
||||
STR_TRACE_RESTRICT_VARIABLE_CURRENT_ORDER :current order
|
||||
STR_TRACE_RESTRICT_VARIABLE_NEXT_ORDER :next order
|
||||
STR_TRACE_RESTRICT_VARIABLE_LAST_VISITED_STATION :last visited station
|
||||
STR_TRACE_RESTRICT_VARIABLE_CARGO :cargo
|
||||
STR_TRACE_RESTRICT_VARIABLE_ENTRY_DIRECTION :entry direction
|
||||
STR_TRACE_RESTRICT_VARIABLE_UNDEFINED :undefined
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_COMPARE_INTEGER :{STRING} {STRING} {STRING} {COMMA} then
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_COMPARE_SPEED :{STRING} {STRING} {STRING} {VELOCITY} then
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_ORDER_STATION :{STRING} {STRING} {STRING} {STATION} then
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_ORDER_WAYPOINT :{STRING} {STRING} {STRING} {WAYPOINT} then
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_ORDER_DEPOT :{STRING} {STRING} {STRING} {DEPOT} then
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_CARGO :{STRING} train {STRING} cargo: {STRING} then
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_ENTRY_DIRECTION :{STRING} train {STRING} entering from {STRING} tile edge then
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_ENTRY_SIGNAL_FACE :{STRING} train {STRING} entering from {STRING} of signal then
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_UNDEFINED :{STRING} {STRING} {STRING} {RED}undefined {BLACK}{STRING}then
|
||||
STR_TRACE_RESTRICT_CONDITIONAL_COMPARE_UNDEFINED :{STRING} {RED}undefined {BLACK}{STRING}then
|
||||
STR_TRACE_RESTRICT_PF_PENALTY_ITEM :Add pathfinder penalty: {COMMA}
|
||||
STR_TRACE_RESTRICT_WHITE :{WHITE}
|
||||
STR_TRACE_RESTRICT_START :Start
|
||||
STR_TRACE_RESTRICT_END :End
|
||||
STR_TRACE_RESTRICT_PF_DENY :Deny
|
||||
STR_TRACE_RESTRICT_PF_ALLOW :Allow
|
||||
STR_TRACE_RESTRICT_PF_ALLOW_LONG :Allow (cancel previous Deny)
|
||||
STR_TRACE_RESTRICT_PF_PENALTY :Penalty
|
||||
STR_TRACE_RESTRICT_DIRECTION_FRONT :front
|
||||
STR_TRACE_RESTRICT_DIRECTION_BACK :back
|
||||
STR_TRACE_RESTRICT_DIRECTION_NE :north-east
|
||||
STR_TRACE_RESTRICT_DIRECTION_SE :south-east
|
||||
STR_TRACE_RESTRICT_DIRECTION_SW :south-west
|
||||
STR_TRACE_RESTRICT_DIRECTION_NW :north-west
|
||||
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
|
||||
STR_TRACE_RESTRICT_TYPE_TOOLTIP :{BLACK}Type
|
||||
STR_TRACE_RESTRICT_COND_COMPARATOR_TOOLTIP :{BLACK}Comparison operator
|
||||
STR_TRACE_RESTRICT_COND_VALUE_TOOLTIP :{BLACK}Value
|
||||
STR_TRACE_RESTRICT_CONDFLAGS_TOOLTIP :{BLACK}Condition type
|
||||
STR_TRACE_RESTRICT_GOTO_SIGNAL_TOOLTIP :{BLACK}Go to signal
|
||||
STR_TRACE_RESTRICT_INSERT :{BLACK}Insert
|
||||
STR_TRACE_RESTRICT_REMOVE :{BLACK}Remove
|
||||
STR_TRACE_RESTRICT_RESET :{BLACK}Reset
|
||||
STR_TRACE_RESTRICT_COPY :{BLACK}Copy
|
||||
STR_TRACE_RESTRICT_SHARE :{BLACK}Share
|
||||
STR_TRACE_RESTRICT_UNSHARE :{BLACK}Unshare
|
||||
STR_TRACE_RESTRICT_SELECT_TARGET :{BLACK}Select Target
|
||||
STR_TRACE_RESTRICT_INSERT_TOOLTIP :{BLACK}Insert an instruction
|
||||
STR_TRACE_RESTRICT_REMOVE_TOOLTIP :{BLACK}Remove the selected instruction
|
||||
STR_TRACE_RESTRICT_RESET_TOOLTIP :{BLACK}Reset the current signal (without affecting shared programs)
|
||||
STR_TRACE_RESTRICT_COPY_TOOLTIP :{BLACK}Copy program from another signal
|
||||
STR_TRACE_RESTRICT_SHARE_TOOLTIP :{BLACK}Share program with another signal
|
||||
STR_TRACE_RESTRICT_UNSHARE_TOOLTIP :{BLACK}Stop sharing program with other signals, create a copy of the program
|
||||
STR_TRACE_RESTRICT_SIGNAL_GUI_TOOLTIP :{BLACK}Routefinding restriction
|
||||
STR_TRACE_RESTRICT_INSTRUCTION_LIST_TOOLTIP :{BLACK}Click an instruction to select it{}Ctrl+Click to scroll to the instruction's target (if any)
|
||||
STR_TRACE_RESTRICT_ERROR_CAN_T_INSERT_ITEM :{WHITE}Can't insert instruction
|
||||
STR_TRACE_RESTRICT_ERROR_CAN_T_MODIFY_ITEM :{WHITE}Can't modify instruction
|
||||
STR_TRACE_RESTRICT_ERROR_CAN_T_REMOVE_ITEM :{WHITE}Can't remove instruction
|
||||
STR_TRACE_RESTRICT_ERROR_VALUE_TOO_LARGE :{WHITE}Value too large, maximum is {COMMA}
|
||||
STR_TRACE_RESTRICT_ERROR_NO_PROGRAM :No trace restrict program exists
|
||||
STR_TRACE_RESTRICT_ERROR_OFFSET_TOO_LARGE :Offset too large
|
||||
STR_TRACE_RESTRICT_ERROR_CAN_T_CHANGE_CONDITIONALITY :Can't change conditionality
|
||||
STR_TRACE_RESTRICT_ERROR_CAN_T_REMOVE_ENDIF :Can't remove an 'end if'
|
||||
STR_TRACE_RESTRICT_ERROR_VALIDATE_END_CONDSTACK :Validation failed: condstack non-empty at exit
|
||||
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_ELIF_NO_IF :Validation failed: else if without opening if
|
||||
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_COPY_PROGRAM :{WHITE}Can't copy program
|
||||
STR_TRACE_RESTRICT_ERROR_CAN_T_SHARE_PROGRAM :{WHITE}Can't share program
|
||||
STR_TRACE_RESTRICT_ERROR_CAN_T_UNSHARE_PROGRAM :{WHITE}Can't unshare program
|
||||
|
||||
# Bridge selection window
|
||||
STR_SELECT_RAIL_BRIDGE_CAPTION :{WHITE}Select Rail Bridge
|
||||
STR_SELECT_ROAD_BRIDGE_CAPTION :{WHITE}Select Road Bridge
|
||||
@@ -2625,6 +2712,8 @@ STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS :{STRING} track
|
||||
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS :{STRING} track with path and one-way path signals
|
||||
STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT :{STRING} train depot
|
||||
|
||||
STR_LAI_RAIL_DESCRIPTION_RESTRICTED_SIGNAL :{STRING1} (restricted)
|
||||
|
||||
STR_LAI_ROAD_DESCRIPTION_ROAD :Road
|
||||
STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS :Road with street lights
|
||||
STR_LAI_ROAD_DESCRIPTION_TREE_LINED_ROAD :Tree-lined road
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include "core/pool_type.hpp"
|
||||
#include "game/game.hpp"
|
||||
#include "linkgraph/linkgraphschedule.h"
|
||||
#include "tracerestrict.h"
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
@@ -72,6 +73,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin
|
||||
}
|
||||
|
||||
LinkGraphSchedule::Clear();
|
||||
ClearTraceRestrictMapping();
|
||||
PoolBase::Clean(PT_NORMAL);
|
||||
|
||||
ResetPersistentNewGRFData();
|
||||
|
@@ -175,6 +175,7 @@ public:
|
||||
|
||||
/* Tiletype */
|
||||
SetDParam(0, td.dparam[0]);
|
||||
SetDParam(1, td.dparam[1]);
|
||||
GetString(this->landinfo_data[line_nr], td.str, lastof(this->landinfo_data[line_nr]));
|
||||
line_nr++;
|
||||
|
||||
|
@@ -65,6 +65,7 @@
|
||||
#include "viewport_sprite_sorter.h"
|
||||
|
||||
#include "linkgraph/linkgraphschedule.h"
|
||||
#include "tracerestrict.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
@@ -302,6 +303,7 @@ static void ShutdownGame()
|
||||
#endif
|
||||
|
||||
LinkGraphSchedule::Clear();
|
||||
ClearTraceRestrictMapping();
|
||||
PoolBase::Clean(PT_ALL);
|
||||
|
||||
/* No NewGRFs were loaded when it was still bootstrapping. */
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#define YAPF_COSTRAIL_HPP
|
||||
|
||||
#include "../../pbs.h"
|
||||
#include "../../tracerestrict.h"
|
||||
|
||||
template <class Types>
|
||||
class CYapfCostRailT
|
||||
@@ -180,6 +181,30 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
// returns true if ExecuteTraceRestrict should be called
|
||||
inline bool ShouldCheckTraceRestrict(Node& n, TileIndex tile)
|
||||
{
|
||||
return n.m_num_signals_passed < m_sig_look_ahead_costs.Size() &&
|
||||
IsRestrictedSignal(tile);
|
||||
}
|
||||
|
||||
// returns true if dead end bit has been set
|
||||
inline bool ExecuteTraceRestrict(Node& n, TileIndex tile, Trackdir trackdir, int& cost, TraceRestrictProgramResult &out)
|
||||
{
|
||||
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(trackdir));
|
||||
if (prog) {
|
||||
prog->Execute(Yapf().GetVehicle(), TraceRestrictProgramInput(tile, trackdir), out);
|
||||
if (out.flags & TRPRF_DENY) {
|
||||
n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
|
||||
return true;
|
||||
}
|
||||
cost += out.penalty;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
int SignalCost(Node& n, TileIndex tile, Trackdir trackdir)
|
||||
{
|
||||
int cost = 0;
|
||||
@@ -239,6 +264,13 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
if (ShouldCheckTraceRestrict(n, tile)) {
|
||||
TraceRestrictProgramResult out;
|
||||
if (ExecuteTraceRestrict(n, tile, trackdir, cost, out)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
n.m_num_signals_passed++;
|
||||
n.m_segment->m_last_signal_tile = tile;
|
||||
n.m_segment->m_last_signal_td = trackdir;
|
||||
@@ -246,6 +278,13 @@ public:
|
||||
|
||||
if (has_signal_against && IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) {
|
||||
cost += n.m_num_signals_passed < Yapf().PfGetSettings().rail_look_ahead_max_signals ? Yapf().PfGetSettings().rail_pbs_signal_back_penalty : 0;
|
||||
|
||||
if (ShouldCheckTraceRestrict(n, tile)) {
|
||||
TraceRestrictProgramResult out;
|
||||
if (ExecuteTraceRestrict(n, tile, trackdir, cost, out)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include "strings_func.h"
|
||||
#include "company_gui.h"
|
||||
#include "object_map.h"
|
||||
#include "tracerestrict.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
#include "table/railtypes.h"
|
||||
@@ -1452,6 +1453,7 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1
|
||||
SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
|
||||
Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
|
||||
DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
|
||||
TraceRestrictNotifySignalRemoval(tile, track);
|
||||
|
||||
/* removed last signal from tile? */
|
||||
if (GetPresentSignals(tile) == 0) {
|
||||
@@ -2768,6 +2770,12 @@ static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
|
||||
}
|
||||
|
||||
td->str = signal_type[secondary_signal][primary_signal];
|
||||
|
||||
if (IsRestrictedSignal(tile)) {
|
||||
SetDParamX(td->dparam, 0, td->str);
|
||||
SetDParamX(td->dparam, 1, rti->strings.name);
|
||||
td->str = STR_LAI_RAIL_DESCRIPTION_RESTRICTED_SIGNAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#include "vehicle_func.h"
|
||||
#include "zoom_func.h"
|
||||
#include "rail_gui.h"
|
||||
#include "tracerestrict.h"
|
||||
|
||||
#include "station_map.h"
|
||||
#include "tunnelbridge_map.h"
|
||||
@@ -49,6 +50,7 @@ static DiagDirection _build_depot_direction; ///< Currently selected depot direc
|
||||
static byte _waypoint_count = 1; ///< Number of waypoint types
|
||||
static byte _cur_waypoint_type; ///< Currently selected waypoint type
|
||||
static bool _convert_signal_button; ///< convert signal button in the signal GUI pressed
|
||||
static bool _trace_restrict_button; ///< trace restrict button in the signal GUI pressed
|
||||
static SignalVariant _cur_signal_variant; ///< set the signal variant (for signal GUI)
|
||||
static SignalType _cur_signal_type; ///< set the signal type (for signal GUI)
|
||||
|
||||
@@ -224,6 +226,10 @@ static void GenericPlaceSignals(TileIndex tile)
|
||||
|
||||
if (_remove_button_clicked) {
|
||||
DoCommandP(tile, track, 0, CMD_REMOVE_SIGNALS | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM), CcPlaySound1E);
|
||||
} else if (_trace_restrict_button) {
|
||||
if (IsPlainRailTile(tile) && HasTrack(tile, track) && HasSignalOnTrack(tile, track)) {
|
||||
ShowTraceRestrictProgramWindow(tile, track);
|
||||
}
|
||||
} else {
|
||||
const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
|
||||
|
||||
@@ -1518,6 +1524,7 @@ public:
|
||||
~BuildSignalWindow()
|
||||
{
|
||||
_convert_signal_button = false;
|
||||
_trace_restrict_button = false;
|
||||
}
|
||||
|
||||
virtual void OnInit()
|
||||
@@ -1602,6 +1609,12 @@ public:
|
||||
|
||||
case WID_BS_CONVERT:
|
||||
_convert_signal_button = !_convert_signal_button;
|
||||
if (_convert_signal_button) _trace_restrict_button = false;
|
||||
break;
|
||||
|
||||
case WID_BS_TRACE_RESTRICT:
|
||||
_trace_restrict_button = !_trace_restrict_button;
|
||||
if (_trace_restrict_button) _convert_signal_button = false;
|
||||
break;
|
||||
|
||||
case WID_BS_DRAG_SIGNALS_DENSITY_DECREASE:
|
||||
@@ -1635,6 +1648,7 @@ public:
|
||||
this->LowerWidget((_cur_signal_variant == SIG_ELECTRIC ? WID_BS_ELECTRIC_NORM : WID_BS_SEMAPHORE_NORM) + _cur_signal_type);
|
||||
|
||||
this->SetWidgetLoweredState(WID_BS_CONVERT, _convert_signal_button);
|
||||
this->SetWidgetLoweredState(WID_BS_TRACE_RESTRICT, _trace_restrict_button);
|
||||
|
||||
this->SetWidgetDisabledState(WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, _settings_client.gui.drag_signals_density == 1);
|
||||
this->SetWidgetDisabledState(WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, _settings_client.gui.drag_signals_density == 20);
|
||||
@@ -1656,6 +1670,7 @@ static const NWidgetPart _nested_signal_builder_widgets[] = {
|
||||
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP), EndContainer(), SetFill(1, 1),
|
||||
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1),
|
||||
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_BS_CONVERT), SetDataTip(SPR_IMG_SIGNAL_CONVERT, STR_BUILD_SIGNAL_CONVERT_TOOLTIP), SetFill(1, 1),
|
||||
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_BS_TRACE_RESTRICT), SetDataTip(SPR_IMG_SETTINGS, STR_TRACE_RESTRICT_SIGNAL_GUI_TOOLTIP), SetFill(1, 1),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
|
||||
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_NORM), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP), EndContainer(), SetFill(1, 1),
|
||||
@@ -1674,6 +1689,7 @@ static const NWidgetPart _nested_signal_builder_widgets[] = {
|
||||
EndContainer(),
|
||||
NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0),
|
||||
EndContainer(),
|
||||
NWidget(WWT_PANEL, COLOUR_DARK_GREEN), EndContainer(), SetFill(1, 1),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
};
|
||||
@@ -1974,6 +1990,7 @@ void InitializeRailGUI()
|
||||
SetDefaultRailGui();
|
||||
|
||||
_convert_signal_button = false;
|
||||
_trace_restrict_button = false;
|
||||
_cur_signal_type = _default_signal_type[_settings_client.gui.default_signal_type];
|
||||
ResetSignalVariant();
|
||||
}
|
||||
|
@@ -479,6 +479,26 @@ static inline bool HasOnewaySignalBlockingTrackdir(TileIndex tile, Trackdir td)
|
||||
!HasSignalOnTrackdir(tile, td) && IsOnewaySignal(tile, TrackdirToTrack(td));
|
||||
}
|
||||
|
||||
/**
|
||||
* Does signal tile have "one or more trace restrict mappings present" bit set
|
||||
* @param tile the tile to check
|
||||
*/
|
||||
static inline bool IsRestrictedSignal(TileIndex tile)
|
||||
{
|
||||
assert(GetRailTileType(tile) == RAIL_TILE_SIGNALS);
|
||||
return (bool) GB(_m[tile].m2, 12, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set signal tile "one or more trace restrict mappings present" bit
|
||||
* @param tile the tile to set
|
||||
*/
|
||||
static inline void SetRestrictedSignal(TileIndex tile, bool is_restricted)
|
||||
{
|
||||
assert(GetRailTileType(tile) == RAIL_TILE_SIGNALS);
|
||||
SB(_m[tile].m2, 12, 1, is_restricted);
|
||||
}
|
||||
|
||||
|
||||
RailType GetTileRailType(TileIndex tile);
|
||||
|
||||
|
@@ -2988,6 +2988,8 @@ bool AfterLoadGame()
|
||||
ResetSignalHandlers();
|
||||
|
||||
AfterLoadLinkGraphs();
|
||||
|
||||
AfterLoadTraceRestrict();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -45,6 +45,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
|
||||
|
||||
const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
||||
{ XSLFI_TRACE_RESTRICT, XSCF_NULL, 1, 1, "tracerestrict", NULL, NULL, "TRRM,TRRP" },
|
||||
{ XSLFI_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker
|
||||
};
|
||||
|
||||
@@ -121,7 +122,12 @@ void SlXvCheckSpecialSavegameVersions()
|
||||
{
|
||||
extern uint16 _sl_version;
|
||||
|
||||
// TODO: check for savegame versions
|
||||
if (_sl_version == 2000) {
|
||||
DEBUG(sl, 1, "Loading a trace restrict patch savegame version %d as version 194", _sl_version);
|
||||
_sl_version = 194;
|
||||
_sl_is_faked_ext = true;
|
||||
_sl_xv_feature_versions[XSLFI_TRACE_RESTRICT] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
enum SlXvFeatureIndex {
|
||||
XSLFI_NULL = 0, ///< Unused value, to indicate that no extended feature test is in use
|
||||
XSLFI_TRACE_RESTRICT, ///< Trace restrict
|
||||
|
||||
XSLFI_SIZE, ///< Total count of features, including null feature
|
||||
};
|
||||
|
@@ -454,6 +454,7 @@ extern const ChunkHandler _linkgraph_chunk_handlers[];
|
||||
extern const ChunkHandler _airport_chunk_handlers[];
|
||||
extern const ChunkHandler _object_chunk_handlers[];
|
||||
extern const ChunkHandler _persistent_storage_chunk_handlers[];
|
||||
extern const ChunkHandler _trace_restrict_chunk_handlers[];
|
||||
|
||||
/** Array of all chunks in a savegame, \c NULL terminated. */
|
||||
static const ChunkHandler * const _chunk_handlers[] = {
|
||||
@@ -491,6 +492,7 @@ static const ChunkHandler * const _chunk_handlers[] = {
|
||||
_airport_chunk_handlers,
|
||||
_object_chunk_handlers,
|
||||
_persistent_storage_chunk_handlers,
|
||||
_trace_restrict_chunk_handlers,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@@ -34,6 +34,7 @@ void AfterLoadLabelMaps();
|
||||
void AfterLoadStoryBook();
|
||||
void AfterLoadLinkGraphs();
|
||||
void AfterLoadCompanyStats();
|
||||
void AfterLoadTraceRestrict();
|
||||
void UpdateHousesAndTowns();
|
||||
|
||||
void UpdateOldAircraft();
|
||||
|
111
src/saveload/tracerestrict_sl.cpp
Normal file
111
src/saveload/tracerestrict_sl.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file tracerestrict_sl.cpp Code handling saving and loading of trace restrict programs */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../tracerestrict.h"
|
||||
#include "saveload.h"
|
||||
#include <vector>
|
||||
#include "saveload.h"
|
||||
|
||||
static const SaveLoad _trace_restrict_mapping_desc[] = {
|
||||
SLE_VAR(TraceRestrictMappingItem, program_id, SLE_UINT32),
|
||||
SLE_END()
|
||||
};
|
||||
|
||||
/**
|
||||
* Load mappings
|
||||
*/
|
||||
static void Load_TRRM()
|
||||
{
|
||||
int index;
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
TraceRestrictMappingItem &item = _tracerestrictprogram_mapping[index];
|
||||
SlObject(&item, _trace_restrict_mapping_desc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save mappings
|
||||
*/
|
||||
static void Save_TRRM()
|
||||
{
|
||||
for (TraceRestrictMapping::iterator iter = _tracerestrictprogram_mapping.begin();
|
||||
iter != _tracerestrictprogram_mapping.end(); ++iter) {
|
||||
SlSetArrayIndex(iter->first);
|
||||
SlObject(&(iter->second), _trace_restrict_mapping_desc);
|
||||
}
|
||||
}
|
||||
|
||||
/** program length save header struct */
|
||||
struct TraceRestrictProgramStub {
|
||||
uint32 length;
|
||||
};
|
||||
|
||||
static const SaveLoad _trace_restrict_program_stub_desc[] = {
|
||||
SLE_VAR(TraceRestrictProgramStub, length, SLE_UINT32),
|
||||
SLE_END()
|
||||
};
|
||||
|
||||
/**
|
||||
* Load program pool
|
||||
*/
|
||||
static void Load_TRRP()
|
||||
{
|
||||
int index;
|
||||
TraceRestrictProgramStub stub;
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
TraceRestrictProgram *prog = new (index) TraceRestrictProgram();
|
||||
SlObject(&stub, _trace_restrict_program_stub_desc);
|
||||
prog->items.resize(stub.length);
|
||||
SlArray(&(prog->items[0]), stub.length, SLE_UINT32);
|
||||
assert(prog->Validate().Succeeded());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a program, used by SlAutolength
|
||||
*/
|
||||
static void RealSave_TRRP(TraceRestrictProgram *prog)
|
||||
{
|
||||
TraceRestrictProgramStub stub;
|
||||
stub.length = prog->items.size();
|
||||
SlObject(&stub, _trace_restrict_program_stub_desc);
|
||||
SlArray(&(prog->items[0]), stub.length, SLE_UINT32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save program pool
|
||||
*/
|
||||
static void Save_TRRP()
|
||||
{
|
||||
TraceRestrictProgram *prog;
|
||||
|
||||
FOR_ALL_TRACE_RESTRICT_PROGRAMS(prog) {
|
||||
SlSetArrayIndex(prog->index);
|
||||
SlAutolength((AutolengthProc*) RealSave_TRRP, prog);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update program reference counts from just-loaded mapping
|
||||
*/
|
||||
void AfterLoadTraceRestrict()
|
||||
{
|
||||
for (TraceRestrictMapping::iterator iter = _tracerestrictprogram_mapping.begin();
|
||||
iter != _tracerestrictprogram_mapping.end(); ++iter) {
|
||||
_tracerestrictprogram_pool.Get(iter->second.program_id)->IncrementRefCount();
|
||||
}
|
||||
}
|
||||
|
||||
extern const ChunkHandler _trace_restrict_chunk_handlers[] = {
|
||||
{ 'TRRM', Save_TRRM, Load_TRRM, NULL, NULL, CH_SPARSE_ARRAY}, // Trace Restrict Mapping chunk
|
||||
{ 'TRRP', Save_TRRP, Load_TRRP, NULL, NULL, CH_ARRAY | CH_LAST}, // Trace Restrict Mapping Program Pool chunk
|
||||
};
|
@@ -2054,6 +2054,7 @@ public:
|
||||
WID_BS_ELECTRIC_PBS = ::WID_BS_ELECTRIC_PBS, ///< Build an electric path signal.
|
||||
WID_BS_ELECTRIC_PBS_OWAY = ::WID_BS_ELECTRIC_PBS_OWAY, ///< Build an electric one way path signal.
|
||||
WID_BS_CONVERT = ::WID_BS_CONVERT, ///< Convert the signal.
|
||||
WID_BS_TRACE_RESTRICT = ::WID_BS_TRACE_RESTRICT, ///< Open trace restrict window.
|
||||
WID_BS_DRAG_SIGNALS_DENSITY_LABEL = ::WID_BS_DRAG_SIGNALS_DENSITY_LABEL, ///< The current signal density.
|
||||
WID_BS_DRAG_SIGNALS_DENSITY_DECREASE = ::WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, ///< Decrease the signal density.
|
||||
WID_BS_DRAG_SIGNALS_DENSITY_INCREASE = ::WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, ///< Increase the signal density.
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include "core/random_func.hpp"
|
||||
#include "linkgraph/linkgraph.h"
|
||||
#include "linkgraph/linkgraphschedule.h"
|
||||
#include "tracerestrict.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
@@ -137,6 +138,8 @@ Station::~Station()
|
||||
/* Now delete all orders that go to the station */
|
||||
RemoveOrderFromAllVehicles(OT_GOTO_STATION, this->index);
|
||||
|
||||
TraceRestrictRemoveDestinationID(TROCAF_STATION, this->index);
|
||||
|
||||
/* Remove all news items */
|
||||
DeleteStationNews(this->index);
|
||||
|
||||
|
11
src/stdafx.h
11
src/stdafx.h
@@ -514,4 +514,15 @@ static inline void free(const void *ptr)
|
||||
#define IGNORE_UNINITIALIZED_WARNING_STOP
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Conditional define for the override keyword.
|
||||
* Use of the override keyword can prevent various types of problems when the base method signature is changed, but derived overriding methods are not
|
||||
* This is conditional to maintain compatibility with legacy compilers
|
||||
*/
|
||||
#if __cplusplus >= 201103L || defined(__STDCXX_VERSION__) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__)
|
||||
#define OVERRIDE override
|
||||
#else
|
||||
#define OVERRIDE
|
||||
#endif
|
||||
|
||||
#endif /* STDAFX_H */
|
||||
|
894
src/tracerestrict.cpp
Normal file
894
src/tracerestrict.cpp
Normal file
@@ -0,0 +1,894 @@
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file tracerestrict.cpp Main file for Trace Restrict */
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "tracerestrict.h"
|
||||
#include "train.h"
|
||||
#include "core/bitmath_func.hpp"
|
||||
#include "core/pool_func.hpp"
|
||||
#include "command_func.h"
|
||||
#include "company_func.h"
|
||||
#include "viewport_func.h"
|
||||
#include "window_func.h"
|
||||
#include "order_base.h"
|
||||
#include "cargotype.h"
|
||||
#include "pathfinder/yapf/yapf_cache.h"
|
||||
#include <vector>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Trace Restrict Data Storage Model Notes:
|
||||
*
|
||||
* Signals may have 0, 1 or 2 trace restrict programs attached to them,
|
||||
* up to one for each track. Two-way signals share the same program.
|
||||
*
|
||||
* The mapping between signals and programs is defined in terms of
|
||||
* TraceRestrictRefId to TraceRestrictProgramID,
|
||||
* where TraceRestrictRefId is formed of the tile index and track,
|
||||
* and TraceRestrictProgramID is an index into the program pool.
|
||||
*
|
||||
* If one or more mappings exist for a given signal tile, bit 12 of M3 will be set to 1.
|
||||
* This is updated whenever mappings are added/removed for that tile. This is to avoid
|
||||
* needing to do a mapping lookup for the common case where there is no trace restrict
|
||||
* program mapping for the given tile.
|
||||
*
|
||||
* Programs in the program pool are refcounted based on the number of mappings which exist.
|
||||
* When this falls to 0, the program is deleted from the pool.
|
||||
* If a program has a refcount greater than 1, it is a shared program.
|
||||
*
|
||||
* In all cases, an empty program is evaluated the same as the absence of a program.
|
||||
* Therefore it is not necessary to store mappings to empty unshared programs.
|
||||
* Any editing action which would otherwise result in a mapping to an empty program
|
||||
* which has no other references, instead removes the mapping.
|
||||
* This is not done for shared programs as this would delete the shared aspect whenever
|
||||
* the program became empty.
|
||||
*
|
||||
* Empty programs with a refcount of 1 may still exist due to the edge case where:
|
||||
* 1: There is an empty program with refcount 2
|
||||
* 2: One of the two mappings is deleted
|
||||
* Finding the other mapping would entail a linear search of the mappings, and there is little
|
||||
* to be gained by doing so.
|
||||
*/
|
||||
|
||||
TraceRestrictProgramPool _tracerestrictprogram_pool("TraceRestrictProgram");
|
||||
INSTANTIATE_POOL_METHODS(TraceRestrictProgram)
|
||||
|
||||
/**
|
||||
* TraceRestrictRefId --> TraceRestrictProgramID (Pool ID) mapping
|
||||
* The indirection is mainly to enable shared programs
|
||||
* TODO: use a more efficient container/indirection mechanism
|
||||
*/
|
||||
TraceRestrictMapping _tracerestrictprogram_mapping;
|
||||
|
||||
/**
|
||||
* This should be used when all pools have been or are immediately about to be also cleared
|
||||
* Calling this at other times will leave dangling refcounts
|
||||
*/
|
||||
void ClearTraceRestrictMapping() {
|
||||
_tracerestrictprogram_mapping.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags used for the program execution condition stack
|
||||
* Each 'if' pushes onto the stack
|
||||
* Each 'end if' pops from the stack
|
||||
* Elif/orif/else may modify the stack top
|
||||
*/
|
||||
enum TraceRestrictCondStackFlags {
|
||||
TRCSF_DONE_IF = 1<<0, ///< The if/elif/else is "done", future elif/else branches will not be executed
|
||||
TRCSF_SEEN_ELSE = 1<<1, ///< An else branch has been seen already, error if another is seen afterwards
|
||||
TRCSF_ACTIVE = 1<<2, ///< The condition is currently active
|
||||
TRCSF_PARENT_INACTIVE = 1<<3, ///< The parent condition is not active, thus this condition is also not active
|
||||
};
|
||||
DECLARE_ENUM_AS_BIT_SET(TraceRestrictCondStackFlags)
|
||||
|
||||
/**
|
||||
* Helper function to handle condition stack manipulatoin
|
||||
*/
|
||||
static void HandleCondition(std::vector<TraceRestrictCondStackFlags> &condstack, TraceRestrictCondFlags condflags, bool value)
|
||||
{
|
||||
if (condflags & TRCF_OR) {
|
||||
assert(!condstack.empty());
|
||||
if (condstack.back() & TRCSF_ACTIVE) {
|
||||
// leave TRCSF_ACTIVE set
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (condflags & (TRCF_OR | TRCF_ELSE)) {
|
||||
assert(!condstack.empty());
|
||||
if (condstack.back() & (TRCSF_DONE_IF | TRCSF_PARENT_INACTIVE)) {
|
||||
condstack.back() &= ~TRCSF_ACTIVE;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!condstack.empty() && !(condstack.back() & TRCSF_ACTIVE)) {
|
||||
//this is a 'nested if', the 'parent if' is not active
|
||||
condstack.push_back(TRCSF_PARENT_INACTIVE);
|
||||
return;
|
||||
}
|
||||
condstack.push_back(static_cast<TraceRestrictCondStackFlags>(0));
|
||||
}
|
||||
|
||||
if (value) {
|
||||
condstack.back() |= TRCSF_DONE_IF | TRCSF_ACTIVE;
|
||||
} else {
|
||||
condstack.back() &= ~TRCSF_ACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Integer condition testing
|
||||
* Test value op condvalue
|
||||
*/
|
||||
static bool TestCondition(uint16 value, TraceRestrictCondOp condop, uint16 condvalue)
|
||||
{
|
||||
switch (condop) {
|
||||
case TRCO_IS:
|
||||
return value == condvalue;
|
||||
case TRCO_ISNOT:
|
||||
return value != condvalue;
|
||||
case TRCO_LT:
|
||||
return value < condvalue;
|
||||
case TRCO_LTE:
|
||||
return value <= condvalue;
|
||||
case TRCO_GT:
|
||||
return value > condvalue;
|
||||
case TRCO_GTE:
|
||||
return value >= condvalue;
|
||||
default:
|
||||
NOT_REACHED();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Binary condition testing helper function
|
||||
*/
|
||||
static bool TestBinaryConditionCommon(TraceRestrictItem item, bool input)
|
||||
{
|
||||
switch (GetTraceRestrictCondOp(item)) {
|
||||
case TRCO_IS:
|
||||
return input;
|
||||
|
||||
case TRCO_ISNOT:
|
||||
return !input;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test order condition
|
||||
* @p order may be NULL
|
||||
*/
|
||||
static bool TestOrderCondition(const Order *order, TraceRestrictItem item)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (order) {
|
||||
DestinationID condvalue = GetTraceRestrictValue(item);
|
||||
switch (static_cast<TraceRestrictOrderCondAuxField>(GetTraceRestrictAuxField(item))) {
|
||||
case TROCAF_STATION:
|
||||
result = order->IsType(OT_GOTO_STATION) && order->GetDestination() == condvalue;
|
||||
break;
|
||||
|
||||
case TROCAF_WAYPOINT:
|
||||
result = order->IsType(OT_GOTO_WAYPOINT) && order->GetDestination() == condvalue;
|
||||
break;
|
||||
|
||||
case OT_GOTO_DEPOT:
|
||||
result = order->IsType(OT_GOTO_DEPOT) && order->GetDestination() == condvalue;
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
return TestBinaryConditionCommon(item, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test station condition
|
||||
*/
|
||||
static bool TestStationCondition(StationID station, TraceRestrictItem item)
|
||||
{
|
||||
bool result = (GetTraceRestrictAuxField(item) == TROCAF_STATION) && (station == GetTraceRestrictValue(item));
|
||||
return TestBinaryConditionCommon(item, result);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute program on train and store results in out
|
||||
* @p v may not be NULL
|
||||
* @p out should be zero-initialised
|
||||
*/
|
||||
void TraceRestrictProgram::Execute(const Train* v, const TraceRestrictProgramInput &input, TraceRestrictProgramResult& out) const
|
||||
{
|
||||
// static to avoid needing to re-alloc/resize on each execution
|
||||
static std::vector<TraceRestrictCondStackFlags> condstack;
|
||||
condstack.clear();
|
||||
|
||||
size_t size = this->items.size();
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
TraceRestrictItem item = this->items[i];
|
||||
TraceRestrictItemType type = GetTraceRestrictType(item);
|
||||
|
||||
if (IsTraceRestrictConditional(item)) {
|
||||
TraceRestrictCondFlags condflags = GetTraceRestrictCondFlags(item);
|
||||
TraceRestrictCondOp condop = GetTraceRestrictCondOp(item);
|
||||
|
||||
if (type == TRIT_COND_ENDIF) {
|
||||
assert(!condstack.empty());
|
||||
if (condflags & TRCF_ELSE) {
|
||||
// else
|
||||
assert(!(condstack.back() & TRCSF_SEEN_ELSE));
|
||||
HandleCondition(condstack, condflags, true);
|
||||
condstack.back() |= TRCSF_SEEN_ELSE;
|
||||
} else {
|
||||
// end if
|
||||
condstack.pop_back();
|
||||
}
|
||||
} else {
|
||||
uint16 condvalue = GetTraceRestrictValue(item);
|
||||
bool result = false;
|
||||
switch(type) {
|
||||
case TRIT_COND_UNDEFINED:
|
||||
result = false;
|
||||
break;
|
||||
|
||||
case TRIT_COND_TRAIN_LENGTH:
|
||||
result = TestCondition(CeilDiv(v->gcache.cached_total_length, TILE_SIZE), condop, condvalue);
|
||||
break;
|
||||
|
||||
case TRIT_COND_MAX_SPEED:
|
||||
result = TestCondition(v->GetDisplayMaxSpeed(), condop, condvalue);
|
||||
break;
|
||||
|
||||
case TRIT_COND_CURRENT_ORDER:
|
||||
result = TestOrderCondition(&(v->current_order), item);
|
||||
break;
|
||||
|
||||
case TRIT_COND_NEXT_ORDER: {
|
||||
if (v->orders.list == NULL) break;
|
||||
if (v->orders.list->GetNumOrders() == 0) break;
|
||||
|
||||
const Order *current_order = v->GetOrder(v->cur_real_order_index);
|
||||
for (const Order *order = v->orders.list->GetNext(current_order); order != current_order; order = v->orders.list->GetNext(order)) {
|
||||
if (order->IsGotoOrder()) {
|
||||
result = TestOrderCondition(order, item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TRIT_COND_LAST_STATION:
|
||||
result = TestStationCondition(v->last_station_visited, item);
|
||||
break;
|
||||
|
||||
case TRIT_COND_CARGO: {
|
||||
bool have_cargo = false;
|
||||
for (const Vehicle *v_iter = v; v_iter != NULL; v_iter = v_iter->Next()) {
|
||||
if (v_iter->cargo_type == GetTraceRestrictValue(item) && v_iter->cargo_cap > 0) {
|
||||
have_cargo = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = TestBinaryConditionCommon(item, have_cargo);
|
||||
break;
|
||||
}
|
||||
|
||||
case TRIT_COND_ENTRY_DIRECTION: {
|
||||
bool direction_match;
|
||||
switch (GetTraceRestrictValue(item)) {
|
||||
case TRNTSV_NE:
|
||||
case TRNTSV_SE:
|
||||
case TRNTSV_SW:
|
||||
case TRNTSV_NW:
|
||||
direction_match = (static_cast<DiagDirection>(GetTraceRestrictValue(item)) == TrackdirToExitdir(ReverseTrackdir(input.trackdir)));
|
||||
break;
|
||||
|
||||
case TRDTSV_FRONT:
|
||||
direction_match = IsTileType(input.tile, MP_RAILWAY) && HasSignalOnTrackdir(input.tile, input.trackdir);
|
||||
break;
|
||||
|
||||
case TRDTSV_BACK:
|
||||
direction_match = IsTileType(input.tile, MP_RAILWAY) && !HasSignalOnTrackdir(input.tile, input.trackdir);
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
}
|
||||
result = TestBinaryConditionCommon(item, direction_match);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
HandleCondition(condstack, condflags, result);
|
||||
}
|
||||
} else {
|
||||
if (condstack.empty() || condstack.back() & TRCSF_ACTIVE) {
|
||||
switch(type) {
|
||||
case TRIT_PF_DENY:
|
||||
if (GetTraceRestrictValue(item)) {
|
||||
out.flags &= ~TRPRF_DENY;
|
||||
} else {
|
||||
out.flags |= TRPRF_DENY;
|
||||
}
|
||||
break;
|
||||
case TRIT_PF_PENALTY:
|
||||
out.penalty += GetTraceRestrictValue(item);
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(condstack.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrement ref count, only use when removing a mapping
|
||||
*/
|
||||
void TraceRestrictProgram::DecrementRefCount() {
|
||||
assert(this->refcount > 0);
|
||||
this->refcount--;
|
||||
if (this->refcount == 0) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a instruction list
|
||||
* Returns successful result if program seems OK
|
||||
* This only validates that conditional nesting is correct, at present
|
||||
*/
|
||||
CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem> &items) {
|
||||
// static to avoid needing to re-alloc/resize on each execution
|
||||
static std::vector<TraceRestrictCondStackFlags> condstack;
|
||||
condstack.clear();
|
||||
|
||||
size_t size = items.size();
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
TraceRestrictItem item = items[i];
|
||||
TraceRestrictItemType type = GetTraceRestrictType(item);
|
||||
|
||||
if (IsTraceRestrictConditional(item)) {
|
||||
TraceRestrictCondFlags condflags = GetTraceRestrictCondFlags(item);
|
||||
|
||||
if (type == TRIT_COND_ENDIF) {
|
||||
if (condstack.empty()) {
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_NO_IF); // else/endif with no starting if
|
||||
}
|
||||
if (condflags & TRCF_ELSE) {
|
||||
// else
|
||||
if (condstack.back() & TRCSF_SEEN_ELSE) {
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_DUP_ELSE); // Two else clauses
|
||||
}
|
||||
HandleCondition(condstack, condflags, true);
|
||||
condstack.back() |= TRCSF_SEEN_ELSE;
|
||||
} else {
|
||||
// end if
|
||||
condstack.pop_back();
|
||||
}
|
||||
} else {
|
||||
if (condflags & (TRCF_OR | TRCF_ELSE)) { // elif/orif
|
||||
if (condstack.empty()) {
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_ELIF_NO_IF); // Pre-empt assertions in HandleCondition
|
||||
}
|
||||
if (condstack.back() & TRCSF_SEEN_ELSE) {
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_DUP_ELSE); // else clause followed by elif/orif
|
||||
}
|
||||
}
|
||||
HandleCondition(condstack, condflags, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!condstack.empty()) {
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_END_CONDSTACK);
|
||||
}
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value and aux field of @p item, as per the value type in @p value_type
|
||||
*/
|
||||
void SetTraceRestrictValueDefault(TraceRestrictItem &item, TraceRestrictValueType value_type)
|
||||
{
|
||||
switch (value_type) {
|
||||
case TRVT_NONE:
|
||||
case TRVT_INT:
|
||||
case TRVT_DENY:
|
||||
case TRVT_SPEED:
|
||||
SetTraceRestrictValue(item, 0);
|
||||
SetTraceRestrictAuxField(item, 0);
|
||||
break;
|
||||
|
||||
case TRVT_ORDER:
|
||||
SetTraceRestrictValue(item, INVALID_STATION);
|
||||
SetTraceRestrictAuxField(item, TROCAF_STATION);
|
||||
break;
|
||||
|
||||
case TRVT_CARGO_ID:
|
||||
assert(_sorted_standard_cargo_specs_size > 0);
|
||||
SetTraceRestrictValue(item, _sorted_cargo_specs[0]->Index());
|
||||
SetTraceRestrictAuxField(item, 0);
|
||||
break;
|
||||
|
||||
case TRVT_DIRECTION:
|
||||
SetTraceRestrictValue(item, TRDTSV_FRONT);
|
||||
SetTraceRestrictAuxField(item, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type field of a TraceRestrictItem, and resets any other fields which are no longer valid/meaningful to sensible defaults
|
||||
*/
|
||||
void SetTraceRestrictTypeAndNormalise(TraceRestrictItem &item, TraceRestrictItemType type)
|
||||
{
|
||||
if (item != 0) {
|
||||
assert(GetTraceRestrictType(item) != TRIT_NULL);
|
||||
assert(IsTraceRestrictConditional(item) == IsTraceRestrictTypeConditional(type));
|
||||
}
|
||||
assert(type != TRIT_NULL);
|
||||
|
||||
TraceRestrictTypePropertySet old_properties = GetTraceRestrictTypeProperties(item);
|
||||
SetTraceRestrictType(item, type);
|
||||
TraceRestrictTypePropertySet new_properties = GetTraceRestrictTypeProperties(item);
|
||||
|
||||
if (old_properties.cond_type != new_properties.cond_type ||
|
||||
old_properties.value_type != new_properties.value_type) {
|
||||
SetTraceRestrictCondOp(item, TRCO_IS);
|
||||
SetTraceRestrictValueDefault(item, new_properties.value_type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "signal has a trace restrict mapping" bit
|
||||
* This looks for mappings with that tile index
|
||||
*/
|
||||
void SetIsSignalRestrictedBit(TileIndex t)
|
||||
{
|
||||
// First mapping for this tile, or later
|
||||
TraceRestrictMapping::iterator lower_bound = _tracerestrictprogram_mapping.lower_bound(MakeTraceRestrictRefId(t, static_cast<Track>(0)));
|
||||
|
||||
// First mapping for next tile, or later
|
||||
TraceRestrictMapping::iterator upper_bound = _tracerestrictprogram_mapping.lower_bound(MakeTraceRestrictRefId(t + 1, static_cast<Track>(0)));
|
||||
|
||||
// If iterators are the same, there are no mappings for this tile
|
||||
SetRestrictedSignal(t, lower_bound != upper_bound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new program mapping to an existing program
|
||||
* If a mapping already exists, it is removed
|
||||
*/
|
||||
void TraceRestrictCreateProgramMapping(TraceRestrictRefId ref, TraceRestrictProgram *prog)
|
||||
{
|
||||
std::pair<TraceRestrictMapping::iterator, bool> insert_result =
|
||||
_tracerestrictprogram_mapping.insert(std::make_pair(ref, TraceRestrictMappingItem(prog->index)));
|
||||
|
||||
if (!insert_result.second) {
|
||||
// value was not inserted, there is an existing mapping
|
||||
// unref the existing mapping before updating it
|
||||
_tracerestrictprogram_pool.Get(insert_result.first->second.program_id)->DecrementRefCount();
|
||||
insert_result.first->second = prog->index;
|
||||
}
|
||||
prog->IncrementRefCount();
|
||||
|
||||
TileIndex tile = GetTraceRestrictRefIdTileIndex(ref);
|
||||
Track track = GetTraceRestrictRefIdTrack(ref);
|
||||
SetIsSignalRestrictedBit(tile);
|
||||
MarkTileDirtyByTile(tile);
|
||||
YapfNotifyTrackLayoutChange(tile, track);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a program mapping
|
||||
*/
|
||||
void TraceRestrictRemoveProgramMapping(TraceRestrictRefId ref)
|
||||
{
|
||||
TraceRestrictMapping::iterator iter = _tracerestrictprogram_mapping.find(ref);
|
||||
if (iter != _tracerestrictprogram_mapping.end()) {
|
||||
// Found
|
||||
_tracerestrictprogram_pool.Get(iter->second.program_id)->DecrementRefCount();
|
||||
_tracerestrictprogram_mapping.erase(iter);
|
||||
|
||||
TileIndex tile = GetTraceRestrictRefIdTileIndex(ref);
|
||||
Track track = GetTraceRestrictRefIdTrack(ref);
|
||||
SetIsSignalRestrictedBit(tile);
|
||||
MarkTileDirtyByTile(tile);
|
||||
YapfNotifyTrackLayoutChange(tile, track);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the signal program for the tile ref @p ref
|
||||
* An empty program will be constructed if none exists, and @p create_new is true, unless the pool is full
|
||||
*/
|
||||
TraceRestrictProgram *GetTraceRestrictProgram(TraceRestrictRefId ref, bool create_new)
|
||||
{
|
||||
// Optimise for lookup, creating doesn't have to be that fast
|
||||
|
||||
TraceRestrictMapping::iterator iter = _tracerestrictprogram_mapping.find(ref);
|
||||
if (iter != _tracerestrictprogram_mapping.end()) {
|
||||
// Found
|
||||
return _tracerestrictprogram_pool.Get(iter->second.program_id);
|
||||
} else if (create_new) {
|
||||
// Not found
|
||||
|
||||
// Create new pool item
|
||||
if (!TraceRestrictProgram::CanAllocateItem()) {
|
||||
return NULL;
|
||||
}
|
||||
TraceRestrictProgram *prog = new TraceRestrictProgram();
|
||||
|
||||
// Create new mapping to pool item
|
||||
TraceRestrictCreateProgramMapping(ref, prog);
|
||||
return prog;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify that a signal is being removed
|
||||
* Remove any trace restrict mappings associated with it
|
||||
*/
|
||||
void TraceRestrictNotifySignalRemoval(TileIndex tile, Track track)
|
||||
{
|
||||
TraceRestrictRefId ref = MakeTraceRestrictRefId(tile, track);
|
||||
TraceRestrictRemoveProgramMapping(ref);
|
||||
DeleteWindowById(WC_TRACE_RESTRICT, ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to perform parameter bit-packing and call DoCommandP, for instruction modification actions
|
||||
*/
|
||||
void TraceRestrictDoCommandP(TileIndex tile, Track track, TraceRestrictDoCommandType type, uint32 offset, uint32 value, StringID error_msg)
|
||||
{
|
||||
uint32 p1 = 0;
|
||||
SB(p1, 0, 3, track);
|
||||
SB(p1, 3, 5, type);
|
||||
assert(offset < (1 << 16));
|
||||
SB(p1, 8, 16, offset);
|
||||
DoCommandP(tile, p1, value, CMD_PROGRAM_TRACERESTRICT_SIGNAL | CMD_MSG(error_msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a tile/tracl pair contains a usable signal
|
||||
*/
|
||||
static CommandCost TraceRestrictCheckTileIsUsable(TileIndex tile, Track track)
|
||||
{
|
||||
// Check that there actually is a signal here
|
||||
if (!IsPlainRailTile(tile) || !HasTrack(tile, track)) {
|
||||
return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
|
||||
}
|
||||
if (!HasSignalOnTrack(tile, track)) {
|
||||
return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
|
||||
}
|
||||
|
||||
// Check tile ownership, do this afterwards to avoid tripping up on house/industry tiles
|
||||
CommandCost ret = CheckTileOwnership(tile);
|
||||
if (ret.Failed()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
/**
|
||||
* The main command for editing a signal tracerestrict program.
|
||||
* @param tile The tile which contains the signal.
|
||||
* @param flags Internal command handler stuff.
|
||||
* Below apply for instruction modification actions only
|
||||
* @param p1 Bitstuffed items
|
||||
* @param p2 Item, for insert and modify operations
|
||||
* @return the cost of this operation (which is free), or an error
|
||||
*/
|
||||
CommandCost CmdProgramSignalTraceRestrict(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
||||
{
|
||||
TraceRestrictDoCommandType type = static_cast<TraceRestrictDoCommandType>(GB(p1, 3, 5));
|
||||
|
||||
if (type >= TRDCT_PROG_COPY) {
|
||||
return CmdProgramSignalTraceRestrictProgMgmt(tile, flags, p1, p2, text);
|
||||
}
|
||||
|
||||
Track track = static_cast<Track>(GB(p1, 0, 3));
|
||||
uint32 offset = GB(p1, 8, 16);
|
||||
TraceRestrictItem item = static_cast<TraceRestrictItem>(p2);
|
||||
|
||||
CommandCost ret = TraceRestrictCheckTileIsUsable(tile, track);
|
||||
if (ret.Failed()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool can_make_new = (type == TRDCT_INSERT_ITEM) && (flags & DC_EXEC);
|
||||
bool need_existing = (type != TRDCT_INSERT_ITEM);
|
||||
TraceRestrictProgram *prog = GetTraceRestrictProgram(MakeTraceRestrictRefId(tile, track), can_make_new);
|
||||
if (need_existing && !prog) {
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_NO_PROGRAM);
|
||||
}
|
||||
|
||||
uint32 offset_limit_exclusive = ((type == TRDCT_INSERT_ITEM) ? 1 : 0);
|
||||
if (prog) offset_limit_exclusive += prog->items.size();
|
||||
|
||||
if (offset >= offset_limit_exclusive) {
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_OFFSET_TOO_LARGE);
|
||||
}
|
||||
|
||||
// copy program
|
||||
std::vector<TraceRestrictItem> items;
|
||||
if (prog) items = prog->items;
|
||||
|
||||
switch (type) {
|
||||
case TRDCT_INSERT_ITEM:
|
||||
items.insert(items.begin() + offset, item);
|
||||
if (IsTraceRestrictConditional(item) &&
|
||||
GetTraceRestrictCondFlags(item) == 0 &&
|
||||
GetTraceRestrictType(item) != TRIT_COND_ENDIF) {
|
||||
// this is an opening if block, insert a corresponding end if
|
||||
TraceRestrictItem endif_item = 0;
|
||||
SetTraceRestrictType(endif_item, TRIT_COND_ENDIF);
|
||||
items.insert(items.begin() + offset + 1, endif_item);
|
||||
}
|
||||
break;
|
||||
|
||||
case TRDCT_MODIFY_ITEM: {
|
||||
TraceRestrictItem old_item = items[offset];
|
||||
if (IsTraceRestrictConditional(old_item) != IsTraceRestrictConditional(item)) {
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_CAN_T_CHANGE_CONDITIONALITY);
|
||||
}
|
||||
items[offset] = item;
|
||||
break;
|
||||
}
|
||||
|
||||
case TRDCT_REMOVE_ITEM: {
|
||||
TraceRestrictItem old_item = items[offset];
|
||||
if (IsTraceRestrictConditional(old_item)) {
|
||||
bool remove_whole_block = false;
|
||||
if (GetTraceRestrictCondFlags(old_item) == 0) {
|
||||
if (GetTraceRestrictType(old_item) == TRIT_COND_ENDIF) {
|
||||
// this is an end if, can't remove these
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_CAN_T_REMOVE_ENDIF);
|
||||
} else {
|
||||
// this is an opening if
|
||||
remove_whole_block = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 recursion_depth = 1;
|
||||
std::vector<TraceRestrictItem>::iterator remove_start = items.begin() + offset;
|
||||
std::vector<TraceRestrictItem>::iterator remove_end = remove_start + 1;
|
||||
|
||||
// iterate until matching end block found
|
||||
for (; remove_end != items.end(); ++remove_end) {
|
||||
TraceRestrictItem current_item = *remove_end;
|
||||
if (IsTraceRestrictConditional(current_item)) {
|
||||
if (GetTraceRestrictCondFlags(current_item) == 0) {
|
||||
if (GetTraceRestrictType(current_item) == TRIT_COND_ENDIF) {
|
||||
// this is an end if
|
||||
recursion_depth--;
|
||||
if (recursion_depth == 0) {
|
||||
if (remove_whole_block) {
|
||||
// inclusively remove up to here
|
||||
++remove_end;
|
||||
break;
|
||||
} else {
|
||||
// exclusively remove up to here
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// this is an opening if
|
||||
recursion_depth++;
|
||||
}
|
||||
} else {
|
||||
// this is an else/or type block
|
||||
if (recursion_depth == 1 && !remove_whole_block) {
|
||||
// exclusively remove up to here
|
||||
recursion_depth = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (recursion_depth != 0) return CMD_ERROR; // ran off the end
|
||||
items.erase(remove_start, remove_end);
|
||||
} else {
|
||||
items.erase(items.begin() + offset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
}
|
||||
|
||||
CommandCost validation_result = TraceRestrictProgram::Validate(items);
|
||||
if (validation_result.Failed()) {
|
||||
return validation_result;
|
||||
}
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
assert(prog);
|
||||
|
||||
// move in modified program
|
||||
prog->items.swap(items);
|
||||
|
||||
if (prog->items.size() == 0 && prog->refcount == 1) {
|
||||
// program is empty, and this tile is the only reference to it
|
||||
// so delete it, as it's redundant
|
||||
TraceRestrictRemoveProgramMapping(MakeTraceRestrictRefId(tile, track));
|
||||
}
|
||||
|
||||
// update windows
|
||||
InvalidateWindowClassesData(WC_TRACE_RESTRICT);
|
||||
}
|
||||
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to perform parameter bit-packing and call DoCommandP, for program management actions
|
||||
*/
|
||||
void TraceRestrictProgMgmtWithSourceDoCommandP(TileIndex tile, Track track, TraceRestrictDoCommandType type,
|
||||
TileIndex source_tile, Track source_track, StringID error_msg)
|
||||
{
|
||||
uint32 p1 = 0;
|
||||
SB(p1, 0, 3, track);
|
||||
SB(p1, 3, 5, type);
|
||||
SB(p1, 8, 3, source_track);
|
||||
DoCommandP(tile, p1, source_tile, CMD_PROGRAM_TRACERESTRICT_SIGNAL | CMD_MSG(error_msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub command for copy/share/unshare operations on signal tracerestrict programs.
|
||||
* @param tile The tile which contains the signal.
|
||||
* @param flags Internal command handler stuff.
|
||||
* @param p1 Bitstuffed items
|
||||
* @param p2 Source tile, for share/copy operations
|
||||
* @return the cost of this operation (which is free), or an error
|
||||
*/
|
||||
CommandCost CmdProgramSignalTraceRestrictProgMgmt(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
||||
{
|
||||
TraceRestrictDoCommandType type = static_cast<TraceRestrictDoCommandType>(GB(p1, 3, 5));
|
||||
Track track = static_cast<Track>(GB(p1, 0, 3));
|
||||
Track source_track = static_cast<Track>(GB(p1, 8, 3));
|
||||
TileIndex source_tile = static_cast<TileIndex>(p2);
|
||||
|
||||
TraceRestrictRefId self = MakeTraceRestrictRefId(tile, track);
|
||||
TraceRestrictRefId source = MakeTraceRestrictRefId(source_tile, source_track);
|
||||
|
||||
assert(type >= TRDCT_PROG_COPY);
|
||||
|
||||
CommandCost ret = TraceRestrictCheckTileIsUsable(tile, track);
|
||||
if (ret.Failed()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (type == TRDCT_PROG_SHARE || type == TRDCT_PROG_COPY) {
|
||||
if (self == source) {
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_SOURCE_SAME_AS_TARGET);
|
||||
}
|
||||
|
||||
ret = TraceRestrictCheckTileIsUsable(source_tile, source_track);
|
||||
if (ret.Failed()) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & DC_EXEC)) {
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case TRDCT_PROG_COPY: {
|
||||
TraceRestrictRemoveProgramMapping(self);
|
||||
TraceRestrictProgram *prog = GetTraceRestrictProgram(self, true);
|
||||
if (!prog) {
|
||||
// allocation failed
|
||||
return CMD_ERROR;
|
||||
}
|
||||
|
||||
TraceRestrictProgram *source_prog = GetTraceRestrictProgram(source, false);
|
||||
if (source_prog) {
|
||||
prog->items = source_prog->items; // copy
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TRDCT_PROG_SHARE: {
|
||||
TraceRestrictRemoveProgramMapping(self);
|
||||
TraceRestrictProgram *source_prog = GetTraceRestrictProgram(source, true);
|
||||
if (!source_prog) {
|
||||
// allocation failed
|
||||
return CMD_ERROR;
|
||||
}
|
||||
|
||||
TraceRestrictCreateProgramMapping(self, source_prog);
|
||||
break;
|
||||
}
|
||||
|
||||
case TRDCT_PROG_UNSHARE: {
|
||||
std::vector<TraceRestrictItem> items;
|
||||
TraceRestrictProgram *prog = GetTraceRestrictProgram(self, false);
|
||||
if (prog) {
|
||||
// copy program into temporary
|
||||
items = prog->items;
|
||||
}
|
||||
// remove old program
|
||||
TraceRestrictRemoveProgramMapping(self);
|
||||
|
||||
if (items.size()) {
|
||||
// if prog is non-empty, create new program and move temporary in
|
||||
TraceRestrictProgram *new_prog = GetTraceRestrictProgram(self, true);
|
||||
if (!new_prog) {
|
||||
// allocation failed
|
||||
return CMD_ERROR;
|
||||
}
|
||||
|
||||
new_prog->items.swap(items);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TRDCT_PROG_RESET: {
|
||||
TraceRestrictRemoveProgramMapping(self);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
}
|
||||
|
||||
// update windows
|
||||
InvalidateWindowClassesData(WC_TRACE_RESTRICT);
|
||||
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when a station, waypoint or depot is about to be deleted
|
||||
* Scan program pool and change any references to it to the invalid station ID, to avoid dangling references
|
||||
*/
|
||||
void TraceRestrictRemoveDestinationID(TraceRestrictOrderCondAuxField type, uint16 index)
|
||||
{
|
||||
TraceRestrictProgram *prog;
|
||||
|
||||
FOR_ALL_TRACE_RESTRICT_PROGRAMS(prog) {
|
||||
for (size_t i = 0; i < prog->items.size(); i++) {
|
||||
TraceRestrictItem &item = prog->items[i]; // note this is a reference,
|
||||
if (GetTraceRestrictType(item) == TRIT_COND_CURRENT_ORDER ||
|
||||
GetTraceRestrictType(item) == TRIT_COND_NEXT_ORDER ||
|
||||
GetTraceRestrictType(item) == TRIT_COND_LAST_STATION) {
|
||||
if (GetTraceRestrictAuxField(item) == type && GetTraceRestrictValue(item) == index) {
|
||||
SetTraceRestrictValueDefault(item, TRVT_ORDER); // this updates the instruction in-place
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update windows
|
||||
InvalidateWindowClassesData(WC_TRACE_RESTRICT);
|
||||
}
|
465
src/tracerestrict.h
Normal file
465
src/tracerestrict.h
Normal file
@@ -0,0 +1,465 @@
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file tracerestrict.h Header file for Trace Restrict */
|
||||
|
||||
#ifndef TRACERESTRICT_H
|
||||
#define TRACERESTRICT_H
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "core/bitmath_func.hpp"
|
||||
#include "core/enum_type.hpp"
|
||||
#include "core/pool_type.hpp"
|
||||
#include "command_func.h"
|
||||
#include "rail_map.h"
|
||||
#include "tile_type.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
struct Train;
|
||||
|
||||
/** Program pool ID type. */
|
||||
typedef uint32 TraceRestrictProgramID;
|
||||
struct TraceRestrictProgram;
|
||||
|
||||
/** Tile/track mapping type. */
|
||||
typedef uint32 TraceRestrictRefId;
|
||||
|
||||
/** Type of the pool for trace restrict programs. */
|
||||
typedef Pool<TraceRestrictProgram, TraceRestrictProgramID, 16, 256000> TraceRestrictProgramPool;
|
||||
/** The actual pool for trace restrict nodes. */
|
||||
extern TraceRestrictProgramPool _tracerestrictprogram_pool;
|
||||
|
||||
#define FOR_ALL_TRACE_RESTRICT_PROGRAMS_FROM(var, start) FOR_ALL_ITEMS_FROM(TraceRestrictProgram, tr_index, var, start)
|
||||
#define FOR_ALL_TRACE_RESTRICT_PROGRAMS(var) FOR_ALL_TRACE_RESTRICT_PROGRAMS_FROM(var, 0)
|
||||
|
||||
/** Type used for the TraceRestrictRefId -> TraceRestrictProgramID mapping */
|
||||
struct TraceRestrictMappingItem {
|
||||
TraceRestrictProgramID program_id;
|
||||
|
||||
TraceRestrictMappingItem() { }
|
||||
|
||||
TraceRestrictMappingItem(TraceRestrictProgramID program_id_)
|
||||
: program_id(program_id_) { }
|
||||
};
|
||||
|
||||
typedef std::map<TraceRestrictRefId, TraceRestrictMappingItem> TraceRestrictMapping;
|
||||
|
||||
/** The actual mapping from TraceRestrictRefId to TraceRestrictProgramID. */
|
||||
extern TraceRestrictMapping _tracerestrictprogram_mapping;
|
||||
|
||||
void ClearTraceRestrictMapping();
|
||||
|
||||
/** Type of a single instruction, this is bit-packed as per TraceRestrictItemFlagAllocation */
|
||||
typedef uint32 TraceRestrictItem;
|
||||
|
||||
/**
|
||||
* Describes the allocation of bits to fields in TraceRestrictItem
|
||||
* Of the fields below, the type seem the most likely
|
||||
* to need future expansion, hence the reserved bits are placed
|
||||
* immediately after them
|
||||
*
|
||||
* COUNT values describe the field bit width
|
||||
* OFFSET values describe the field bit offset
|
||||
*/
|
||||
enum TraceRestrictItemFlagAllocation {
|
||||
TRIFA_TYPE_COUNT = 5,
|
||||
TRIFA_TYPE_OFFSET = 0,
|
||||
|
||||
/* 3 bits reserved for future use */
|
||||
|
||||
TRIFA_COND_FLAGS_COUNT = 3,
|
||||
TRIFA_COND_FLAGS_OFFSET = 8,
|
||||
|
||||
TRIFA_AUX_FIELD_COUNT = 2,
|
||||
TRIFA_AUX_FIELD_OFFSET = 11,
|
||||
|
||||
TRIFA_COND_OP_COUNT = 3,
|
||||
TRIFA_COND_OP_OFFSET = 13,
|
||||
|
||||
TRIFA_VALUE_COUNT = 16,
|
||||
TRIFA_VALUE_OFFSET = 16,
|
||||
};
|
||||
|
||||
/**
|
||||
* Enumeration of TraceRestrictItem type field
|
||||
* This is split into two halves:
|
||||
* * non-conditionals < TRIT_COND_BEGIN
|
||||
* * conditionals, >= TRIT_COND_BEGIN
|
||||
*/
|
||||
enum TraceRestrictItemType {
|
||||
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_PENALTY = 2, ///< Add to pathfinder penalty
|
||||
|
||||
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_UNDEFINED = 9, ///< This condition has no type defined (evaluate as false)
|
||||
TRIT_COND_TRAIN_LENGTH = 10, ///< Test train length
|
||||
TRIT_COND_MAX_SPEED = 11, ///< Test train max speed
|
||||
TRIT_COND_CURRENT_ORDER = 12, ///< Test train current order (station, waypoint or depot)
|
||||
TRIT_COND_NEXT_ORDER = 13, ///< Test train next order (station, waypoint or depot)
|
||||
TRIT_COND_LAST_STATION = 14, ///< Test train last visited station
|
||||
TRIT_COND_CARGO = 15, ///< Test if train can carry cargo type
|
||||
TRIT_COND_ENTRY_DIRECTION = 16, ///< Test which side of signal/signal tile is being entered from
|
||||
/* space up to 31 */
|
||||
};
|
||||
|
||||
/**
|
||||
* TraceRestrictItem condition flags field, only valid with conditional types (IsTraceRestrictTypeConditional() is true)
|
||||
*/
|
||||
enum TraceRestrictCondFlags {
|
||||
TRCF_DEFAULT = 0, ///< indicates end if for type: TRIT_COND_ENDIF, if otherwise
|
||||
TRCF_ELSE = 1 << 0, ///< indicates an else block for type: TRIT_COND_ENDIF, elif otherwise
|
||||
TRCF_OR = 1 << 1, ///< indicates an orif block, not valid with type: TRIT_COND_ENDIF
|
||||
/* 1 bit spare */
|
||||
};
|
||||
DECLARE_ENUM_AS_BIT_SET(TraceRestrictCondFlags)
|
||||
|
||||
/**
|
||||
* Enumeration of TraceRestrictItemvalue type field when type is TRIT_NULL
|
||||
*/
|
||||
enum TraceRestrictNullTypeSpecialValue {
|
||||
TRNTSV_NULL = 0, ///< null, what you get when you zero-init a TraceRestrictItemvalue
|
||||
TRNTSV_START = 1, ///< start tag, generated within GUI
|
||||
TRNTSV_END = 2, ///< end tag, generated within GUI
|
||||
};
|
||||
|
||||
/**
|
||||
* Enumeration of TraceRestrictItemvalue type field when value type is TRVT_DIRECTION
|
||||
*/
|
||||
enum TraceRestrictDirectionTypeSpecialValue {
|
||||
TRNTSV_NE = 0, ///< DIAGDIR_NE: entering at NE tile edge
|
||||
TRNTSV_SE = 1, ///< DIAGDIR_SE: entering at SE tile edge
|
||||
TRNTSV_SW = 2, ///< DIAGDIR_SW: entering at SW tile edge
|
||||
TRNTSV_NW = 3, ///< DIAGDIR_NW: entering at NW tile edge
|
||||
TRDTSV_FRONT = 4, ///< entering at front face of signal
|
||||
TRDTSV_BACK = 5, ///< entering at rear face of signal
|
||||
};
|
||||
|
||||
/**
|
||||
* TraceRestrictItem condition operator field, only valid with conditional types (IsTraceRestrictTypeConditional() is true)
|
||||
*/
|
||||
enum TraceRestrictCondOp {
|
||||
TRCO_IS = 0, ///< equality test, or can carry test for cargo
|
||||
TRCO_ISNOT = 1, ///< inequality test, or can't carry test for cargo
|
||||
TRCO_LT = 2, ///< less than test
|
||||
TRCO_LTE = 3, ///< less than or equal test
|
||||
TRCO_GT = 4, ///< greater than test
|
||||
TRCO_GTE = 5, ///< greater than or equal test
|
||||
/* space up to 7 */
|
||||
};
|
||||
|
||||
/**
|
||||
* TraceRestrictItem auxiliary type field, for order type conditionals
|
||||
*/
|
||||
enum TraceRestrictOrderCondAuxField {
|
||||
TROCAF_STATION = 0, ///< value field is a station StationID
|
||||
TROCAF_WAYPOINT = 1, ///< value field is a waypoint StationID
|
||||
TROCAF_DEPOT = 2, ///< value field is a depot DepotID
|
||||
/* space up to 3 */
|
||||
};
|
||||
|
||||
/**
|
||||
* Enumeration for TraceRestrictProgramResult::flags
|
||||
*/
|
||||
enum TraceRestrictProgramResultFlags {
|
||||
TRPRF_DENY = 1 << 0, ///< Pathfinder deny is set
|
||||
};
|
||||
DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramResultFlags)
|
||||
|
||||
/**
|
||||
* Execution input of a TraceRestrictProgram
|
||||
*/
|
||||
struct TraceRestrictProgramInput {
|
||||
TileIndex tile; ///< Tile of restrict signal, for direction testing
|
||||
Trackdir trackdir; ///< Track direction on tile of restrict signal, for direction testing
|
||||
|
||||
TraceRestrictProgramInput(TileIndex tile_, Trackdir trackdir_)
|
||||
: tile(tile_), trackdir(trackdir_) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* Execution result of a TraceRestrictProgram
|
||||
*/
|
||||
struct TraceRestrictProgramResult {
|
||||
uint32 penalty; ///< Total additional pathfinder penalty
|
||||
TraceRestrictProgramResultFlags flags; ///< Flags of other actions to take
|
||||
|
||||
TraceRestrictProgramResult()
|
||||
: penalty(0), flags(static_cast<TraceRestrictProgramResultFlags>(0)) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* Program type, this stores the instruction list
|
||||
* This is refcounted, see info at top of tracerestrict.cpp
|
||||
*/
|
||||
struct TraceRestrictProgram : TraceRestrictProgramPool::PoolItem<&_tracerestrictprogram_pool> {
|
||||
std::vector<TraceRestrictItem> items;
|
||||
uint32 refcount;
|
||||
|
||||
TraceRestrictProgram()
|
||||
: refcount(0) { }
|
||||
|
||||
void Execute(const Train *v, const TraceRestrictProgramInput &input, TraceRestrictProgramResult &out) const;
|
||||
|
||||
/**
|
||||
* Increment ref count, only use when creating a mapping
|
||||
*/
|
||||
void IncrementRefCount() { refcount++; }
|
||||
|
||||
void DecrementRefCount();
|
||||
|
||||
static CommandCost Validate(const std::vector<TraceRestrictItem> &items);
|
||||
|
||||
/**
|
||||
* Call validation function on current program instruction list
|
||||
*/
|
||||
CommandCost Validate() const { return TraceRestrictProgram::Validate(items); }
|
||||
};
|
||||
|
||||
/** Get TraceRestrictItem type field */
|
||||
static inline TraceRestrictItemType GetTraceRestrictType(TraceRestrictItem item)
|
||||
{
|
||||
return static_cast<TraceRestrictItemType>(GB(item, TRIFA_TYPE_OFFSET, TRIFA_TYPE_COUNT));
|
||||
}
|
||||
|
||||
/** Get TraceRestrictItem condition flags field */
|
||||
static inline TraceRestrictCondFlags GetTraceRestrictCondFlags(TraceRestrictItem item)
|
||||
{
|
||||
return static_cast<TraceRestrictCondFlags>(GB(item, TRIFA_COND_FLAGS_OFFSET, TRIFA_COND_FLAGS_COUNT));
|
||||
}
|
||||
|
||||
/** Get TraceRestrictItem condition operator field */
|
||||
static inline TraceRestrictCondOp GetTraceRestrictCondOp(TraceRestrictItem item)
|
||||
{
|
||||
return static_cast<TraceRestrictCondOp>(GB(item, TRIFA_COND_OP_OFFSET, TRIFA_COND_OP_COUNT));
|
||||
}
|
||||
|
||||
/** Get TraceRestrictItem auxiliary field */
|
||||
static inline uint8 GetTraceRestrictAuxField(TraceRestrictItem item)
|
||||
{
|
||||
return GB(item, TRIFA_AUX_FIELD_OFFSET, TRIFA_AUX_FIELD_COUNT);
|
||||
}
|
||||
|
||||
/** Get TraceRestrictItem value field */
|
||||
static inline uint16 GetTraceRestrictValue(TraceRestrictItem item)
|
||||
{
|
||||
return static_cast<uint16>(GB(item, TRIFA_VALUE_OFFSET, TRIFA_VALUE_COUNT));
|
||||
}
|
||||
|
||||
/** Set TraceRestrictItem type field */
|
||||
static inline void SetTraceRestrictType(TraceRestrictItem &item, TraceRestrictItemType type)
|
||||
{
|
||||
SB(item, TRIFA_TYPE_OFFSET, TRIFA_TYPE_COUNT, type);
|
||||
}
|
||||
|
||||
/** Set TraceRestrictItem condition operator field */
|
||||
static inline void SetTraceRestrictCondOp(TraceRestrictItem &item, TraceRestrictCondOp condop)
|
||||
{
|
||||
SB(item, TRIFA_COND_OP_OFFSET, TRIFA_COND_OP_COUNT, condop);
|
||||
}
|
||||
|
||||
/** Set TraceRestrictItem condition flags field */
|
||||
static inline void SetTraceRestrictCondFlags(TraceRestrictItem &item, TraceRestrictCondFlags condflags)
|
||||
{
|
||||
SB(item, TRIFA_COND_FLAGS_OFFSET, TRIFA_COND_FLAGS_COUNT, condflags);
|
||||
}
|
||||
|
||||
/** Set TraceRestrictItem auxiliary field */
|
||||
static inline void SetTraceRestrictAuxField(TraceRestrictItem &item, uint8 data)
|
||||
{
|
||||
SB(item, TRIFA_AUX_FIELD_OFFSET, TRIFA_AUX_FIELD_COUNT, data);
|
||||
}
|
||||
|
||||
/** Set TraceRestrictItem value field */
|
||||
static inline void SetTraceRestrictValue(TraceRestrictItem &item, uint16 value)
|
||||
{
|
||||
SB(item, TRIFA_VALUE_OFFSET, TRIFA_VALUE_COUNT, value);
|
||||
}
|
||||
|
||||
/** Is TraceRestrictItemType a conditional type? */
|
||||
static inline bool IsTraceRestrictTypeConditional(TraceRestrictItemType type)
|
||||
{
|
||||
return type >= TRIT_COND_BEGIN;
|
||||
}
|
||||
|
||||
/** Is TraceRestrictItem type field a conditional type? */
|
||||
static inline bool IsTraceRestrictConditional(TraceRestrictItem item)
|
||||
{
|
||||
return IsTraceRestrictTypeConditional(GetTraceRestrictType(item));
|
||||
}
|
||||
|
||||
/**
|
||||
* Categorisation of what is allowed in the TraceRestrictItem condition op field
|
||||
* see TraceRestrictTypePropertySet
|
||||
*/
|
||||
enum TraceRestrictConditionOpType {
|
||||
TRCOT_NONE = 0, ///< takes no condition op
|
||||
TRCOT_BINARY = 1, ///< takes "is" and "is not" condition ops
|
||||
TRCOT_ALL = 2, ///< takes all condition ops (i.e. all relational ops)
|
||||
};
|
||||
|
||||
/**
|
||||
* Categorisation of what is in the TraceRestrictItem value field
|
||||
* see TraceRestrictTypePropertySet
|
||||
*/
|
||||
enum TraceRestrictValueType {
|
||||
TRVT_NONE = 0, ///< value field not used (set to 0)
|
||||
TRVT_SPECIAL = 1, ///< special handling of value field
|
||||
TRVT_INT = 2, ///< takes an unsigned integer value
|
||||
TRVT_DENY = 3, ///< takes a value 0 = deny, 1 = allow (cancel previous deny)
|
||||
TRVT_SPEED = 4, ///< takes an integer speed value
|
||||
TRVT_ORDER = 5, ///< takes an order target ID, as per the auxiliary field as type: TraceRestrictOrderCondAuxField
|
||||
TRVT_CARGO_ID = 6, ///< takes a CargoID
|
||||
TRVT_DIRECTION = 7, ///< takes a TraceRestrictDirectionTypeSpecialValue
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes formats of TraceRestrictItem condition op and value fields
|
||||
*/
|
||||
struct TraceRestrictTypePropertySet {
|
||||
TraceRestrictConditionOpType cond_type;
|
||||
TraceRestrictValueType value_type;
|
||||
};
|
||||
|
||||
void SetTraceRestrictValueDefault(TraceRestrictItem &item, TraceRestrictValueType value_type);
|
||||
void SetTraceRestrictTypeAndNormalise(TraceRestrictItem &item, TraceRestrictItemType type);
|
||||
|
||||
/**
|
||||
* Get TraceRestrictTypePropertySet for a given instruction, only looks at value field
|
||||
*/
|
||||
static inline TraceRestrictTypePropertySet GetTraceRestrictTypeProperties(TraceRestrictItem item)
|
||||
{
|
||||
TraceRestrictTypePropertySet out;
|
||||
|
||||
if (GetTraceRestrictType(item) == TRIT_NULL) {
|
||||
out.cond_type = TRCOT_NONE;
|
||||
out.value_type = TRVT_SPECIAL;
|
||||
} else if (GetTraceRestrictType(item) == TRIT_COND_ENDIF ||
|
||||
GetTraceRestrictType(item) == TRIT_COND_UNDEFINED) {
|
||||
out.cond_type = TRCOT_NONE;
|
||||
out.value_type = TRVT_NONE;
|
||||
} else if (IsTraceRestrictConditional(item)) {
|
||||
out.cond_type = TRCOT_ALL;
|
||||
|
||||
switch (GetTraceRestrictType(item)) {
|
||||
case TRIT_COND_TRAIN_LENGTH:
|
||||
out.value_type = TRVT_INT;
|
||||
break;
|
||||
|
||||
case TRIT_COND_MAX_SPEED:
|
||||
out.value_type = TRVT_SPEED;
|
||||
break;
|
||||
|
||||
case TRIT_COND_CURRENT_ORDER:
|
||||
case TRIT_COND_NEXT_ORDER:
|
||||
case TRIT_COND_LAST_STATION:
|
||||
out.value_type = TRVT_ORDER;
|
||||
out.cond_type = TRCOT_BINARY;
|
||||
break;
|
||||
|
||||
case TRIT_COND_CARGO:
|
||||
out.value_type = TRVT_CARGO_ID;
|
||||
out.cond_type = TRCOT_BINARY;
|
||||
break;
|
||||
|
||||
case TRIT_COND_ENTRY_DIRECTION:
|
||||
out.value_type = TRVT_DIRECTION;
|
||||
out.cond_type = TRCOT_BINARY;
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
out.cond_type = TRCOT_NONE;
|
||||
if (GetTraceRestrictType(item) == TRIT_PF_PENALTY) {
|
||||
out.value_type = TRVT_INT;
|
||||
} else if (GetTraceRestrictType(item) == TRIT_PF_DENY) {
|
||||
out.value_type = TRVT_DENY;
|
||||
} else {
|
||||
out.value_type = TRVT_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Get mapping ref ID from tile and track */
|
||||
static inline TraceRestrictRefId MakeTraceRestrictRefId(TileIndex t, Track track)
|
||||
{
|
||||
return (t << 3) | track;
|
||||
}
|
||||
|
||||
/** Get tile from mapping ref ID */
|
||||
static inline TileIndex GetTraceRestrictRefIdTileIndex(TraceRestrictRefId ref)
|
||||
{
|
||||
return static_cast<TileIndex>(ref >> 3);
|
||||
}
|
||||
|
||||
/** Get track from mapping ref ID */
|
||||
static inline Track GetTraceRestrictRefIdTrack(TraceRestrictRefId ref)
|
||||
{
|
||||
return static_cast<Track>(ref & 7);
|
||||
}
|
||||
|
||||
void TraceRestrictCreateProgramMapping(TraceRestrictRefId ref, TraceRestrictProgram *prog);
|
||||
void TraceRestrictRemoveProgramMapping(TraceRestrictRefId ref);
|
||||
|
||||
TraceRestrictProgram *GetTraceRestrictProgram(TraceRestrictRefId ref, bool create_new);
|
||||
|
||||
void TraceRestrictNotifySignalRemoval(TileIndex tile, Track track);
|
||||
|
||||
/**
|
||||
* Gets the existing signal program for the tile identified by @p t and @p track, or NULL
|
||||
*/
|
||||
static inline const TraceRestrictProgram *GetExistingTraceRestrictProgram(TileIndex t, Track track)
|
||||
{
|
||||
if (IsRestrictedSignal(t)) {
|
||||
return GetTraceRestrictProgram(MakeTraceRestrictRefId(t, track), false);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration for command action type field, indicates what command to do
|
||||
*/
|
||||
enum TraceRestrictDoCommandType {
|
||||
TRDCT_INSERT_ITEM = 0, ///< insert new instruction before offset field as given value
|
||||
TRDCT_MODIFY_ITEM = 1, ///< modify instruction at offset field to given value
|
||||
TRDCT_REMOVE_ITEM = 2, ///< remove instruction at offset field
|
||||
|
||||
TRDCT_PROG_COPY = 3, ///< copy program operation. Do not re-order this with respect to other values
|
||||
TRDCT_PROG_SHARE = 4, ///< share program operation
|
||||
TRDCT_PROG_UNSHARE = 5, ///< unshare program (copy as a new program)
|
||||
TRDCT_PROG_RESET = 6, ///< reset program state of signal
|
||||
};
|
||||
|
||||
void TraceRestrictDoCommandP(TileIndex tile, Track track, TraceRestrictDoCommandType type, uint32 offset, uint32 value, StringID error_msg);
|
||||
|
||||
void TraceRestrictProgMgmtWithSourceDoCommandP(TileIndex tile, Track track, TraceRestrictDoCommandType type,
|
||||
TileIndex source_tile, Track source_track, StringID error_msg);
|
||||
|
||||
/**
|
||||
* Short-hand to call TraceRestrictProgMgmtWithSourceDoCommandP with 0 for source tile/track
|
||||
*/
|
||||
inline void TraceRestrictProgMgmtDoCommandP(TileIndex tile, Track track, TraceRestrictDoCommandType type, StringID error_msg)
|
||||
{
|
||||
TraceRestrictProgMgmtWithSourceDoCommandP(tile, track, type, static_cast<TileIndex>(0), static_cast<Track>(0), error_msg);
|
||||
}
|
||||
|
||||
CommandCost CmdProgramSignalTraceRestrict(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text);
|
||||
CommandCost CmdProgramSignalTraceRestrictProgMgmt(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text);
|
||||
|
||||
void ShowTraceRestrictProgramWindow(TileIndex tile, Track track);
|
||||
|
||||
void TraceRestrictRemoveDestinationID(TraceRestrictOrderCondAuxField type, uint16 index);
|
||||
|
||||
#endif /* TRACERESTRICT_H */
|
1588
src/tracerestrict_gui.cpp
Normal file
1588
src/tracerestrict_gui.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,7 @@
|
||||
#include "window_func.h"
|
||||
#include "newgrf_station.h"
|
||||
#include "waypoint_base.h"
|
||||
#include "tracerestrict.h"
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
@@ -54,4 +55,5 @@ Waypoint::~Waypoint()
|
||||
if (CleaningPool()) return;
|
||||
DeleteWindowById(WC_WAYPOINT_VIEW, this->index);
|
||||
RemoveOrderFromAllVehicles(OT_GOTO_WAYPOINT, this->index);
|
||||
TraceRestrictRemoveDestinationID(TROCAF_WAYPOINT, this->index);
|
||||
}
|
||||
|
@@ -91,6 +91,7 @@ enum BuildSignalWidgets {
|
||||
WID_BS_ELECTRIC_PBS, ///< Build an electric path signal.
|
||||
WID_BS_ELECTRIC_PBS_OWAY, ///< Build an electric one way path signal.
|
||||
WID_BS_CONVERT, ///< Convert the signal.
|
||||
WID_BS_TRACE_RESTRICT, ///< Open trace restrict window.
|
||||
WID_BS_DRAG_SIGNALS_DENSITY_LABEL, ///< The current signal density.
|
||||
WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, ///< Decrease the signal density.
|
||||
WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, ///< Increase the signal density.
|
||||
|
@@ -681,6 +681,12 @@ enum WindowClass {
|
||||
*/
|
||||
WC_SAVE_PRESET,
|
||||
|
||||
/**
|
||||
* Trace restrict programme window; %Window numbers:
|
||||
* - #TileIndex << 3 | #Track = #TraceRestrictWindow
|
||||
*/
|
||||
WC_TRACE_RESTRICT,
|
||||
|
||||
WC_INVALID = 0xFFFF, ///< Invalid window.
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user