@ -1949,46 +1949,76 @@ CommandCost TraceRestrictProgramRemoveItemAt(std::vector<TraceRestrictItem> &ite
return CommandCost ( ) ;
}
CommandCost TraceRestrictProgramMoveItemAt ( std : : vector < TraceRestrictItem > & items , uint32 & offset , bool up , bool shallow_mode )
static CommandCost AdvanceItemEndIteratorForBlock ( const std : : vector < TraceRestrictItem > & items ,
const std : : vector < TraceRestrictItem > : : iterator & move_start , std : : vector < TraceRestrictItem > : : iterator & move_end , bool allow_elif )
{
std : : vector < TraceRestrictItem > : : iterator move_start = TraceRestrictProgram : : InstructionAt ( items , offset ) ;
std : : vector < TraceRestrictItem > : : iterator move_end = InstructionIteratorNext ( move_start ) ;
TraceRestrictItem old_item = * move_start ;
if ( ! shallow_mode ) {
if ( IsTraceRestrictConditional ( old_item ) ) {
if ( GetTraceRestrictCondFlags ( old_item ) ! = 0 ) {
// can't move or/else blocks
return_cmd_error ( STR_TRACE_RESTRICT_ERROR_CAN_T_MOVE_ITEM ) ;
}
if ( GetTraceRestrictType ( old_item ) = = TRIT_COND_ENDIF ) {
// this is an end if, can't move these
return_cmd_error ( STR_TRACE_RESTRICT_ERROR_CAN_T_MOVE_ITEM ) ;
if ( IsTraceRestrictConditional ( old_item ) ) {
if ( GetTraceRestrictType ( old_item ) = = TRIT_COND_ENDIF ) {
// this is an else or end if, can't move these
return CMD_ERROR ;
}
if ( GetTraceRestrictCondFlags ( old_item ) ! = 0 ) {
if ( allow_elif ) {
uint32 recursion_depth = 0 ;
for ( ; move_end ! = items . end ( ) ; InstructionIteratorAdvance ( move_end ) ) {
TraceRestrictItem current_item = * move_end ;
if ( IsTraceRestrictConditional ( current_item ) ) {
if ( GetTraceRestrictCondFlags ( current_item ) = = 0 ) {
if ( GetTraceRestrictType ( current_item ) = = TRIT_COND_ENDIF ) {
// this is an end if
if ( recursion_depth = = 0 ) break ;
recursion_depth - - ;
} else {
// this is an opening if
recursion_depth + + ;
}
} else if ( recursion_depth = = 0 ) {
// next elif/orif
break ;
}
}
}
return CommandCost ( ) ;
}
// can't move or/else blocks
return CMD_ERROR ;
}
uint32 recursion_depth = 1 ;
// iterate until matching end block found
for ( ; move_end ! = items . end ( ) ; InstructionIteratorAdvance ( move_end ) ) {
TraceRestrictItem current_item = * move_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 ) {
// inclusively remove up to here
InstructionIteratorAdvance ( move_end ) ;
break ;
}
} else {
// this is an opening if
recursion_depth + + ;
uint32 recursion_depth = 1 ;
// iterate until matching end block found
for ( ; move_end ! = items . end ( ) ; InstructionIteratorAdvance ( move_end ) ) {
TraceRestrictItem current_item = * move_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 ) {
// inclusively remove up to here
InstructionIteratorAdvance ( move_end ) ;
break ;
}
} else {
// this is an opening if
recursion_depth + + ;
}
}
}
if ( recursion_depth ! = 0 ) return CMD_ERROR ; // ran off the end
}
if ( recursion_depth ! = 0 ) return CMD_ERROR ; // ran off the end
}
return CommandCost ( ) ;
}
CommandCost TraceRestrictProgramMoveItemAt ( std : : vector < TraceRestrictItem > & items , uint32 & offset , bool up , bool shallow_mode )
{
std : : vector < TraceRestrictItem > : : iterator move_start = TraceRestrictProgram : : InstructionAt ( items , offset ) ;
std : : vector < TraceRestrictItem > : : iterator move_end = InstructionIteratorNext ( move_start ) ;
if ( ! shallow_mode ) {
CommandCost res = AdvanceItemEndIteratorForBlock ( items , move_start , move_end , false ) ;
if ( res . Failed ( ) ) return CommandCost ( STR_TRACE_RESTRICT_ERROR_CAN_T_MOVE_ITEM ) ;
}
if ( up ) {
@ -2003,6 +2033,32 @@ CommandCost TraceRestrictProgramMoveItemAt(std::vector<TraceRestrictItem> &items
return CommandCost ( ) ;
}
CommandCost TraceRestrictProgramDuplicateItemAt ( std : : vector < TraceRestrictItem > & items , uint32 offset )
{
std : : vector < TraceRestrictItem > : : iterator dup_start = TraceRestrictProgram : : InstructionAt ( items , offset ) ;
std : : vector < TraceRestrictItem > : : iterator dup_end = InstructionIteratorNext ( dup_start ) ;
CommandCost res = AdvanceItemEndIteratorForBlock ( items , dup_start , dup_end , true ) ;
if ( res . Failed ( ) ) return CommandCost ( STR_TRACE_RESTRICT_ERROR_CAN_T_DUPLICATE_ITEM ) ;
std : : vector < TraceRestrictItem > new_items ;
new_items . reserve ( items . size ( ) + ( dup_end - dup_start ) ) ;
new_items . insert ( new_items . end ( ) , items . begin ( ) , dup_end ) ;
new_items . insert ( new_items . end ( ) , dup_start , dup_end ) ;
new_items . insert ( new_items . end ( ) , dup_end , items . end ( ) ) ;
items = std : : move ( new_items ) ;
return CommandCost ( ) ;
}
bool TraceRestrictProgramDuplicateItemAtDryRun ( const std : : vector < TraceRestrictItem > & items , uint32 offset )
{
std : : vector < TraceRestrictItem > : : iterator dup_start = TraceRestrictProgram : : InstructionAt ( const_cast < std : : vector < TraceRestrictItem > & > ( items ) , offset ) ;
std : : vector < TraceRestrictItem > : : iterator dup_end = InstructionIteratorNext ( dup_start ) ;
CommandCost res = AdvanceItemEndIteratorForBlock ( items , dup_start , dup_end , true ) ;
return res . Succeeded ( ) ;
}
/**
* The main command for editing a signal tracerestrict program .
* @ param tile The tile which contains the signal .
@ -2103,6 +2159,12 @@ CommandCost CmdProgramSignalTraceRestrict(TileIndex tile, DoCommandFlag flags, u
break ;
}
case TRDCT_DUPLICATE_ITEM : {
CommandCost res = TraceRestrictProgramDuplicateItemAt ( items , offset ) ;
if ( res . Failed ( ) ) return res ;
break ;
}
default :
return CMD_ERROR ;
}