Initial support for multi-item instructions.

This involves various changes to instruction modification actions,
and the GUI code.
This commit is contained in:
Jonathan G Rennison
2015-07-28 00:56:19 +01:00
parent 2c5bfc5486
commit 116bd41101
3 changed files with 148 additions and 23 deletions

View File

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