Merge branch 'tracerestrict-sx' into jgrpp

This commit is contained in:
Jonathan G Rennison
2015-08-02 17:59:10 +01:00
31 changed files with 3335 additions and 1 deletions

View File

@@ -1273,6 +1273,10 @@
<ClCompile Include="..\src\os\windows\win32.cpp" />
<ClInclude Include="..\src\thread\thread.h" />
<ClCompile Include="..\src\thread\thread_win32.cpp" />
<ClInclude Include="..\src\tracerestrict.h" />
<ClCompile Include="..\src\tracerestrict.cpp" />
<ClCompile Include="..\src\tracerestrict_gui.cpp" />
<ClCompile Include="..\src\saveload\tracerestrict_sl.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="..\media\openttd.ico" />

View File

@@ -3048,6 +3048,18 @@
<ClCompile Include="..\src\thread\thread_win32.cpp">
<Filter>Threading</Filter>
</ClCompile>
<ClInclude Include="..\src\tracerestrict.h">
<Filter>Threading</Filter>
</ClInclude>
<ClCompile Include="..\src\tracerestrict.cpp">
<Filter>Threading</Filter>
</ClCompile>
<ClCompile Include="..\src\tracerestrict_gui.cpp">
<Filter>Threading</Filter>
</ClCompile>
<ClCompile Include="..\src\saveload\tracerestrict_sl.cpp">
<Filter>Threading</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\media\openttd.ico" />

View File

@@ -4490,6 +4490,22 @@
RelativePath=".\..\src\thread\thread_win32.cpp"
>
</File>
<File
RelativePath=".\..\src\tracerestrict.h"
>
</File>
<File
RelativePath=".\..\src\tracerestrict.cpp"
>
</File>
<File
RelativePath=".\..\src\tracerestrict_gui.cpp"
>
</File>
<File
RelativePath=".\..\src\saveload\tracerestrict_sl.cpp"
>
</File>
</Filter>
<File
RelativePath=".\..\media\openttd.ico"

View File

@@ -4487,6 +4487,22 @@
RelativePath=".\..\src\thread\thread_win32.cpp"
>
</File>
<File
RelativePath=".\..\src\tracerestrict.h"
>
</File>
<File
RelativePath=".\..\src\tracerestrict.cpp"
>
</File>
<File
RelativePath=".\..\src\tracerestrict_gui.cpp"
>
</File>
<File
RelativePath=".\..\src\saveload\tracerestrict_sl.cpp"
>
</File>
</Filter>
<File
RelativePath=".\..\media\openttd.ico"

View File

@@ -1195,3 +1195,8 @@ thread/thread.h
#else
thread/thread_none.cpp
#end
tracerestrict.h
tracerestrict.cpp
tracerestrict_gui.cpp
saveload/tracerestrict_sl.cpp

View File

@@ -198,6 +198,8 @@ CommandProc CmdSetTimetableStart;
CommandProc CmdOpenCloseAirport;
CommandProc CmdProgramSignalTraceRestrict;
#define DEF_CMD(proc, flags, type) {proc, #proc, (CommandFlags)flags, type}
/**
@@ -354,6 +356,8 @@ static const Command _command_proc_table[] = {
DEF_CMD(CmdSetTimetableStart, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_TIMETABLE_START
DEF_CMD(CmdOpenCloseAirport, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_OPEN_CLOSE_AIRPORT
DEF_CMD(CmdProgramSignalTraceRestrict, 0, CMDT_OTHER_MANAGEMENT ), // CMD_PROGRAM_TRACERESTRICT_SIGNAL
};
/*!

View File

@@ -329,6 +329,8 @@ enum Commands {
CMD_OPEN_CLOSE_AIRPORT, ///< open/close an airport to incoming aircraft
CMD_PROGRAM_TRACERESTRICT_SIGNAL, ///< modify a signal tracerestrict program
CMD_END, ///< Must ALWAYS be on the end of this list!! (period)
};

View File

@@ -17,6 +17,7 @@
#include "core/pool_func.hpp"
#include "vehicle_gui.h"
#include "vehiclelist.h"
#include "tracerestrict.h"
#include "safeguards.h"
@@ -42,6 +43,8 @@ Depot::~Depot()
/* Clear the depot from all order-lists */
RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, this->index);
TraceRestrictRemoveDestinationID(TROCAF_DEPOT, this->index);
/* Delete the depot-window */
DeleteWindowById(WC_VEHICLE_DEPOT, this->xy);

