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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user