Initial support for multi-item instructions.
This involves various changes to instruction modification actions, and the GUI code.
This commit is contained in:
@@ -395,6 +395,14 @@ CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem>
|
||||
}
|
||||
HandleCondition(condstack, condflags, true);
|
||||
}
|
||||
} else {
|
||||
// check multi-word instructions
|
||||
if (IsTraceRestrictDoubleItem(item)) {
|
||||
i++;
|
||||
if (i >= size) {
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_OFFSET_TOO_LARGE); // instruction ran off end
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!condstack.empty()) {
|
||||
@@ -403,6 +411,35 @@ CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem>
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an instruction index into an item array index
|
||||
*/
|
||||
size_t TraceRestrictProgram::InstructionOffsetToArrayOffset(const std::vector<TraceRestrictItem> &items, size_t offset)
|
||||
{
|
||||
size_t output_offset = 0;
|
||||
size_t size = items.size();
|
||||
for (size_t i = 0; i < offset && output_offset < size; i++, output_offset++) {
|
||||
if (IsTraceRestrictDoubleItem(items[output_offset])) {
|
||||
output_offset++;
|
||||
}
|
||||
}
|
||||
return output_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an item array index into an instruction index
|
||||
*/
|
||||
size_t TraceRestrictProgram::ArrayOffsetToInstructionOffset(const std::vector<TraceRestrictItem> &items, size_t offset)
|
||||
{
|
||||
size_t output_offset = 0;
|
||||
for (size_t i = 0; i < offset; i++, output_offset++) {
|
||||
if (IsTraceRestrictDoubleItem(items[i])) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return output_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value and aux field of @p item, as per the value type in @p value_type
|
||||
*/
|
||||
@@ -595,6 +632,18 @@ static CommandCost TraceRestrictCheckTileIsUsable(TileIndex tile, Track track)
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an appropriate default value for the second item of a dual-item instruction
|
||||
* @p item is the first item of the instruction
|
||||
*/
|
||||
static uint32 GetDualInstructionInitialValue(TraceRestrictItem item)
|
||||
{
|
||||
switch (GetTraceRestrictType(item)) {
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main command for editing a signal tracerestrict program.
|
||||
* @param tile The tile which contains the signal.
|
||||
@@ -641,28 +690,46 @@ CommandCost CmdProgramSignalTraceRestrict(TileIndex tile, DoCommandFlag flags, u
|
||||
|
||||
switch (type) {
|
||||
case TRDCT_INSERT_ITEM:
|
||||
items.insert(items.begin() + offset, item);
|
||||
items.insert(TraceRestrictProgram::InstructionAt(items, 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);
|
||||
items.insert(TraceRestrictProgram::InstructionAt(items, offset) + 1, endif_item);
|
||||
} else if (IsTraceRestrictDoubleItem(item)) {
|
||||
items.insert(TraceRestrictProgram::InstructionAt(items, offset) + 1, GetDualInstructionInitialValue(item));
|
||||
}
|
||||
break;
|
||||
|
||||
case TRDCT_MODIFY_ITEM: {
|
||||
TraceRestrictItem old_item = items[offset];
|
||||
if (IsTraceRestrictConditional(old_item) != IsTraceRestrictConditional(item)) {
|
||||
std::vector<TraceRestrictItem>::iterator old_item = TraceRestrictProgram::InstructionAt(items, offset);
|
||||
if (IsTraceRestrictConditional(*old_item) != IsTraceRestrictConditional(item)) {
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_CAN_T_CHANGE_CONDITIONALITY);
|
||||
}
|
||||
items[offset] = item;
|
||||
bool old_is_dual = IsTraceRestrictDoubleItem(*old_item);
|
||||
bool new_is_dual = IsTraceRestrictDoubleItem(item);
|
||||
*old_item = item;
|
||||
if (old_is_dual && !new_is_dual) {
|
||||
items.erase(old_item + 1);
|
||||
} else if (!old_is_dual && new_is_dual) {
|
||||
items.insert(old_item + 1, GetDualInstructionInitialValue(item));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TRDCT_MODIFY_DUAL_ITEM: {
|
||||
std::vector<TraceRestrictItem>::iterator old_item = TraceRestrictProgram::InstructionAt(items, offset);
|
||||
if (!IsTraceRestrictDoubleItem(*old_item)) {
|
||||
return CMD_ERROR;
|
||||
}
|
||||
*(old_item + 1) = p2;
|
||||
break;
|
||||
}
|
||||
|
||||
case TRDCT_REMOVE_ITEM: {
|
||||
TraceRestrictItem old_item = items[offset];
|
||||
TraceRestrictItem old_item = *TraceRestrictProgram::InstructionAt(items, offset);
|
||||
if (IsTraceRestrictConditional(old_item)) {
|
||||
bool remove_whole_block = false;
|
||||
if (GetTraceRestrictCondFlags(old_item) == 0) {
|
||||
@@ -676,7 +743,7 @@ CommandCost CmdProgramSignalTraceRestrict(TileIndex tile, DoCommandFlag flags, u
|
||||
}
|
||||
|
||||
uint32 recursion_depth = 1;
|
||||
std::vector<TraceRestrictItem>::iterator remove_start = items.begin() + offset;
|
||||
std::vector<TraceRestrictItem>::iterator remove_start = TraceRestrictProgram::InstructionAt(items, offset);
|
||||
std::vector<TraceRestrictItem>::iterator remove_end = remove_start + 1;
|
||||
|
||||
// iterate until matching end block found
|
||||
@@ -709,12 +776,22 @@ CommandCost CmdProgramSignalTraceRestrict(TileIndex tile, DoCommandFlag flags, u
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (IsTraceRestrictDoubleItem(current_item)) {
|
||||
// this is a double-item, jump over the next item as well
|
||||
++remove_end;
|
||||
}
|
||||
}
|
||||
if (recursion_depth != 0) return CMD_ERROR; // ran off the end
|
||||
items.erase(remove_start, remove_end);
|
||||
} else {
|
||||
items.erase(items.begin() + offset);
|
||||
std::vector<TraceRestrictItem>::iterator remove_start = TraceRestrictProgram::InstructionAt(items, offset);
|
||||
std::vector<TraceRestrictItem>::iterator remove_end = remove_start + 1;
|
||||
|
||||
if (IsTraceRestrictDoubleItem(old_item)) {
|
||||
// this is a double-item, remove the next item as well
|
||||
++remove_end;
|
||||
}
|
||||
items.erase(remove_start, remove_end);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@@ -216,6 +216,46 @@ struct TraceRestrictProgram : TraceRestrictProgramPool::PoolItem<&_tracerestrict
|
||||
|
||||
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
|
||||
*/
|
||||
@@ -294,6 +334,12 @@ 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
|
||||
@@ -432,14 +478,15 @@ static inline const TraceRestrictProgram *GetExistingTraceRestrictProgram(TileIn
|
||||
* 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_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 = 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
|
||||
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);
|
||||
|
@@ -1109,7 +1109,7 @@ private:
|
||||
int GetItemCount(const TraceRestrictProgram *prog) const
|
||||
{
|
||||
if (prog) {
|
||||
return 2 + prog->items.size();
|
||||
return 2 + prog->GetInstructionCount();
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
@@ -1141,17 +1141,17 @@ private:
|
||||
}
|
||||
|
||||
if (prog) {
|
||||
const std::vector<TraceRestrictItem> &items = prog->items;
|
||||
size_t instruction_count = prog->GetInstructionCount();
|
||||
|
||||
if (static_cast<size_t>(index) == items.size() + 1) {
|
||||
if (static_cast<size_t>(index) == instruction_count + 1) {
|
||||
return MakeSpecialItem(TRNTSV_END);
|
||||
}
|
||||
|
||||
if (static_cast<size_t>(index) > items.size() + 1) {
|
||||
if (static_cast<size_t>(index) > instruction_count + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return items[index - 1];
|
||||
return prog->items[prog->InstructionOffsetToArrayOffset(index - 1)];
|
||||
} else {
|
||||
// No program defined, this is equivalent to an empty program
|
||||
if (index == 1) {
|
||||
@@ -1460,12 +1460,13 @@ private:
|
||||
|
||||
std::vector<TraceRestrictItem> items = prog->items; // copy
|
||||
|
||||
if (offset >= (items.size() + (replace ? 0 : 1))) return false; // off the end of the program
|
||||
if (offset >= (TraceRestrictProgram::GetInstructionCount(items) + (replace ? 0 : 1))) return false; // off the end of the program
|
||||
|
||||
uint array_offset = TraceRestrictProgram::InstructionOffsetToArrayOffset(items, offset);
|
||||
if (replace) {
|
||||
items[offset] = item;
|
||||
items[array_offset] = item;
|
||||
} else {
|
||||
items.insert(items.begin() + offset, item);
|
||||
items.insert(items.begin() + array_offset, item);
|
||||
}
|
||||
|
||||
return TraceRestrictProgram::Validate(items).Succeeded();
|
||||
|
Reference in New Issue
Block a user