View File

@@ -2370,6 +2370,93 @@ STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Dragging
STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}Decrease dragging signal density
STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Increase dragging signal density
# Tracerestrict GUI
STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_EQUALS :is
STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_NOT_EQUALS :is not
STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_LESS_THAN :<
STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_LESS_EQUALS :<=
STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_MORE_THAN :>
STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_MORE_EQUALS :>=
STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_CARGO_EQUALS :can carry
STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_CARGO_NOT_EQUALS :can't carry
STR_TRACE_RESTRICT_CONDITIONAL_IF :If
STR_TRACE_RESTRICT_CONDITIONAL_ELIF :Else if
STR_TRACE_RESTRICT_CONDITIONAL_ORIF :Or if
STR_TRACE_RESTRICT_CONDITIONAL_ELSE :Else
STR_TRACE_RESTRICT_CONDITIONAL_ENDIF :End if
STR_TRACE_RESTRICT_VARIABLE_TRAIN_LENGTH :train length
STR_TRACE_RESTRICT_VARIABLE_MAX_SPEED :max speed
STR_TRACE_RESTRICT_VARIABLE_CURRENT_ORDER :current order
STR_TRACE_RESTRICT_VARIABLE_NEXT_ORDER :next order
STR_TRACE_RESTRICT_VARIABLE_LAST_VISITED_STATION :last visited station
STR_TRACE_RESTRICT_VARIABLE_CARGO :cargo
STR_TRACE_RESTRICT_VARIABLE_ENTRY_DIRECTION :entry direction
STR_TRACE_RESTRICT_VARIABLE_UNDEFINED :undefined
STR_TRACE_RESTRICT_CONDITIONAL_COMPARE_INTEGER :{STRING} {STRING} {STRING} {COMMA} then
STR_TRACE_RESTRICT_CONDITIONAL_COMPARE_SPEED :{STRING} {STRING} {STRING} {VELOCITY} then
STR_TRACE_RESTRICT_CONDITIONAL_ORDER_STATION :{STRING} {STRING} {STRING} {STATION} then
STR_TRACE_RESTRICT_CONDITIONAL_ORDER_WAYPOINT :{STRING} {STRING} {STRING} {WAYPOINT} then
STR_TRACE_RESTRICT_CONDITIONAL_ORDER_DEPOT :{STRING} {STRING} {STRING} {DEPOT} then
STR_TRACE_RESTRICT_CONDITIONAL_CARGO :{STRING} train {STRING} cargo: {STRING} then
STR_TRACE_RESTRICT_CONDITIONAL_ENTRY_DIRECTION :{STRING} train {STRING} entering from {STRING} tile edge then
STR_TRACE_RESTRICT_CONDITIONAL_ENTRY_SIGNAL_FACE :{STRING} train {STRING} entering from {STRING} of signal then
STR_TRACE_RESTRICT_CONDITIONAL_UNDEFINED :{STRING} {STRING} {STRING} {RED}undefined {BLACK}{STRING}then
STR_TRACE_RESTRICT_CONDITIONAL_COMPARE_UNDEFINED :{STRING} {RED}undefined {BLACK}{STRING}then
STR_TRACE_RESTRICT_PF_PENALTY_ITEM :Add pathfinder penalty: {COMMA}
STR_TRACE_RESTRICT_WHITE :{WHITE}
STR_TRACE_RESTRICT_START :Start
STR_TRACE_RESTRICT_END :End
STR_TRACE_RESTRICT_PF_DENY :Deny
STR_TRACE_RESTRICT_PF_ALLOW :Allow
STR_TRACE_RESTRICT_PF_ALLOW_LONG :Allow (cancel previous Deny)
STR_TRACE_RESTRICT_PF_PENALTY :Penalty
STR_TRACE_RESTRICT_DIRECTION_FRONT :front
STR_TRACE_RESTRICT_DIRECTION_BACK :back
STR_TRACE_RESTRICT_DIRECTION_NE :north-east
STR_TRACE_RESTRICT_DIRECTION_SE :south-east
STR_TRACE_RESTRICT_DIRECTION_SW :south-west
STR_TRACE_RESTRICT_DIRECTION_NW :north-west
STR_TRACE_RESTRICT_VALUE_CAPTION :{WHITE}Value
STR_TRACE_RESTRICT_CAPTION :{WHITE}Routefinding restriction
STR_TRACE_RESTRICT_CAPTION_SHARED :{WHITE}Routefinding restriction - shared by {COMMA} signals
STR_TRACE_RESTRICT_TYPE_TOOLTIP :{BLACK}Type
STR_TRACE_RESTRICT_COND_COMPARATOR_TOOLTIP :{BLACK}Comparison operator
STR_TRACE_RESTRICT_COND_VALUE_TOOLTIP :{BLACK}Value
STR_TRACE_RESTRICT_CONDFLAGS_TOOLTIP :{BLACK}Condition type
STR_TRACE_RESTRICT_GOTO_SIGNAL_TOOLTIP :{BLACK}Go to signal
STR_TRACE_RESTRICT_INSERT :{BLACK}Insert
STR_TRACE_RESTRICT_REMOVE :{BLACK}Remove
STR_TRACE_RESTRICT_RESET :{BLACK}Reset
STR_TRACE_RESTRICT_COPY :{BLACK}Copy
STR_TRACE_RESTRICT_SHARE :{BLACK}Share
STR_TRACE_RESTRICT_UNSHARE :{BLACK}Unshare
STR_TRACE_RESTRICT_SELECT_TARGET :{BLACK}Select Target
STR_TRACE_RESTRICT_INSERT_TOOLTIP :{BLACK}Insert an instruction
STR_TRACE_RESTRICT_REMOVE_TOOLTIP :{BLACK}Remove the selected instruction
STR_TRACE_RESTRICT_RESET_TOOLTIP :{BLACK}Reset the current signal (without affecting shared programs)
STR_TRACE_RESTRICT_COPY_TOOLTIP :{BLACK}Copy program from another signal
STR_TRACE_RESTRICT_SHARE_TOOLTIP :{BLACK}Share program with another signal
STR_TRACE_RESTRICT_UNSHARE_TOOLTIP :{BLACK}Stop sharing program with other signals, create a copy of the program
STR_TRACE_RESTRICT_SIGNAL_GUI_TOOLTIP :{BLACK}Routefinding restriction
STR_TRACE_RESTRICT_INSTRUCTION_LIST_TOOLTIP :{BLACK}Click an instruction to select it{}Ctrl+Click to scroll to the instruction's target (if any)
STR_TRACE_RESTRICT_ERROR_CAN_T_INSERT_ITEM :{WHITE}Can't insert instruction
STR_TRACE_RESTRICT_ERROR_CAN_T_MODIFY_ITEM :{WHITE}Can't modify instruction
STR_TRACE_RESTRICT_ERROR_CAN_T_REMOVE_ITEM :{WHITE}Can't remove instruction
STR_TRACE_RESTRICT_ERROR_VALUE_TOO_LARGE :{WHITE}Value too large, maximum is {COMMA}
STR_TRACE_RESTRICT_ERROR_NO_PROGRAM :No trace restrict program exists
STR_TRACE_RESTRICT_ERROR_OFFSET_TOO_LARGE :Offset too large
STR_TRACE_RESTRICT_ERROR_CAN_T_CHANGE_CONDITIONALITY :Can't change conditionality
STR_TRACE_RESTRICT_ERROR_CAN_T_REMOVE_ENDIF :Can't remove an 'end if'
STR_TRACE_RESTRICT_ERROR_VALIDATE_END_CONDSTACK :Validation failed: condstack non-empty at exit
STR_TRACE_RESTRICT_ERROR_VALIDATE_NO_IF :Validation failed: else/endif without opening if
STR_TRACE_RESTRICT_ERROR_VALIDATE_DUP_ELSE :Validation failed: duplicate else
STR_TRACE_RESTRICT_ERROR_VALIDATE_ELIF_NO_IF :Validation failed: else if without opening if
STR_TRACE_RESTRICT_ERROR_SOURCE_SAME_AS_TARGET :Source and target signals are the same
STR_TRACE_RESTRICT_ERROR_CAN_T_RESET_SIGNAL :{WHITE}Can't reset signal
STR_TRACE_RESTRICT_ERROR_CAN_T_COPY_PROGRAM :{WHITE}Can't copy program
STR_TRACE_RESTRICT_ERROR_CAN_T_SHARE_PROGRAM :{WHITE}Can't share program
STR_TRACE_RESTRICT_ERROR_CAN_T_UNSHARE_PROGRAM :{WHITE}Can't unshare program
# Bridge selection window
STR_SELECT_RAIL_BRIDGE_CAPTION :{WHITE}Select Rail Bridge
STR_SELECT_ROAD_BRIDGE_CAPTION :{WHITE}Select Road Bridge
@@ -2625,6 +2712,8 @@ STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS :{STRING} track
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS :{STRING} track with path and one-way path signals
STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT :{STRING} train depot
STR_LAI_RAIL_DESCRIPTION_RESTRICTED_SIGNAL :{STRING1} (restricted)
STR_LAI_ROAD_DESCRIPTION_ROAD :Road
STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS :Road with street lights
STR_LAI_ROAD_DESCRIPTION_TREE_LINED_ROAD :Tree-lined road

