@ -21,6 +21,7 @@
# include "group.h"
# include "pathfinder/yapf/yapf_cache.h"
# include <vector>
# include <algorithm>
/** @file
*
@ -844,13 +845,152 @@ static uint32 GetDualInstructionInitialValue(TraceRestrictItem item)
}
}
template < typename T > T InstructionIteratorNext ( T iter )
{
return IsTraceRestrictDoubleItem ( * iter ) ? iter + 2 : iter + 1 ;
}
template < typename T > void InstructionIteratorAdvance ( T & iter )
{
iter = InstructionIteratorNext ( iter ) ;
}
CommandCost TraceRestrictProgramRemoveItemAt ( std : : vector < TraceRestrictItem > & items , uint32 offset , bool shallow_mode )
{
TraceRestrictItem old_item = * TraceRestrictProgram : : InstructionAt ( items , offset ) ;
if ( IsTraceRestrictConditional ( old_item ) & & GetTraceRestrictCondFlags ( old_item ) ! = TRCF_OR ) {
bool remove_whole_block = false ;
if ( GetTraceRestrictCondFlags ( old_item ) = = 0 ) {
if ( GetTraceRestrictType ( old_item ) = = TRIT_COND_ENDIF ) {
// this is an end if, can't remove these
return_cmd_error ( STR_TRACE_RESTRICT_ERROR_CAN_T_REMOVE_ENDIF ) ;
} else {
// this is an opening if
remove_whole_block = true ;
}
}
uint32 recursion_depth = 1 ;
std : : vector < TraceRestrictItem > : : iterator remove_start = TraceRestrictProgram : : InstructionAt ( items , offset ) ;
std : : vector < TraceRestrictItem > : : iterator remove_end = InstructionIteratorNext ( remove_start ) ;
// iterate until matching end block found
for ( ; remove_end ! = items . end ( ) ; InstructionIteratorAdvance ( remove_end ) ) {
TraceRestrictItem current_item = * remove_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 ) {
if ( remove_whole_block ) {
if ( shallow_mode ) {
// must erase endif first, as it is later in the vector
items . erase ( remove_end , InstructionIteratorNext ( remove_end ) ) ;
} else {
// inclusively remove up to here
InstructionIteratorAdvance ( remove_end ) ;
}
break ;
} else {
// exclusively remove up to here
break ;
}
}
} else {
// this is an opening if
recursion_depth + + ;
}
} else {
// this is an else/or type block
if ( recursion_depth = = 1 & & ! remove_whole_block ) {
// exclusively remove up to here
recursion_depth = 0 ;
break ;
}
if ( recursion_depth = = 1 & & remove_whole_block & & shallow_mode ) {
// shallow-removing whole if block, and it contains an else/or if, bail out
return_cmd_error ( STR_TRACE_RESTRICT_ERROR_CAN_T_SHALLOW_REMOVE_IF_ELIF ) ;
}
}
}
}
if ( recursion_depth ! = 0 ) return CMD_ERROR ; // ran off the end
if ( shallow_mode ) {
items . erase ( remove_start , InstructionIteratorNext ( remove_start ) ) ;
} else {
items . erase ( remove_start , remove_end ) ;
}
} else {
std : : vector < TraceRestrictItem > : : iterator remove_start = TraceRestrictProgram : : InstructionAt ( items , offset ) ;
std : : vector < TraceRestrictItem > : : iterator remove_end = InstructionIteratorNext ( remove_start ) ;
items . erase ( remove_start , remove_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 ) ;
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 ) ;
}
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 ( up ) {
if ( move_start = = items . begin ( ) ) return_cmd_error ( STR_TRACE_RESTRICT_ERROR_CAN_T_MOVE_ITEM ) ;
std : : rotate ( TraceRestrictProgram : : InstructionAt ( items , offset - 1 ) , move_start , move_end ) ;
offset - - ;
} else {
if ( move_end = = items . end ( ) ) return_cmd_error ( STR_TRACE_RESTRICT_ERROR_CAN_T_MOVE_ITEM ) ;
std : : rotate ( move_start , move_end , InstructionIteratorNext ( move_end ) ) ;
offset + + ;
}
return CommandCost ( ) ;
}
/**
* The main command for editing a signal tracerestrict program .
* @ param tile The tile which contains the signal .
* @ param flags Internal command handler stuff .
* Below apply for instruction modification actions only
* @ param p1 Bitstuffed items
* @ param p2 Item , for insert and modify operations
* @ param p2 Item , for insert and modify operations . Flags for instruction move operations
* @ return the cost of this operation ( which is free ) , or an error
*/
CommandCost CmdProgramSignalTraceRestrict ( TileIndex tile , DoCommandFlag flags , uint32 p1 , uint32 p2 , const char * text )
@ -928,71 +1068,16 @@ CommandCost CmdProgramSignalTraceRestrict(TileIndex tile, DoCommandFlag flags, u
break ;
}
case TRDCT_REMOVE_ITEM : {
TraceRestrictItem old_item = * TraceRestrictProgram : : InstructionAt ( items , offset ) ;
if ( IsTraceRestrictConditional ( old_item ) & & GetTraceRestrictCondFlags ( old_item ) ! = TRCF_OR ) {
bool remove_whole_block = false ;
if ( GetTraceRestrictCondFlags ( old_item ) = = 0 ) {
if ( GetTraceRestrictType ( old_item ) = = TRIT_COND_ENDIF ) {
// this is an end if, can't remove these
return_cmd_error ( STR_TRACE_RESTRICT_ERROR_CAN_T_REMOVE_ENDIF ) ;
} else {
// this is an opening if
remove_whole_block = true ;
}
}
uint32 recursion_depth = 1 ;
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
for ( ; remove_end ! = items . end ( ) ; + + remove_end ) {
TraceRestrictItem current_item = * remove_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 ) {
if ( remove_whole_block ) {
// inclusively remove up to here
+ + remove_end ;
break ;
} else {
// exclusively remove up to here
break ;
}
}
} else {
// this is an opening if
recursion_depth + + ;
}
} else {
// this is an else/or type block
if ( recursion_depth = = 1 & & ! remove_whole_block ) {
// exclusively remove up to here
recursion_depth = 0 ;
case TRDCT_REMOVE_ITEM :
case TRDCT_SHALLOW_REMOVE_ITEM : {
CommandCost res = TraceRestrictProgramRemoveItemAt ( items , offset , type = = TRDCT_SHALLOW_REMOVE_ITEM ) ;
if ( res . Failed ( ) ) return res ;
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 {
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 ) ;
}
case TRDCT_MOVE_ITEM : {
CommandCost res = TraceRestrictProgramMoveItemAt ( items , offset , p2 & 1 , p2 & 2 ) ;
if ( res . Failed ( ) ) return res ;
break ;
}