abstract class TweakAIActionRecord
{

	public static function GetFriendlyName( record : TweakDBID, const nodeName : ref< String > ) : String
	{
		var actionName : String;
		if( IsFinal() )
		{
			actionName = "NoStringDebugInFinal =(";
		}
		else if( GetDebugActionNameFromRecord( record, actionName ) )
		{
			return ( ( ( "Archetype" + nodeName ) + ":  ''" ) + actionName ) + "'' ";
		}
		return ( ( nodeName + ":  ''" ) + actionName ) + "'' ";
	}

	public static function GetDebugActionNameFromRecord( record : TweakDBID, debugStringName : ref< String > ) : Bool
	{
		var actionName : TweakDBID;
		if( AIScriptUtils.GetActionNameFromRecord( record, actionName ) )
		{
			debugStringName = TDBID.ToStringDEBUG( actionName );
			return true;
		}
		debugStringName = TDBID.ToStringDEBUG( record );
		return false;
	}

	public static function GetHeldItemType( const context : ScriptExecutionContext, out heldItemType : gamedataItemType ) : Bool
	{
		var item : weak< ItemObject >;
		var ts : TransactionSystem;
		var owner : gamePuppet;
		owner = ScriptExecutionContext.GetOwner( context );
		ts = GameInstance.GetTransactionSystem( owner.GetGame() );
		if( !( ts ) )
		{
			return false;
		}
		item = ts.GetItemInSlot( owner, T"AttachmentSlots.WeaponRight" );
		if( !( item ) )
		{
			item = ts.GetItemInSlot( owner, T"AttachmentSlots.WeaponLeft" );
		}
		if( !( item ) )
		{
			return false;
		}
		heldItemType = item.GetItemData().GetItemType();
		return true;
	}

	public static function IsArchetypeAction( record : TweakDBID ) : Bool
	{
		return AIScriptUtils.IsArchetypeAction( record );
	}

	public static function GetActionRecord( const context : ScriptExecutionContext, actionID : TweakDBID, actionDebugName : ref< String >, out actionRecord : weak< AIAction_Record > ) : Bool
	{
		var record : AIRecord_Record;
		if( !( ScriptExecutionContext.GetOverriddenNode( context, actionID, record, true ) ) )
		{
			return false;
		}
		if( record )
		{
			actionID = record.GetID();
		}
		if( !( IsFinal() ) )
		{
			actionDebugName = TDBID.ToStringDEBUG( actionID );
		}
		actionRecord = ( ( AIAction_Record )( record ) );
		return actionRecord != NULL;
	}

	public static function GetSelectorRecord( const context : ScriptExecutionContext, selectorID : TweakDBID, selectorDebugName : ref< String >, out selectorRecord : weak< AIActionSelector_Record > ) : Bool
	{
		var record : AIRecord_Record;
		if( !( ScriptExecutionContext.GetOverriddenNode( context, selectorID, record, true ) ) )
		{
			return false;
		}
		selectorID = record.GetID();
		if( !( IsFinal() ) )
		{
			selectorDebugName = TDBID.ToStringDEBUG( selectorID );
		}
		selectorRecord = ( ( AIActionSelector_Record )( record ) );
		return selectorRecord != NULL;
	}

	public static function GetSequenceRecord( const context : ScriptExecutionContext, sequenceID : TweakDBID, sequenceDebugName : ref< String >, out sequenceRecord : weak< AIActionSequence_Record > ) : Bool
	{
		var record : AIRecord_Record;
		if( !( ScriptExecutionContext.GetOverriddenNode( context, sequenceID, record, true ) ) )
		{
			return false;
		}
		sequenceID = record.GetID();
		if( !( IsFinal() ) )
		{
			sequenceDebugName = TDBID.ToStringDEBUG( sequenceID );
		}
		sequenceRecord = ( ( AIActionSequence_Record )( record ) );
		return sequenceRecord != NULL;
	}

	public static function GetSmartCompositeRecord( const context : ScriptExecutionContext, smartCompositeID : TweakDBID, smartCompositeDebugName : ref< String >, out smartCompositeRecord : weak< AIActionSmartComposite_Record > ) : Bool
	{
		var record : AIRecord_Record;
		if( !( ScriptExecutionContext.GetOverriddenNode( context, smartCompositeID, record, true ) ) )
		{
			return false;
		}
		smartCompositeID = record.GetID();
		if( !( IsFinal() ) )
		{
			smartCompositeDebugName = TDBID.ToStringDEBUG( smartCompositeID );
		}
		smartCompositeRecord = ( ( AIActionSmartComposite_Record )( record ) );
		return smartCompositeRecord != NULL;
	}