View File

@@ -28,6 +28,7 @@
#include "core/pool_type.hpp"
#include "game/game.hpp"
#include "linkgraph/linkgraphschedule.h"
#include "tracerestrict.h"
#include "safeguards.h"
@@ -72,6 +73,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin
}
LinkGraphSchedule::Clear();
ClearTraceRestrictMapping();
PoolBase::Clean(PT_NORMAL);
ResetPersistentNewGRFData();

View File

@@ -175,6 +175,7 @@ public:
/* Tiletype */
SetDParam(0, td.dparam[0]);
SetDParam(1, td.dparam[1]);
GetString(this->landinfo_data[line_nr], td.str, lastof(this->landinfo_data[line_nr]));
line_nr++;

View File

@@ -65,6 +65,7 @@
#include "viewport_sprite_sorter.h"
#include "linkgraph/linkgraphschedule.h"
#include "tracerestrict.h"
#include <stdarg.h>
@@ -302,6 +303,7 @@ static void ShutdownGame()
#endif
LinkGraphSchedule::Clear();
ClearTraceRestrictMapping();
PoolBase::Clean(PT_ALL);
/* No NewGRFs were loaded when it was still bootstrapping. */

View File

@@ -13,6 +13,7 @@
#define YAPF_COSTRAIL_HPP
#include "../../pbs.h"
#include "../../tracerestrict.h"
template <class Types>
class CYapfCostRailT
@@ -180,6 +181,30 @@ public:
return 0;
}
private:
// returns true if ExecuteTraceRestrict should be called
inline bool ShouldCheckTraceRestrict(Node& n, TileIndex tile)
{
return n.m_num_signals_passed < m_sig_look_ahead_costs.Size() &&
IsRestrictedSignal(tile);
}
// returns true if dead end bit has been set
inline bool ExecuteTraceRestrict(Node& n, TileIndex tile, Trackdir trackdir, int& cost, TraceRestrictProgramResult &out)
{
const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(trackdir));
if (prog) {
prog->Execute(Yapf().GetVehicle(), TraceRestrictProgramInput(tile, trackdir), out);
if (out.flags & TRPRF_DENY) {
n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
return true;
}
cost += out.penalty;
}
return false;
}
public:
int SignalCost(Node& n, TileIndex tile, Trackdir trackdir)
{
int cost = 0;
@@ -239,6 +264,13 @@ public:
}
}
if (ShouldCheckTraceRestrict(n, tile)) {
TraceRestrictProgramResult out;
if (ExecuteTraceRestrict(n, tile, trackdir, cost, out)) {
return -1;
}
}
n.m_num_signals_passed++;
n.m_segment->m_last_signal_tile = tile;
n.m_segment->m_last_signal_td = trackdir;
@@ -246,6 +278,13 @@ public:
if (has_signal_against && IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) {
cost += n.m_num_signals_passed < Yapf().PfGetSettings().rail_look_ahead_max_signals ? Yapf().PfGetSettings().rail_pbs_signal_back_penalty : 0;
if (ShouldCheckTraceRestrict(n, tile)) {
TraceRestrictProgramResult out;
if (ExecuteTraceRestrict(n, tile, trackdir, cost, out)) {
return -1;
}
}
}
}
}

