You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OpenTTD-patches/src/tracerestrict.h

513 lines
19 KiB
C

/*
* 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);
static size_t InstructionOffsetToArrayOffset(const std::vector<TraceRestrictItem> &items, size_t offset);
static size_t ArrayOffsetToInstructionOffset(const std::vector<TraceRestrictItem> &items, size_t offset);
/** Call InstructionOffsetToArrayOffset on current program instruction list */
size_t InstructionOffsetToArrayOffset(size_t offset) const
{
return TraceRestrictProgram::InstructionOffsetToArrayOffset(this->items, offset);
}
/** Call ArrayOffsetToInstructionOffset on current program instruction list */
size_t ArrayOffsetToInstructionOffset(size_t offset) const
{
return TraceRestrictProgram::ArrayOffsetToInstructionOffset(this->items, offset);
}
/** Get number of instructions in @p items */
static size_t GetInstructionCount(const std::vector<TraceRestrictItem> &items)
{
return ArrayOffsetToInstructionOffset(items, items.size());
}
/** Call GetInstructionCount on current program instruction list */
size_t GetInstructionCount() const
{
return TraceRestrictProgram::GetInstructionCount(this->items);
}
/** Get an iterator to the instruction at a given @p instruction_offset in @p items */
static std::vector<TraceRestrictItem>::iterator InstructionAt(std::vector<TraceRestrictItem> &items, size_t instruction_offset)
{
return items.begin() + TraceRestrictProgram::InstructionOffsetToArrayOffset(items, instruction_offset);
}
/** Get a const_iterator to the instruction at a given @p instruction_offset in @p items */
static std::vector<TraceRestrictItem>::const_iterator InstructionAt(const std::vector<TraceRestrictItem> &items, size_t instruction_offset)
{
return items.begin() + TraceRestrictProgram::InstructionOffsetToArrayOffset(items, instruction_offset);
}
/**
* 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));
}
/** Is TraceRestrictItem a double-item type? */
static inline bool IsTraceRestrictDoubleItem(TraceRestrictItem item)
{
return false;
}
/**
* 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, ///< insert new instruction before offset field as given value
TRDCT_MODIFY_ITEM, ///< modify instruction at offset field to given value
TRDCT_MODIFY_DUAL_ITEM, ///< modify second item of dual-part instruction at offset field to given value
TRDCT_REMOVE_ITEM, ///< remove instruction at offset field
TRDCT_PROG_COPY, ///< copy program operation. Do not re-order this with respect to other values
TRDCT_PROG_SHARE, ///< share program operation
TRDCT_PROG_UNSHARE, ///< unshare program (copy as a new program)
TRDCT_PROG_RESET, ///< 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 */