	public static function GetActionRecordFromSelector( const context : ScriptExecutionContext, selectorRecord : weak< AIActionSelector_Record >, actionDebugName : ref< String >, out actionRecord : weak< AIAction_Record >, out nodeIterator : Int32, out shouldCallAgain : Bool ) : Bool
	{
		var count : Int32;
		var limitCount : Uint32;
		var alternativesLimitEnabled : Bool;
		var alternativesLimit : Uint32;
		var player : PlayerPuppet;
		var playerInCombat : Bool;
		var blackBoard : IBlackboard;
		limitCount = 0;
		if( !( selectorRecord ) )
		{
			return false;
		}
		player = GetPlayer( ScriptExecutionContext.GetOwner( context ).GetGame() );
		if( player )
		{
			playerInCombat = player.IsInCombat();
		}
		alternativesLimitEnabled = ScriptExecutionContext.GetTweakActionSystem( context ).IsTweakCompositeAlternativesLimitEnabled( context, playerInCombat );
		alternativesLimit = ScriptExecutionContext.GetTweakActionSystem( context ).GetTweakCompositeAlternativesLimit( context );
		count = selectorRecord.GetActionsCount();
		if( nodeIterator >= count )
		{
			nodeIterator = 0;
		}
		while( nodeIterator < count )
		{
			if( ( !( selectorRecord.DisableActionsLimit() ) && alternativesLimitEnabled ) && ( limitCount >= alternativesLimit ) )
			{
				shouldCallAgain = true;
				return false;
			}
			actionRecord = selectorRecord.GetActionsItem( nodeIterator );
			if( !( actionRecord ) )
			{
				nodeIterator += 1;
				limitCount += ( ( Uint32 )( 1 ) );
				continue;
			}
			if( !( TweakAIActionRecord.GetActionRecord( context, actionRecord.GetID(), actionDebugName, actionRecord ) ) )
			{
				return false;
			}
			if( ( ( AISubActionRandomize_Record )( actionRecord.AnimData().AnimVariationSubAction() ) ) )
			{
				blackBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
				if( ( ( TweakDBID )( blackBoard.GetVariant( GetAllBlackboardDefs().AIAction.ownerLastAnimVariationAction ) ) ) != actionRecord.GetID() )
				{
					blackBoard.SetVariant( GetAllBlackboardDefs().AIAction.ownerLastAnimVariationAction, TDBID.None() );
					blackBoard.SetBool( GetAllBlackboardDefs().AIAction.ownerCurrentAnimVariationSet, false );
				}
				if( AICondition.ActivationCheck( context, actionRecord ) )
				{
					blackBoard.SetVariant( GetAllBlackboardDefs().AIAction.ownerLastAnimVariationAction, actionRecord.GetID() );
					return true;
				}
			}
			else if( AICondition.ActivationCheck( context, actionRecord ) )
			{
				return true;
			}
			nodeIterator += 1;
			limitCount += ( ( Uint32 )( 1 ) );
		}
		actionRecord = selectorRecord.DefaultAction();
		if( actionRecord )
		{
			nodeIterator = -1;
			if( !( TweakAIActionRecord.GetActionRecord( context, actionRecord.GetID(), actionDebugName, actionRecord ) ) )
			{
				return false;
			}
			return true;
		}
		return false;
	}

	public static function IsThisLastActionInSelector( selectorRecord : weak< AIActionSelector_Record >, const nodeIterator : Int32 ) : Bool
	{
		var count : Int32;
		if( !( selectorRecord ) )
		{
			return false;
		}
		if( nodeIterator < 0 )
		{
			return true;
		}
		count = selectorRecord.GetActionsCount();
		return nodeIterator >= ( count - 1 );
	}

	public static function GetActionRecordFromSequence( const context : ScriptExecutionContext, sequenceRecord : weak< AIActionSequence_Record >, actionDebugName : ref< String >, out actionRecord : weak< AIAction_Record >, out sequenceIterator : Int32, out shouldCallAgain : Bool ) : Bool
	{
		var count : Int32;
		var limitCount : Uint32;
		var alternativesLimitEnabled : Bool;
		var alternativesLimit : Uint32;
		var player : PlayerPuppet;
		var playerInCombat : Bool;
		var blackBoard : IBlackboard;
		limitCount = 0;
		if( !( sequenceRecord ) )
		{
			return false;
		}
		player = GetPlayer( ScriptExecutionContext.GetOwner( context ).GetGame() );
		if( player )
		{
			playerInCombat = player.IsInCombat();
		}
		alternativesLimitEnabled = ScriptExecutionContext.GetTweakActionSystem( context ).IsTweakCompositeAlternativesLimitEnabled( context, playerInCombat );
		alternativesLimit = ScriptExecutionContext.GetTweakActionSystem( context ).GetTweakCompositeAlternativesLimit( context );
		count = sequenceRecord.GetActionsCount();
		if( sequenceIterator >= count )
		{
			sequenceIterator = 0;
		}
		while( sequenceIterator < count )
		{
			if( ( !( sequenceRecord.DisableActionsLimit() ) && alternativesLimitEnabled ) && ( limitCount >= alternativesLimit ) )
			{
				shouldCallAgain = true;
				return false;
			}
			actionRecord = sequenceRecord.GetActionsItem( sequenceIterator );
			if( !( actionRecord ) )
			{
				sequenceIterator += 1;
				limitCount += ( ( Uint32 )( 1 ) );
				continue;
			}
			if( !( TweakAIActionRecord.GetActionRecord( context, actionRecord.GetID(), actionDebugName, actionRecord ) ) )
			{
				return false;
			}
			if( ( ( AISubActionRandomize_Record )( actionRecord.AnimData().AnimVariationSubAction() ) ) )
			{
				blackBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
				if( ( ( TweakDBID )( blackBoard.GetVariant( GetAllBlackboardDefs().AIAction.ownerLastAnimVariationAction ) ) ) != actionRecord.GetID() )
				{
					blackBoard.SetVariant( GetAllBlackboardDefs().AIAction.ownerLastAnimVariationAction, TDBID.None() );
					blackBoard.SetBool( GetAllBlackboardDefs().AIAction.ownerCurrentAnimVariationSet, false );
				}
				if( AICondition.ActivationCheck( context, actionRecord ) )
				{
					blackBoard.SetVariant( GetAllBlackboardDefs().AIAction.ownerLastAnimVariationAction, actionRecord.GetID() );
					return true;
				}
			}
			else if( AICondition.ActivationCheck( context, actionRecord ) )
			{
				return true;
			}
			sequenceIterator += 1;
			limitCount += ( ( Uint32 )( 1 ) );
		}
		actionRecord = NULL;
		return false;
	}