View File

@@ -33,6 +33,7 @@
#include "strings_func.h"
#include "company_gui.h"
#include "object_map.h"
#include "tracerestrict.h"
#include "table/strings.h"
#include "table/railtypes.h"
@@ -1452,6 +1453,7 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1
SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
TraceRestrictNotifySignalRemoval(tile, track);
/* removed last signal from tile? */
if (GetPresentSignals(tile) == 0) {
@@ -2768,6 +2770,12 @@ static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
}
td->str = signal_type[secondary_signal][primary_signal];
if (IsRestrictedSignal(tile)) {
SetDParamX(td->dparam, 0, td->str);
SetDParamX(td->dparam, 1, rti->strings.name);
td->str = STR_LAI_RAIL_DESCRIPTION_RESTRICTED_SIGNAL;
}
break;
}

View File

@@ -34,6 +34,7 @@
#include "vehicle_func.h"
#include "zoom_func.h"
#include "rail_gui.h"
#include "tracerestrict.h"
#include "station_map.h"
#include "tunnelbridge_map.h"
@@ -49,6 +50,7 @@ static DiagDirection _build_depot_direction; ///< Currently selected depot direc
static byte _waypoint_count = 1; ///< Number of waypoint types
static byte _cur_waypoint_type; ///< Currently selected waypoint type
static bool _convert_signal_button; ///< convert signal button in the signal GUI pressed
static bool _trace_restrict_button; ///< trace restrict button in the signal GUI pressed
static SignalVariant _cur_signal_variant; ///< set the signal variant (for signal GUI)
static SignalType _cur_signal_type; ///< set the signal type (for signal GUI)
@@ -224,6 +226,10 @@ static void GenericPlaceSignals(TileIndex tile)
if (_remove_button_clicked) {
DoCommandP(tile, track, 0, CMD_REMOVE_SIGNALS | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM), CcPlaySound1E);
} else if (_trace_restrict_button) {
if (IsPlainRailTile(tile) && HasTrack(tile, track) && HasSignalOnTrack(tile, track)) {
ShowTraceRestrictProgramWindow(tile, track);
}
} else {
const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
@@ -1518,6 +1524,7 @@ public:
~BuildSignalWindow()
{
_convert_signal_button = false;
_trace_restrict_button = false;
}
virtual void OnInit()
@@ -1602,6 +1609,12 @@ public:
case WID_BS_CONVERT:
_convert_signal_button = !_convert_signal_button;
if (_convert_signal_button) _trace_restrict_button = false;
break;
case WID_BS_TRACE_RESTRICT:
_trace_restrict_button = !_trace_restrict_button;
if (_trace_restrict_button) _convert_signal_button = false;
break;
case WID_BS_DRAG_SIGNALS_DENSITY_DECREASE:
@@ -1635,6 +1648,7 @@ public:
this->LowerWidget((_cur_signal_variant == SIG_ELECTRIC ? WID_BS_ELECTRIC_NORM : WID_BS_SEMAPHORE_NORM) + _cur_signal_type);
this->SetWidgetLoweredState(WID_BS_CONVERT, _convert_signal_button);
this->SetWidgetLoweredState(WID_BS_TRACE_RESTRICT, _trace_restrict_button);
this->SetWidgetDisabledState(WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, _settings_client.gui.drag_signals_density == 1);
this->SetWidgetDisabledState(WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, _settings_client.gui.drag_signals_density == 20);
@@ -1656,6 +1670,7 @@ static const NWidgetPart _nested_signal_builder_widgets[] = {
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP), EndContainer(), SetFill(1, 1),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_BS_CONVERT), SetDataTip(SPR_IMG_SIGNAL_CONVERT, STR_BUILD_SIGNAL_CONVERT_TOOLTIP), SetFill(1, 1),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_BS_TRACE_RESTRICT), SetDataTip(SPR_IMG_SETTINGS, STR_TRACE_RESTRICT_SIGNAL_GUI_TOOLTIP), SetFill(1, 1),
EndContainer(),
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_NORM), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP), EndContainer(), SetFill(1, 1),
@@ -1674,6 +1689,7 @@ static const NWidgetPart _nested_signal_builder_widgets[] = {
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN), EndContainer(), SetFill(1, 1),
EndContainer(),
EndContainer(),
};
@@ -1974,6 +1990,7 @@ void InitializeRailGUI()
SetDefaultRailGui();
_convert_signal_button = false;
_trace_restrict_button = false;
_cur_signal_type = _default_signal_type[_settings_client.gui.default_signal_type];
ResetSignalVariant();
}

