Merge branch 'tracerestrict-sx' into jgrpp
This commit is contained in:
@@ -1273,6 +1273,10 @@
|
|||||||
<ClCompile Include="..\src\os\windows\win32.cpp" />
|
<ClCompile Include="..\src\os\windows\win32.cpp" />
|
||||||
<ClInclude Include="..\src\thread\thread.h" />
|
<ClInclude Include="..\src\thread\thread.h" />
|
||||||
<ClCompile Include="..\src\thread\thread_win32.cpp" />
|
<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>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\media\openttd.ico" />
|
<None Include="..\media\openttd.ico" />
|
||||||
|
@@ -3048,6 +3048,18 @@
|
|||||||
<ClCompile Include="..\src\thread\thread_win32.cpp">
|
<ClCompile Include="..\src\thread\thread_win32.cpp">
|
||||||
<Filter>Threading</Filter>
|
<Filter>Threading</Filter>
|
||||||
</ClCompile>
|
</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>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\media\openttd.ico" />
|
<None Include="..\media\openttd.ico" />
|
||||||
|
@@ -4490,6 +4490,22 @@
|
|||||||
RelativePath=".\..\src\thread\thread_win32.cpp"
|
RelativePath=".\..\src\thread\thread_win32.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</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>
|
</Filter>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\..\media\openttd.ico"
|
RelativePath=".\..\media\openttd.ico"
|
||||||
|
@@ -4487,6 +4487,22 @@
|
|||||||
RelativePath=".\..\src\thread\thread_win32.cpp"
|
RelativePath=".\..\src\thread\thread_win32.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</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>
|
</Filter>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\..\media\openttd.ico"
|
RelativePath=".\..\media\openttd.ico"
|
||||||
|
@@ -1195,3 +1195,8 @@ thread/thread.h
|
|||||||
#else
|
#else
|
||||||
thread/thread_none.cpp
|
thread/thread_none.cpp
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
tracerestrict.h
|
||||||
|
tracerestrict.cpp
|
||||||
|
tracerestrict_gui.cpp
|
||||||
|
saveload/tracerestrict_sl.cpp
|
||||||
|
@@ -198,6 +198,8 @@ CommandProc CmdSetTimetableStart;
|
|||||||
|
|
||||||
CommandProc CmdOpenCloseAirport;
|
CommandProc CmdOpenCloseAirport;
|
||||||
|
|
||||||
|
CommandProc CmdProgramSignalTraceRestrict;
|
||||||
|
|
||||||
#define DEF_CMD(proc, flags, type) {proc, #proc, (CommandFlags)flags, type}
|
#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(CmdSetTimetableStart, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_TIMETABLE_START
|
||||||
|
|
||||||
DEF_CMD(CmdOpenCloseAirport, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_OPEN_CLOSE_AIRPORT
|
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_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)
|
CMD_END, ///< Must ALWAYS be on the end of this list!! (period)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
#include "core/pool_func.hpp"
|
#include "core/pool_func.hpp"
|
||||||
#include "vehicle_gui.h"
|
#include "vehicle_gui.h"
|
||||||
#include "vehiclelist.h"
|
#include "vehiclelist.h"
|
||||||
|
#include "tracerestrict.h"
|
||||||
|
|
||||||
#include "safeguards.h"
|
#include "safeguards.h"
|
||||||
|
|
||||||
@@ -42,6 +43,8 @@ Depot::~Depot()
|
|||||||
/* Clear the depot from all order-lists */
|
/* Clear the depot from all order-lists */
|
||||||
RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, this->index);
|
RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, this->index);
|
||||||
|
|
||||||
|
TraceRestrictRemoveDestinationID(TROCAF_DEPOT, this->index);
|
||||||
|
|
||||||
/* Delete the depot-window */
|
/* Delete the depot-window */
|
||||||
DeleteWindowById(WC_VEHICLE_DEPOT, this->xy);
|
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_DECREASE_TOOLTIP :{BLACK}Decrease dragging signal density
|
||||||
STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Increase 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
|
# Bridge selection window
|
||||||
STR_SELECT_RAIL_BRIDGE_CAPTION :{WHITE}Select Rail Bridge
|
STR_SELECT_RAIL_BRIDGE_CAPTION :{WHITE}Select Rail Bridge
|
||||||
STR_SELECT_ROAD_BRIDGE_CAPTION :{WHITE}Select Road 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_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_TRAIN_DEPOT :{STRING} train depot
|
||||||
|
|
||||||
|
STR_LAI_RAIL_DESCRIPTION_RESTRICTED_SIGNAL :{STRING1} (restricted)
|
||||||
|
|
||||||
STR_LAI_ROAD_DESCRIPTION_ROAD :Road
|
STR_LAI_ROAD_DESCRIPTION_ROAD :Road
|
||||||
STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS :Road with street lights
|
STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS :Road with street lights
|
||||||
STR_LAI_ROAD_DESCRIPTION_TREE_LINED_ROAD :Tree-lined road
|
STR_LAI_ROAD_DESCRIPTION_TREE_LINED_ROAD :Tree-lined road
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
#include "core/pool_type.hpp"
|
#include "core/pool_type.hpp"
|
||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
#include "linkgraph/linkgraphschedule.h"
|
#include "linkgraph/linkgraphschedule.h"
|
||||||
|
#include "tracerestrict.h"
|
||||||
|
|
||||||
#include "safeguards.h"
|
#include "safeguards.h"
|
||||||
|
|
||||||
@@ -72,6 +73,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin
|
|||||||
}
|
}
|
||||||
|
|
||||||
LinkGraphSchedule::Clear();
|
LinkGraphSchedule::Clear();
|
||||||
|
ClearTraceRestrictMapping();
|
||||||
PoolBase::Clean(PT_NORMAL);
|
PoolBase::Clean(PT_NORMAL);
|
||||||
|
|
||||||
ResetPersistentNewGRFData();
|
ResetPersistentNewGRFData();
|
||||||
|
@@ -175,6 +175,7 @@ public:
|
|||||||
|
|
||||||
/* Tiletype */
|
/* Tiletype */
|
||||||
SetDParam(0, td.dparam[0]);
|
SetDParam(0, td.dparam[0]);
|
||||||
|
SetDParam(1, td.dparam[1]);
|
||||||
GetString(this->landinfo_data[line_nr], td.str, lastof(this->landinfo_data[line_nr]));
|
GetString(this->landinfo_data[line_nr], td.str, lastof(this->landinfo_data[line_nr]));
|
||||||
line_nr++;
|
line_nr++;
|
||||||
|
|
||||||
|
@@ -65,6 +65,7 @@
|
|||||||
#include "viewport_sprite_sorter.h"
|
#include "viewport_sprite_sorter.h"
|
||||||
|
|
||||||
#include "linkgraph/linkgraphschedule.h"
|
#include "linkgraph/linkgraphschedule.h"
|
||||||
|
#include "tracerestrict.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
@@ -302,6 +303,7 @@ static void ShutdownGame()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
LinkGraphSchedule::Clear();
|
LinkGraphSchedule::Clear();
|
||||||
|
ClearTraceRestrictMapping();
|
||||||
PoolBase::Clean(PT_ALL);
|
PoolBase::Clean(PT_ALL);
|
||||||
|
|
||||||
/* No NewGRFs were loaded when it was still bootstrapping. */
|
/* No NewGRFs were loaded when it was still bootstrapping. */
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#define YAPF_COSTRAIL_HPP
|
#define YAPF_COSTRAIL_HPP
|
||||||
|
|
||||||
#include "../../pbs.h"
|
#include "../../pbs.h"
|
||||||
|
#include "../../tracerestrict.h"
|
||||||
|
|
||||||
template <class Types>
|
template <class Types>
|
||||||
class CYapfCostRailT
|
class CYapfCostRailT
|
||||||
@@ -180,6 +181,30 @@ public:
|
|||||||
return 0;
|
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 SignalCost(Node& n, TileIndex tile, Trackdir trackdir)
|
||||||
{
|
{
|
||||||
int cost = 0;
|
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_num_signals_passed++;
|
||||||
n.m_segment->m_last_signal_tile = tile;
|
n.m_segment->m_last_signal_tile = tile;
|
||||||
n.m_segment->m_last_signal_td = trackdir;
|
n.m_segment->m_last_signal_td = trackdir;
|
||||||
@@ -246,6 +278,13 @@ public:
|
|||||||
|
|
||||||
if (has_signal_against && IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) {
|
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;
|
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 "strings_func.h"
|
||||||
#include "company_gui.h"
|
#include "company_gui.h"
|
||||||
#include "object_map.h"
|
#include "object_map.h"
|
||||||
|
#include "tracerestrict.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
#include "table/railtypes.h"
|
#include "table/railtypes.h"
|
||||||
@@ -1452,6 +1453,7 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1
|
|||||||
SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
|
SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
|
||||||
Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
|
Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
|
||||||
DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
|
DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
|
||||||
|
TraceRestrictNotifySignalRemoval(tile, track);
|
||||||
|
|
||||||
/* removed last signal from tile? */
|
/* removed last signal from tile? */
|
||||||
if (GetPresentSignals(tile) == 0) {
|
if (GetPresentSignals(tile) == 0) {
|
||||||
@@ -2768,6 +2770,12 @@ static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
|
|||||||
}
|
}
|
||||||
|
|
||||||
td->str = signal_type[secondary_signal][primary_signal];
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -34,6 +34,7 @@
|
|||||||
#include "vehicle_func.h"
|
#include "vehicle_func.h"
|
||||||
#include "zoom_func.h"
|
#include "zoom_func.h"
|
||||||
#include "rail_gui.h"
|
#include "rail_gui.h"
|
||||||
|
#include "tracerestrict.h"
|
||||||
|
|
||||||
#include "station_map.h"
|
#include "station_map.h"
|
||||||
#include "tunnelbridge_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 _waypoint_count = 1; ///< Number of waypoint types
|
||||||
static byte _cur_waypoint_type; ///< Currently selected waypoint type
|
static byte _cur_waypoint_type; ///< Currently selected waypoint type
|
||||||
static bool _convert_signal_button; ///< convert signal button in the signal GUI pressed
|
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 SignalVariant _cur_signal_variant; ///< set the signal variant (for signal GUI)
|
||||||
static SignalType _cur_signal_type; ///< set the signal type (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) {
|
if (_remove_button_clicked) {
|
||||||
DoCommandP(tile, track, 0, CMD_REMOVE_SIGNALS | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM), CcPlaySound1E);
|
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 {
|
} else {
|
||||||
const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
|
const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
|
||||||
|
|
||||||
@@ -1518,6 +1524,7 @@ public:
|
|||||||
~BuildSignalWindow()
|
~BuildSignalWindow()
|
||||||
{
|
{
|
||||||
_convert_signal_button = false;
|
_convert_signal_button = false;
|
||||||
|
_trace_restrict_button = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void OnInit()
|
virtual void OnInit()
|
||||||
@@ -1602,6 +1609,12 @@ public:
|
|||||||
|
|
||||||
case WID_BS_CONVERT:
|
case WID_BS_CONVERT:
|
||||||
_convert_signal_button = !_convert_signal_button;
|
_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;
|
break;
|
||||||
|
|
||||||
case WID_BS_DRAG_SIGNALS_DENSITY_DECREASE:
|
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->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_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_DECREASE, _settings_client.gui.drag_signals_density == 1);
|
||||||
this->SetWidgetDisabledState(WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, _settings_client.gui.drag_signals_density == 20);
|
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), 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_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_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(),
|
EndContainer(),
|
||||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
|
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),
|
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(),
|
EndContainer(),
|
||||||
NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0),
|
NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0),
|
||||||
EndContainer(),
|
EndContainer(),
|
||||||
|
NWidget(WWT_PANEL, COLOUR_DARK_GREEN), EndContainer(), SetFill(1, 1),
|
||||||
EndContainer(),
|
EndContainer(),
|
||||||
EndContainer(),
|
EndContainer(),
|
||||||
};
|
};
|
||||||
@@ -1974,6 +1990,7 @@ void InitializeRailGUI()
|
|||||||
SetDefaultRailGui();
|
SetDefaultRailGui();
|
||||||
|
|
||||||
_convert_signal_button = false;
|
_convert_signal_button = false;
|
||||||
|
_trace_restrict_button = false;
|
||||||
_cur_signal_type = _default_signal_type[_settings_client.gui.default_signal_type];
|
_cur_signal_type = _default_signal_type[_settings_client.gui.default_signal_type];
|
||||||
ResetSignalVariant();
|
ResetSignalVariant();
|
||||||
}
|
}
|
||||||
|
@@ -479,6 +479,26 @@ static inline bool HasOnewaySignalBlockingTrackdir(TileIndex tile, Trackdir td)
|
|||||||
!HasSignalOnTrackdir(tile, td) && IsOnewaySignal(tile, TrackdirToTrack(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);
|
RailType GetTileRailType(TileIndex tile);
|
||||||
|
|
||||||
|
@@ -2988,6 +2988,8 @@ bool AfterLoadGame()
|
|||||||
ResetSignalHandlers();
|
ResetSignalHandlers();
|
||||||
|
|
||||||
AfterLoadLinkGraphs();
|
AfterLoadLinkGraphs();
|
||||||
|
|
||||||
|
AfterLoadTraceRestrict();
|
||||||
return true;
|
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
|
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, 1, 1, "tracerestrict", NULL, NULL, "TRRM,TRRP" },
|
||||||
{ XSLFI_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker
|
{ 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;
|
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 {
|
enum SlXvFeatureIndex {
|
||||||
XSLFI_NULL = 0, ///< Unused value, to indicate that no extended feature test is in use
|
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
|
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 _airport_chunk_handlers[];
|
||||||
extern const ChunkHandler _object_chunk_handlers[];
|
extern const ChunkHandler _object_chunk_handlers[];
|
||||||
extern const ChunkHandler _persistent_storage_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. */
|
/** Array of all chunks in a savegame, \c NULL terminated. */
|
||||||
static const ChunkHandler * const _chunk_handlers[] = {
|
static const ChunkHandler * const _chunk_handlers[] = {
|
||||||
@@ -491,6 +492,7 @@ static const ChunkHandler * const _chunk_handlers[] = {
|
|||||||
_airport_chunk_handlers,
|
_airport_chunk_handlers,
|
||||||
_object_chunk_handlers,
|
_object_chunk_handlers,
|
||||||
_persistent_storage_chunk_handlers,
|
_persistent_storage_chunk_handlers,
|
||||||
|
_trace_restrict_chunk_handlers,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -34,6 +34,7 @@ void AfterLoadLabelMaps();
|
|||||||
void AfterLoadStoryBook();
|
void AfterLoadStoryBook();
|
||||||
void AfterLoadLinkGraphs();
|
void AfterLoadLinkGraphs();
|
||||||
void AfterLoadCompanyStats();
|
void AfterLoadCompanyStats();
|
||||||
|
void AfterLoadTraceRestrict();
|
||||||
void UpdateHousesAndTowns();
|
void UpdateHousesAndTowns();
|
||||||
|
|
||||||
void UpdateOldAircraft();
|
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 = ::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_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_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_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_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.
|
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 "core/random_func.hpp"
|
||||||
#include "linkgraph/linkgraph.h"
|
#include "linkgraph/linkgraph.h"
|
||||||
#include "linkgraph/linkgraphschedule.h"
|
#include "linkgraph/linkgraphschedule.h"
|
||||||
|
#include "tracerestrict.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
@@ -137,6 +138,8 @@ Station::~Station()
|
|||||||
/* Now delete all orders that go to the station */
|
/* Now delete all orders that go to the station */
|
||||||
RemoveOrderFromAllVehicles(OT_GOTO_STATION, this->index);
|
RemoveOrderFromAllVehicles(OT_GOTO_STATION, this->index);
|
||||||
|
|
||||||
|
TraceRestrictRemoveDestinationID(TROCAF_STATION, this->index);
|
||||||
|
|
||||||
/* Remove all news items */
|
/* Remove all news items */
|
||||||
DeleteStationNews(this->index);
|
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
|
#define IGNORE_UNINITIALIZED_WARNING_STOP
|
||||||
#endif
|
#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 */
|
#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 "window_func.h"
|
||||||
#include "newgrf_station.h"
|
#include "newgrf_station.h"
|
||||||
#include "waypoint_base.h"
|
#include "waypoint_base.h"
|
||||||
|
#include "tracerestrict.h"
|
||||||
|
|
||||||
#include "safeguards.h"
|
#include "safeguards.h"
|
||||||
|
|
||||||
@@ -54,4 +55,5 @@ Waypoint::~Waypoint()
|
|||||||
if (CleaningPool()) return;
|
if (CleaningPool()) return;
|
||||||
DeleteWindowById(WC_WAYPOINT_VIEW, this->index);
|
DeleteWindowById(WC_WAYPOINT_VIEW, this->index);
|
||||||
RemoveOrderFromAllVehicles(OT_GOTO_WAYPOINT, 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, ///< Build an electric path signal.
|
||||||
WID_BS_ELECTRIC_PBS_OWAY, ///< Build an electric one way path signal.
|
WID_BS_ELECTRIC_PBS_OWAY, ///< Build an electric one way path signal.
|
||||||
WID_BS_CONVERT, ///< Convert the 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_LABEL, ///< The current signal density.
|
||||||
WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, ///< Decrease the signal density.
|
WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, ///< Decrease the signal density.
|
||||||
WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, ///< Increase the signal density.
|
WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, ///< Increase the signal density.
|
||||||
|
@@ -681,6 +681,12 @@ enum WindowClass {
|
|||||||
*/
|
*/
|
||||||
WC_SAVE_PRESET,
|
WC_SAVE_PRESET,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trace restrict programme window; %Window numbers:
|
||||||
|
* - #TileIndex << 3 | #Track = #TraceRestrictWindow
|
||||||
|
*/
|
||||||
|
WC_TRACE_RESTRICT,
|
||||||
|
|
||||||
WC_INVALID = 0xFFFF, ///< Invalid window.
|
WC_INVALID = 0xFFFF, ///< Invalid window.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user