	public static function IsThisLastActionInSequence( sequenceRecord : weak< AIActionSequence_Record >, const sequenceIterator : Int32 ) : Bool
	{
		var count : Int32;
		if( !( sequenceRecord ) )
		{
			return false;
		}
		count = sequenceRecord.GetActionsCount();
		return sequenceIterator >= ( count - 1 );
	}

	public static function IsThisLastActionInSmartComposite( smartCompositeRecord : weak< AIActionSmartComposite_Record >, const iterator : Int32 ) : Bool
	{
		var count : Int32;
		if( !( smartCompositeRecord ) )
		{
			return false;
		}
		count = smartCompositeRecord.GetNodesCount();
		return iterator >= ( count - 1 );
	}

	public static function IsSmartCompositeASequence( smartCompositeRecord : weak< AIActionSmartComposite_Record > ) : Bool
	{
		var type : gamedataAISmartCompositeType;
		type = gamedataAISmartCompositeType.Invalid;
		type = smartCompositeRecord.Type().Type();
		if( type == gamedataAISmartCompositeType.Sequence )
		{
			return true;
		}
		if( type == gamedataAISmartCompositeType.SequenceWithMemory )
		{
			return true;
		}
		if( type == gamedataAISmartCompositeType.SequenceWithSmartMemory )
		{
			return true;
		}
		return false;
	}

	public static function IsSmartCompositeASelector( smartCompositeRecord : weak< AIActionSmartComposite_Record > ) : Bool
	{
		var type : gamedataAISmartCompositeType;
		type = gamedataAISmartCompositeType.Invalid;
		type = smartCompositeRecord.Type().Type();
		if( type == gamedataAISmartCompositeType.Selector )
		{
			return true;
		}
		if( type == gamedataAISmartCompositeType.SelectorWithMemory )
		{
			return true;
		}
		if( type == gamedataAISmartCompositeType.SelectorWithSmartMemory )
		{
			return true;
		}
		return false;
	}

}

class TweakAIAction extends TweakAIActionAbstract
{
	[ customEditor = "TweakDBGroupInheritance;AIAction" ]
	editable var m_record : TweakDBID;

	public override function GetDescription( context : ScriptExecutionContext ) : String
	{
		var result : String;
		result = super.GetDescription( context );
		if( result == "" )
		{
			return TDBID.ToStringDEBUG( m_record );
		}
		return result;
	}

	private override function GetActionRecord( const context : ScriptExecutionContext, actionDebugName : ref< String >, out actionRecord : weak< AIAction_Record >, out shouldCallAgain : Bool ) : Bool
	{
		return TweakAIActionRecord.GetActionRecord( context, m_record, actionDebugName, actionRecord );
	}

	private override function Debug_GetBaseActionId() : TweakDBID
	{
		return m_record;
	}

	public export function GetFriendlyName() : String
	{
		if( TweakDBInterface.GetAIActionRecord( m_record ) )
		{
			return TweakAIActionRecord.GetFriendlyName( m_record, "Action" );
		}
		else
		{
			return TweakAIActionRecord.GetFriendlyName( m_record, " [INVALID] Action" );
		}
	}

}

class TweakAIActionCondition extends TweakAIActionConditionAbstract
{
	[ customEditor = "TweakDBGroupInheritance;AIAction" ]
	editable var m_record : TweakDBID;

	public override function GetDescription( context : ScriptExecutionContext ) : String
	{
		var result : String;
		result = super.GetDescription( context );
		if( result == "" )
		{
			return TDBID.ToStringDEBUG( m_record );
		}
		return result;
	}

	private override function GetActionRecord( const context : ScriptExecutionContext, actionDebugName : ref< String >, out actionRecord : weak< AIAction_Record > ) : Bool
	{
		return TweakAIActionRecord.GetActionRecord( context, m_record, actionDebugName, actionRecord );
	}

	public function GetFriendlyName() : String
	{
		if( TweakDBInterface.GetAIActionRecord( m_record ) )
		{
			return TweakAIActionRecord.GetFriendlyName( m_record, "Condition" );
		}
		else
		{
			return TweakAIActionRecord.GetFriendlyName( m_record, " [INVALID] Condition" );
		}
	}

}

class TweakAIActionSelector extends TweakAIActionAbstract
{
	[ customEditor = "TweakDBGroupInheritance;AIActionSelector" ]
	editable var m_selector : TweakDBID;
	var m_selectorRecord : weak< AIActionSelector_Record >;
	var m_nodeIterator : Int32;

	private override function GetActionRecord( const context : ScriptExecutionContext, actionDebugName : ref< String >, out actionRecord : weak< AIAction_Record >, out shouldCallAgain : Bool ) : Bool
	{
		var selectorRecord : weak< AIActionSelector_Record >;
		if( !( TweakAIActionRecord.GetSelectorRecord( context, m_selector, actionDebugName, selectorRecord ) ) )
		{
			return false;
		}
		if( selectorRecord != m_selectorRecord )
		{
			m_nodeIterator = 0;
			m_selectorRecord = selectorRecord;
		}
		return TweakAIActionRecord.GetActionRecordFromSelector( context, m_selectorRecord, actionDebugName, actionRecord, m_nodeIterator, shouldCallAgain );
	}

	private override function Debug_GetBaseActionId() : TweakDBID
	{
		var selectorRecord : AIActionSelector_Record;
		var actionRecord : AIAction_Record;
		selectorRecord = m_selectorRecord;
		if( !( selectorRecord ) )
		{
			return T"";
		}
		if( m_nodeIterator < 0 )
		{
			actionRecord = selectorRecord.DefaultAction();
		}
		else if( m_nodeIterator < selectorRecord.GetActionsCount() )
		{
			actionRecord = selectorRecord.GetActionsItem( m_nodeIterator );
		}
		else
		{
			actionRecord = NULL;
		}
		if( !( actionRecord ) )
		{
			return T"";
		}
		return actionRecord.GetID();
	}