View File

@@ -479,6 +479,26 @@ static inline bool HasOnewaySignalBlockingTrackdir(TileIndex tile, Trackdir td)
!HasSignalOnTrackdir(tile, td) && IsOnewaySignal(tile, TrackdirToTrack(td));
}
/**
* Does signal tile have "one or more trace restrict mappings present" bit set
* @param tile the tile to check
*/
static inline bool IsRestrictedSignal(TileIndex tile)
{
assert(GetRailTileType(tile) == RAIL_TILE_SIGNALS);
return (bool) GB(_m[tile].m2, 12, 1);
}
/**
* Set signal tile "one or more trace restrict mappings present" bit
* @param tile the tile to set
*/
static inline void SetRestrictedSignal(TileIndex tile, bool is_restricted)
{
assert(GetRailTileType(tile) == RAIL_TILE_SIGNALS);
SB(_m[tile].m2, 12, 1, is_restricted);
}
RailType GetTileRailType(TileIndex tile);

View File

@@ -2988,6 +2988,8 @@ bool AfterLoadGame()
ResetSignalHandlers();
AfterLoadLinkGraphs();
AfterLoadTraceRestrict();
return true;
}

View File

@@ -45,6 +45,7 @@ std::vector<uint32> _sl_xv_discardable_chunk_ids; ///< list of chunks
static const uint32 _sl_xv_slxi_chunk_version = 0; ///< current version os SLXI chunk
const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_TRACE_RESTRICT, XSCF_NULL, 1, 1, "tracerestrict", NULL, NULL, "TRRM,TRRP" },
{ XSLFI_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker
};
@@ -121,7 +122,12 @@ void SlXvCheckSpecialSavegameVersions()
{
extern uint16 _sl_version;
// TODO: check for savegame versions
if (_sl_version == 2000) {
DEBUG(sl, 1, "Loading a trace restrict patch savegame version %d as version 194", _sl_version);
_sl_version = 194;
_sl_is_faked_ext = true;
_sl_xv_feature_versions[XSLFI_TRACE_RESTRICT] = 1;
}
}
/**

View File

@@ -21,6 +21,7 @@
*/
enum SlXvFeatureIndex {
XSLFI_NULL = 0, ///< Unused value, to indicate that no extended feature test is in use
XSLFI_TRACE_RESTRICT, ///< Trace restrict
XSLFI_SIZE, ///< Total count of features, including null feature
};

View File

@@ -454,6 +454,7 @@ extern const ChunkHandler _linkgraph_chunk_handlers[];
extern const ChunkHandler _airport_chunk_handlers[];
extern const ChunkHandler _object_chunk_handlers[];
extern const ChunkHandler _persistent_storage_chunk_handlers[];
extern const ChunkHandler _trace_restrict_chunk_handlers[];
/** Array of all chunks in a savegame, \c NULL terminated. */
static const ChunkHandler * const _chunk_handlers[] = {
@@ -491,6 +492,7 @@ static const ChunkHandler * const _chunk_handlers[] = {
_airport_chunk_handlers,
_object_chunk_handlers,
_persistent_storage_chunk_handlers,
_trace_restrict_chunk_handlers,
NULL,
};

View File

@@ -34,6 +34,7 @@ void AfterLoadLabelMaps();
void AfterLoadStoryBook();
void AfterLoadLinkGraphs();
void AfterLoadCompanyStats();
void AfterLoadTraceRestrict();
void UpdateHousesAndTowns();
void UpdateOldAircraft();

View 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
};

View File

@@ -2054,6 +2054,7 @@ public:
WID_BS_ELECTRIC_PBS = ::WID_BS_ELECTRIC_PBS, ///< Build an electric path signal.
WID_BS_ELECTRIC_PBS_OWAY = ::WID_BS_ELECTRIC_PBS_OWAY, ///< Build an electric one way path signal.
WID_BS_CONVERT = ::WID_BS_CONVERT, ///< Convert the signal.
WID_BS_TRACE_RESTRICT = ::WID_BS_TRACE_RESTRICT, ///< Open trace restrict window.
WID_BS_DRAG_SIGNALS_DENSITY_LABEL = ::WID_BS_DRAG_SIGNALS_DENSITY_LABEL, ///< The current signal density.
WID_BS_DRAG_SIGNALS_DENSITY_DECREASE = ::WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, ///< Decrease the signal density.
WID_BS_DRAG_SIGNALS_DENSITY_INCREASE = ::WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, ///< Increase the signal density.