	private override function Debug_GetCompositeId() : TweakDBID
	{
		return m_selector;
	}

	public export function GetFriendlyName() : String
	{
		if( TweakDBInterface.GetAIActionSelectorRecord( m_selector ) )
		{
			return TweakAIActionRecord.GetFriendlyName( m_selector, "Selector" );
		}
		else
		{
			return TweakAIActionRecord.GetFriendlyName( m_selector, " [INVALID] Selector" );
		}
	}

	private export override function Update( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome
	{
		var result : AIbehaviorUpdateOutcome;
		if( !( RetryGetActionRecord( context ) ) )
		{
			return AIbehaviorUpdateOutcome.IN_PROGRESS;
		}
		switch( super.Update( context ) )
		{
			case AIbehaviorUpdateOutcome.FAILURE:
			{
				result = RunNextAction( context );
				if( result == AIbehaviorUpdateOutcome.SUCCESS )
				{
					return AIbehaviorUpdateOutcome.IN_PROGRESS;
				}
				return result;
			}
			case AIbehaviorUpdateOutcome.SUCCESS:
			{
				return AIbehaviorUpdateOutcome.SUCCESS;
			}
			default:
				break;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	private export override function Deactivate( context : ScriptExecutionContext )
	{
		super.Deactivate( context );
		m_nodeIterator = 0;
	}

	private final function RunNextAction( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome
	{
		if( TweakAIActionRecord.IsThisLastActionInSelector( m_selectorRecord, m_nodeIterator ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		m_nodeIterator += 1;
		super.Deactivate( context );
		super.Activate( context );
		if( VerifyActionRecord() )
		{
			return super.Update( context );
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

}

class TweakAIActionSequence extends TweakAIActionAbstract
{
	[ customEditor = "TweakDBGroupInheritance;AIActionSequence" ]
	editable var m_sequence : TweakDBID;
	private var m_sequenceRecord : weak< AIActionSequence_Record >;
	private var m_sequenceIterator : Int32;

	private override function GetActionRecord( const context : ScriptExecutionContext, actionDebugName : ref< String >, out actionRecord : weak< AIAction_Record >, out shouldCallAgain : Bool ) : Bool
	{
		var sequenceRecord : weak< AIActionSequence_Record >;
		if( !( TweakAIActionRecord.GetSequenceRecord( context, m_sequence, actionDebugName, sequenceRecord ) ) )
		{
			ResetSequence();
			return false;
		}
		if( sequenceRecord != m_sequenceRecord )
		{
			ResetSequence();
			m_sequenceRecord = sequenceRecord;
		}
		return TweakAIActionRecord.GetActionRecordFromSequence( context, m_sequenceRecord, actionDebugName, actionRecord, m_sequenceIterator, shouldCallAgain );
	}

	private override function Debug_GetBaseActionId() : TweakDBID
	{
		return m_sequence;
	}

	private override function Debug_GetCompositeId() : TweakDBID
	{
		return m_sequence;
	}

	public export function GetFriendlyName() : String
	{
		if( TweakDBInterface.GetAIActionSequenceRecord( m_sequence ) )
		{
			return TweakAIActionRecord.GetFriendlyName( m_sequence, "Sequence" );
		}
		else
		{
			return TweakAIActionRecord.GetFriendlyName( m_sequence, " [INVALID] Sequence" );
		}
	}

	private export override function Update( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome
	{
		var result : AIbehaviorUpdateOutcome;
		if( !( RetryGetActionRecord( context ) ) )
		{
			return AIbehaviorUpdateOutcome.IN_PROGRESS;
		}
		switch( super.Update( context ) )
		{
			case AIbehaviorUpdateOutcome.FAILURE:
				ResetSequence();
			return AIbehaviorUpdateOutcome.FAILURE;
			case AIbehaviorUpdateOutcome.SUCCESS:
				result = RunNextAction( context );
			if( result == AIbehaviorUpdateOutcome.FAILURE )
			{
				return AIbehaviorUpdateOutcome.IN_PROGRESS;
			}
			return result;
			default:
				break;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	private export override function Deactivate( context : ScriptExecutionContext )
	{
		super.Deactivate( context );
		if( !( m_sequenceRecord ) || !( m_sequenceRecord.HasMemory() ) )
		{
			ResetSequence();
		}
	}

	private final function ResetSequence()
	{
		m_sequenceIterator = 0;
	}

	private final function RunNextAction( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome
	{
		if( TweakAIActionRecord.IsThisLastActionInSequence( m_sequenceRecord, m_sequenceIterator ) )
		{
			ResetSequence();
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		m_sequenceIterator += 1;
		super.Deactivate( context );
		super.Activate( context );
		if( VerifyActionRecord() )
		{
			return super.Update( context );
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

}

enum ETweakAINodeType
{
	Action = 0,
	Selector = 1,
	Sequence = 2,
}

class TweakAIActionSmartComposite extends TweakAIActionAbstract
{
	[ customEditor = "TweakDBGroupInheritance;AIActionSmartComposite" ]
	editable var m_smartComposite : TweakDBID;
	private var m_smartCompositeRecord : weak< AIActionSmartComposite_Record >;
	private var m_interruptionRequested : Bool;
	private var m_conditionSuccessfulCheckTimeStamp : Float;
	private var m_conditionCheckTimeStamp : Float;
	private var m_iteration : Uint32;
	private var m_nodeIterator : Int32;
	private var m_currentNodeIterator : Int32;
	private var m_currentNodeType : ETweakAINodeType;
	private var m_currentNode : weak< AINode_Record >;

	private final function ResetComposite()
	{
		ResetNodeIterator();
		m_interruptionRequested = false;
		m_gracefullyInterrupted = false;
		m_iteration = 0;
		m_conditionSuccessfulCheckTimeStamp = 0.0;
		m_currentNode = NULL;
	}

	public virtual function GetSmartCompositeRecord( const context : ScriptExecutionContext, smartCompositeID : TweakDBID, smartCompositeStringName : ref< String >, out smartCompositeRecord : weak< AIActionSmartComposite_Record > ) : Bool
	{
		return TweakAIActionRecord.GetSmartCompositeRecord( context, smartCompositeID, smartCompositeStringName, smartCompositeRecord );
	}

	private override function GetActionRecord( const context : ScriptExecutionContext, actionDebugName : ref< String >, out actionRecord : weak< AIAction_Record >, out shouldCallAgain : Bool ) : Bool
	{
		var nodeCount : Int32;
		var selectorRecord : weak< AIActionSelector_Record >;
		var sequenceRecord : weak< AIActionSequence_Record >;
		var smartCompositeRecord : weak< AIActionSmartComposite_Record >;
		var debugName : String;
		var limitCounter : Uint32;
		var tempBool : Bool;
		var alternativesLimitEnabled : Bool;
		var alternativesLimit : Uint32;
		var owner : gamePuppet;
		var player : PlayerPuppet;
		var playerInCombat : Bool;
		var blackBoard : IBlackboard;
		limitCounter = 0;
		tempBool = false;
		if( !( GetSmartCompositeRecord( context, m_smartComposite, actionDebugName, smartCompositeRecord ) ) )
		{
			return false;
		}
		else
		{
			RandomizeGracefulInterruptionConditionCheckInterval( smartCompositeRecord );
		}
		owner = ScriptExecutionContext.GetOwner( context );
		player = GetPlayer( ScriptExecutionContext.GetOwner( context ).GetGame() );
		if( player )
		{
			playerInCombat = player.IsInCombat();
		}
		alternativesLimitEnabled = ScriptExecutionContext.GetTweakActionSystem( context ).IsTweakCompositeAlternativesLimitEnabled( context, playerInCombat );
		alternativesLimit = ScriptExecutionContext.GetTweakActionSystem( context ).GetTweakCompositeAlternativesLimit( context );
		if( smartCompositeRecord != m_smartCompositeRecord )
		{
			m_smartCompositeRecord = smartCompositeRecord;
			ResetComposite();
		}
		nodeCount = m_smartCompositeRecord.GetNodesCount();
		if( nodeCount == 0 )
		{
			return false;
		}
		while( m_nodeIterator < nodeCount )
		{
			if( ( !( smartCompositeRecord.DisableActionsLimit() ) && alternativesLimitEnabled ) && ( limitCounter >= alternativesLimit ) )
			{
				shouldCallAgain = true;
				return false;
			}
			m_currentNode = m_smartCompositeRecord.GetNodesItem( m_nodeIterator );
			actionRecord = ( ( AIAction_Record )( m_currentNode ) );
			if( actionRecord )
			{
				if( !( TweakAIActionRecord.GetActionRecord( context, actionRecord.GetID(), actionDebugName, actionRecord ) ) )
				{
					return false;
				}
				m_currentNodeType = ETweakAINodeType.Action;
				if( ( ( AISubActionRandomize_Record )( actionRecord.AnimData().AnimVariationSubAction() ) ) )
				{
					blackBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
					if( ( ( TweakDBID )( blackBoard.GetVariant( GetAllBlackboardDefs().AIAction.ownerLastAnimVariationAction ) ) ) != actionRecord.GetID() )
					{
						blackBoard.SetVariant( GetAllBlackboardDefs().AIAction.ownerLastAnimVariationAction, TDBID.None() );
						blackBoard.SetBool( GetAllBlackboardDefs().AIAction.ownerCurrentAnimVariationSet, false );
					}
					if( AICondition.ActivationCheck( context, actionRecord ) )
					{
						blackBoard.SetVariant( GetAllBlackboardDefs().AIAction.ownerLastAnimVariationAction, actionRecord.GetID() );
						return true;
					}
				}
				else if( AICondition.ActivationCheck( context, actionRecord ) )
				{
					return true;
				}
				else
				{
					IncrementNodeIterator();
					limitCounter += ( ( Uint32 )( 1 ) );
					continue;
				}
				return false;
			}
			if( !( IsFinal() ) )
			{
				debugName = TDBID.ToStringDEBUG( m_smartCompositeRecord.GetID() );
				if( AIActionHelper.ActionDebugHelper( "", owner, debugName ) )
				{
				}
			}
			selectorRecord = ( ( AIActionSelector_Record )( m_currentNode ) );
			if( selectorRecord )
			{
				if( !( TweakAIActionRecord.GetSelectorRecord( context, selectorRecord.GetID(), actionDebugName, selectorRecord ) ) )
				{
					return false;
				}
				if( !( IsFinal() ) )
				{
					debugName = TDBID.ToStringDEBUG( selectorRecord.GetID() );
					if( AIActionHelper.ActionDebugHelper( "", owner, debugName ) )
					{
					}
				}
				if( !( selectorRecord.ActivationCondition() ) || AICondition.CheckActionCondition( context, selectorRecord.ActivationCondition() ) )
				{
					m_currentNodeType = ETweakAINodeType.Selector;
					tempBool = TweakAIActionRecord.GetActionRecordFromSelector( context, selectorRecord, actionDebugName, actionRecord, m_currentNodeIterator, shouldCallAgain );
					if( shouldCallAgain )
					{
						return false;
					}
					if( !( tempBool ) )
					{
						if( TweakAIActionRecord.IsSmartCompositeASelector( m_smartCompositeRecord ) )
						{
							IncrementNodeIterator();
							limitCounter += ( ( Uint32 )( 1 ) );
							continue;
						}
						return false;
					}
				}
				else
				{
					if( m_smartCompositeRecord.FailOnNodeActivationConditionFailure() || selectorRecord.FailOnNodeActivationConditionFailure() )
					{
						return false;
					}
					IncrementNodeIterator();
					limitCounter += ( ( Uint32 )( 1 ) );
					continue;
				}
			}
			sequenceRecord = ( ( AIActionSequence_Record )( m_currentNode ) );
			if( sequenceRecord )
			{
				if( !( TweakAIActionRecord.GetSequenceRecord( context, sequenceRecord.GetID(), actionDebugName, sequenceRecord ) ) )
				{
					return false;
				}
				if( !( IsFinal() ) )
				{
					debugName = TDBID.ToStringDEBUG( sequenceRecord.GetID() );
					if( AIActionHelper.ActionDebugHelper( "", owner, debugName ) )
					{
					}
					if( AIActionHelper.ActionDebugHelper( owner, debugName ) )
					{
					}
				}
				if( m_currentNodeType == ETweakAINodeType.Sequence && ( m_currentNodeIterator > 0 ) )
				{
					tempBool = TweakAIActionRecord.GetActionRecordFromSequence( context, sequenceRecord, actionDebugName, actionRecord, m_currentNodeIterator, shouldCallAgain );
					if( shouldCallAgain )
					{
						return false;
					}
					if( !( tempBool ) )
					{
						if( TweakAIActionRecord.IsSmartCompositeASequence( m_smartCompositeRecord ) )
						{
							IncrementNodeIterator();
							limitCounter += ( ( Uint32 )( 1 ) );
							continue;
						}
						return false;
					}
				}
				else if( !( sequenceRecord.ActivationCondition() ) || AICondition.CheckActionCondition( context, sequenceRecord.ActivationCondition() ) )
				{
					m_currentNodeType = ETweakAINodeType.Sequence;
					tempBool = TweakAIActionRecord.GetActionRecordFromSequence( context, sequenceRecord, actionDebugName, actionRecord, m_currentNodeIterator, shouldCallAgain );
					if( shouldCallAgain )
					{
						return false;
					}
					if( !( tempBool ) )
					{
						if( TweakAIActionRecord.IsSmartCompositeASelector( m_smartCompositeRecord ) )
						{
							IncrementNodeIterator();
							limitCounter += ( ( Uint32 )( 1 ) );
							continue;
						}
						return false;
					}
				}
				else
				{
					if( m_smartCompositeRecord.FailOnNodeActivationConditionFailure() || sequenceRecord.FailOnNodeActivationConditionFailure() )
					{
						return false;
					}
					IncrementNodeIterator();
					limitCounter += ( ( Uint32 )( 1 ) );
					continue;
				}
			}
			return actionRecord != NULL;
		}
		return false;
	}

	private override function Debug_GetBaseActionId() : TweakDBID
	{
		return m_smartComposite;
	}

	private override function Debug_GetCompositeId() : TweakDBID
	{
		return m_smartComposite;
	}

	private final function RandomizeGracefulInterruptionConditionCheckInterval( smartCompositeRecord : weak< AIActionSmartComposite_Record > )
	{
		var randomCheckIntervalMods : array< Float >;
		m_gracefulInterruptionCheckRandomizedInterval = 0.0;
		m_hasGracefulInterruptionConditions = false;
		if( smartCompositeRecord.GetGracefulInterruptionConditionCount() > 0 )
		{
			m_hasGracefulInterruptionConditions = true;
		}
		if( m_hasGracefulInterruptionConditions && ( smartCompositeRecord.GracefulInterruptionConditionCheckInterval() > 0.0 ) )
		{
			randomCheckIntervalMods.Resize( 3 );
			randomCheckIntervalMods[ 0 ] = 0.0;
			randomCheckIntervalMods[ 1 ] = 0.0334;
			randomCheckIntervalMods[ 2 ] = 0.0667;
			m_gracefulInterruptionCheckRandomizedInterval = smartCompositeRecord.GracefulInterruptionConditionCheckInterval();
			m_gracefulInterruptionCheckRandomizedInterval += randomCheckIntervalMods[ RandRange( 0, 3 ) ];
		}
	}

	public export virtual function GetFriendlyName() : String
	{
		if( TweakDBInterface.GetAIActionSmartCompositeRecord( m_smartComposite ) )
		{
			return TweakAIActionRecord.GetFriendlyName( m_smartComposite, "SmartComposite" );
		}
		else
		{
			return TweakAIActionRecord.GetFriendlyName( m_smartComposite, " [INVALID] SmartComposite" );
		}
	}

	protected function CheckGracefulInterruptionConditions( const context : ScriptExecutionContext ) : Bool
	{
		var i : Int32;
		var count : Int32;
		count = m_smartCompositeRecord.GetGracefulInterruptionConditionCount();
		for( i = 0; i < count; i += 1 )
		{
			if( AICondition.CheckActionCondition( context, m_smartCompositeRecord.GetGracefulInterruptionConditionItem( i ) ) )
			{
				return true;
			}
		}
		return false;
	}

	[ profile = "" ]
	private export override function Update( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome
	{
		if( !( RetryGetActionRecord( context ) ) )
		{
			return AIbehaviorUpdateOutcome.IN_PROGRESS;
		}
		if( !( m_smartCompositeRecord ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		if( !( m_interruptionRequested ) )
		{
			if( ( m_hasGracefulInterruptionConditions && ( m_gracefulInterruptionCheckRandomizedInterval <= 0.0 ) ) || ( ( m_gracefulInterruptionCheckRandomizedInterval > 0.0 ) && ( EngineTime.ToFloat( ScriptExecutionContext.GetAITime( context ) ) >= ( m_conditionCheckTimeStamp + m_gracefulInterruptionCheckRandomizedInterval ) ) ) )
			{
				if( CheckGracefulInterruptionConditions( context ) )
				{
					if( ( m_smartCompositeRecord.ConditionSuccessDuration() > 0.0 ) && ( m_conditionSuccessfulCheckTimeStamp < 0.0 ) )
					{
						m_conditionSuccessfulCheckTimeStamp = EngineTime.ToFloat( ScriptExecutionContext.GetAITime( context ) );
					}
					if( ( m_smartCompositeRecord.ConditionSuccessDuration() <= 0.0 ) || ( ( m_smartCompositeRecord.ConditionSuccessDuration() > 0.0 ) && ( EngineTime.ToFloat( ScriptExecutionContext.GetAITime( context ) ) >= ( m_conditionSuccessfulCheckTimeStamp + m_smartCompositeRecord.ConditionSuccessDuration() ) ) ) )
					{
						m_interruptionRequested = super.RequestGracefulInterruption( context );
						if( m_interruptionRequested )
						{
							m_gracefullyInterrupted = true;
						}
					}
				}
				else
				{
					m_conditionSuccessfulCheckTimeStamp = -1.0;
				}
				m_conditionCheckTimeStamp = EngineTime.ToFloat( ScriptExecutionContext.GetAITime( context ) );
			}
		}
		switch( super.Update( context ) )
		{
			case AIbehaviorUpdateOutcome.FAILURE:
			{
				if( m_currentNodeType == ETweakAINodeType.Selector )
				{
					if( RunCurrentNodeNextAction( context ) )
					{
						return AIbehaviorUpdateOutcome.IN_PROGRESS;
					}
				}
				if( TweakAIActionRecord.IsSmartCompositeASelector( m_smartCompositeRecord ) && RunNextNode( context ) )
				{
					return AIbehaviorUpdateOutcome.IN_PROGRESS;
				}
				ResetNodeIterator();
				return AIbehaviorUpdateOutcome.FAILURE;
			}
			case AIbehaviorUpdateOutcome.SUCCESS:
			{
				if( m_interruptionRequested )
				{
					return AIbehaviorUpdateOutcome.SUCCESS;
				}
				if( m_currentNodeType == ETweakAINodeType.Sequence && RunCurrentNodeNextAction( context ) )
				{
					return AIbehaviorUpdateOutcome.IN_PROGRESS;
				}
				if( TweakAIActionRecord.IsSmartCompositeASequence( m_smartCompositeRecord ) && RunNextNode( context ) )
				{
					return AIbehaviorUpdateOutcome.IN_PROGRESS;
				}
				return RepeatComposite( context );
			}
			default:
				break;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	private export override function Deactivate( context : ScriptExecutionContext )
	{
		m_interruptionRequested = false;
		m_iteration = 0;
		m_currentNodeIterator = 0;
		if( !( m_smartCompositeRecord ) || !( m_smartCompositeRecord.Type().HasMemory() ) )
		{
			ResetNodeIterator();
		}
		else if( m_smartCompositeRecord.Type().IncrementIteratorOnDeactivation() )
		{
			if( TweakAIActionRecord.IsThisLastActionInSmartComposite( m_smartCompositeRecord, m_nodeIterator ) )
			{
				ResetNodeIterator();
			}
			else
			{
				IncrementNodeIterator();
			}
		}
		super.Deactivate( context );
		m_gracefullyInterrupted = false;
	}

	private final function RepeatComposite( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome
	{
		m_iteration += ( ( Uint32 )( 1 ) );
		if( ( m_smartCompositeRecord.Repeat() < 0 ) || ( m_iteration == ( ( Uint32 )( m_smartCompositeRecord.Repeat() ) ) ) )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		super.Deactivate( context );
		ResetNodeIterator();
		super.Activate( context );
		if( VerifyActionRecord() )
		{
			switch( super.Update( context ) )
			{
				case AIbehaviorUpdateOutcome.FAILURE:
				{
					if( m_currentNodeType == ETweakAINodeType.Selector )
					{
						if( RunCurrentNodeNextAction( context ) )
						{
							return AIbehaviorUpdateOutcome.IN_PROGRESS;
						}
					}
					if( TweakAIActionRecord.IsSmartCompositeASelector( m_smartCompositeRecord ) && RunNextNode( context ) )
					{
						return AIbehaviorUpdateOutcome.IN_PROGRESS;
					}
					ResetNodeIterator();
					return AIbehaviorUpdateOutcome.FAILURE;
				}
				case AIbehaviorUpdateOutcome.SUCCESS:
				{
					if( m_interruptionRequested )
					{
						return AIbehaviorUpdateOutcome.SUCCESS;
					}
					if( m_currentNodeType == ETweakAINodeType.Sequence && RunCurrentNodeNextAction( context ) )
					{
						return AIbehaviorUpdateOutcome.IN_PROGRESS;
					}
					if( TweakAIActionRecord.IsSmartCompositeASequence( m_smartCompositeRecord ) && RunNextNode( context ) )
					{
						return AIbehaviorUpdateOutcome.IN_PROGRESS;
					}
					return AIbehaviorUpdateOutcome.IN_PROGRESS;
				}
				default:
					break;
			}
			return AIbehaviorUpdateOutcome.IN_PROGRESS;
		}
		return AIbehaviorUpdateOutcome.FAILURE;
	}

	private final function RunNextNode( context : ScriptExecutionContext ) : Bool
	{
		if( TweakAIActionRecord.IsThisLastActionInSmartComposite( m_smartCompositeRecord, m_nodeIterator ) )
		{
			return false;
		}
		super.Deactivate( context );
		IncrementNodeIterator();
		super.Activate( context );
		if( VerifyActionRecord() )
		{
			super.Update( context );
		}
		return true;
	}

	private final function RunCurrentNodeNextAction( context : ScriptExecutionContext ) : Bool
	{
		if( m_currentNodeType == ETweakAINodeType.Sequence && TweakAIActionRecord.IsThisLastActionInSequence( ( ( AIActionSequence_Record )( m_currentNode ) ), m_currentNodeIterator ) )
		{
			return false;
		}
		if( m_currentNodeType == ETweakAINodeType.Selector && TweakAIActionRecord.IsThisLastActionInSelector( ( ( AIActionSelector_Record )( m_currentNode ) ), m_currentNodeIterator ) )
		{
			return false;
		}
		m_currentNodeIterator += 1;
		super.Deactivate( context );
		m_gracefullyInterrupted = false;
		super.Activate( context );
		if( VerifyActionRecord() )
		{
			super.Update( context );
		}
		return true;
	}

	private final function ResetNodeIterator()
	{
		if( m_smartCompositeRecord && m_smartCompositeRecord.Type().RandomizeIteratorOnReset() )
		{
			m_nodeIterator = RandRange( 0, m_smartCompositeRecord.GetNodesCount() );
			m_currentNodeIterator = m_nodeIterator;
		}
		else
		{
			m_nodeIterator = 0;
			m_currentNodeIterator = 0;
		}
	}

	private final function IncrementNodeIterator()
	{
		m_nodeIterator += 1;
		m_currentNodeIterator = 0;
		m_gracefullyInterrupted = false;
	}

}

class IdleActionsCondition extends AIbehaviorconditionScript
{

	private override final function Check( context : ScriptExecutionContext ) : AIbehaviorConditionOutcomes
	{
		var characterRecord : weak< Character_Record >;
		characterRecord = TweakDBInterface.GetCharacterRecord( ScriptExecutionContext.GetOwner( context ).GetRecordID() );
		if( !( characterRecord ) )
		{
			return false;
		}
		if( !( characterRecord.IdleActions() ) )
		{
			return false;
		}
		return true;
	}

	public constexpr function GetFriendlyName() : String
	{
		return "IdleActionsCondition";
	}

}

class IdleActions extends TweakAIActionSmartComposite
{

	public override function GetSmartCompositeRecord( const context : ScriptExecutionContext, smartCompositeID : TweakDBID, smartCompositeDebugName : ref< String >, out smartCompositeRecord : weak< AIActionSmartComposite_Record > ) : Bool
	{
		var characterRecord : weak< Character_Record >;
		characterRecord = TweakDBInterface.GetCharacterRecord( ScriptExecutionContext.GetOwner( context ).GetRecordID() );
		if( !( characterRecord ) )
		{
			return false;
		}
		smartCompositeRecord = characterRecord.IdleActions();
		smartCompositeDebugName = "IdleActions";
		return ( ( smartCompositeRecord ) ? ( true ) : ( false ) );
	}

	public override function GetFriendlyName() : String
	{
		return "IdleActions";
	}

}

class PatrolAction extends TweakAIActionSmartComposite
{

	public override function GetSmartCompositeRecord( const context : ScriptExecutionContext, smartCompositeID : TweakDBID, smartCompositeDebugName : ref< String >, out smartCompositeRecord : weak< AIActionSmartComposite_Record > ) : Bool
	{
		var record : AIRecord_Record;
		var patrolActionID : TweakDBID;
		patrolActionID = ( ( TweakDBID )( GetPuppet( context ).GetAIControllerComponent().GetAIPatrolBlackboard().GetVariant( GetAllBlackboardDefs().AIPatrol.patrolAction ) ) );
		if( !( TDBID.IsValid( patrolActionID ) ) )
		{
			return false;
		}
		if( !( ScriptExecutionContext.GetOverriddenNode( context, patrolActionID, record, true ) ) )
		{
			return false;
		}
		smartCompositeID = record.GetID();
		if( !( IsFinal() ) )
		{
			smartCompositeDebugName = TDBID.ToStringDEBUG( smartCompositeID );
		}
		smartCompositeRecord = ( ( AIActionSmartComposite_Record )( record ) );
		return smartCompositeRecord != NULL;
	}

	public export override function GetFriendlyName() : String
	{
		return "PatrolAction";
	}

}

class PatrolSpotAction extends TweakAIActionSmartComposite
{
	editable inlined var m_patrolAction : AIArgumentMapping;

	public override function GetSmartCompositeRecord( const context : ScriptExecutionContext, smartCompositeID : TweakDBID, smartCompositeDebugName : ref< String >, out smartCompositeRecord : weak< AIActionSmartComposite_Record > ) : Bool
	{
		var patrolActionName : CName;
		var patrolCompositeID : TweakDBID;
		var patrolCompositeRecord : weak< AIActionSmartComposite_Record >;
		patrolActionName = ( ( CName )( ScriptExecutionContext.GetMappingValue( context, m_patrolAction ) ) );
		patrolCompositeID = TDBID.Create( ( ( String )( patrolActionName ) ) );
		if( !( TDBID.IsValid( patrolCompositeID ) ) )
		{
			return false;
		}
		patrolCompositeRecord = TweakDBInterface.GetAIActionSmartCompositeRecord( patrolCompositeID );
		if( !( patrolCompositeRecord ) )
		{
			return false;
		}
		smartCompositeRecord = patrolCompositeRecord;
		smartCompositeDebugName = "PatrolSpotAction";
		return ( ( smartCompositeRecord ) ? ( true ) : ( false ) );
	}

	public export override function GetFriendlyName() : String
	{
		return "PatrolSpotAction";
	}

}