View File

@@ -26,6 +26,7 @@
#include "core/random_func.hpp"
#include "linkgraph/linkgraph.h"
#include "linkgraph/linkgraphschedule.h"
#include "tracerestrict.h"
#include "table/strings.h"
@@ -137,6 +138,8 @@ Station::~Station()
/* Now delete all orders that go to the station */
RemoveOrderFromAllVehicles(OT_GOTO_STATION, this->index);
TraceRestrictRemoveDestinationID(TROCAF_STATION, this->index);
/* Remove all news items */
DeleteStationNews(this->index);

View File

@@ -514,4 +514,15 @@ static inline void free(const void *ptr)
#define IGNORE_UNINITIALIZED_WARNING_STOP
#endif
/*
* Conditional define for the override keyword.
* Use of the override keyword can prevent various types of problems when the base method signature is changed, but derived overriding methods are not
* This is conditional to maintain compatibility with legacy compilers
*/
#if __cplusplus >= 201103L || defined(__STDCXX_VERSION__) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__)
#define OVERRIDE override
#else
#define OVERRIDE
#endif
#endif /* STDAFX_H */

894
src/tracerestrict.cpp Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

View File

@@ -15,6 +15,7 @@
#include "window_func.h"
#include "newgrf_station.h"
#include "waypoint_base.h"
#include "tracerestrict.h"
#include "safeguards.h"
@@ -54,4 +55,5 @@ Waypoint::~Waypoint()
if (CleaningPool()) return;
DeleteWindowById(WC_WAYPOINT_VIEW, this->index);
RemoveOrderFromAllVehicles(OT_GOTO_WAYPOINT, this->index);
TraceRestrictRemoveDestinationID(TROCAF_WAYPOINT, this->index);
}

View File

@@ -91,6 +91,7 @@ enum BuildSignalWidgets {
WID_BS_ELECTRIC_PBS, ///< Build an electric path signal.
WID_BS_ELECTRIC_PBS_OWAY, ///< Build an electric one way path signal.
WID_BS_CONVERT, ///< Convert the signal.
WID_BS_TRACE_RESTRICT, ///< Open trace restrict window.
WID_BS_DRAG_SIGNALS_DENSITY_LABEL, ///< The current signal density.
WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, ///< Decrease the signal density.
WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, ///< Increase the signal density.

View File

@@ -681,6 +681,12 @@ enum WindowClass {
*/
WC_SAVE_PRESET,
/**
* Trace restrict programme window; %Window numbers:
* - #TileIndex << 3 | #Track = #TraceRestrictWindow
*/
WC_TRACE_RESTRICT,
WC_INVALID = 0xFFFF, ///< Invalid window.
};