abstract class TweakAISubAction extends IScriptable
{

	public static function OnCantFindProperActivateMethod( const className : CName )
	{
	}

	public static function OnCantFindProperUpdateMethod( const className : CName )
	{
	}

	public static function OnCantFindProperDeactivateMethod( const className : CName )
	{
	}

	public static function OnCantFindProperGetAnimVariationMethod( const className : CName )
	{
	}

	public static function OnCantFindProperGetPhaseDurationnMethod( const className : CName )
	{
	}

	public static function Activate( context : ScriptExecutionContext, subActionRecord : weak< AISubAction_Record > ) : Bool
	{
		if( !( subActionRecord ) )
		{
			return false;
		}
		AIScriptUtils.CallActivateSubAction( context, subActionRecord );
		return true;
	}

	public static function Update( context : ScriptExecutionContext, subActionRecord : weak< AISubAction_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( !( subActionRecord ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		return AIScriptUtils.CallUpdateSubAction( context, subActionRecord, duration );
	}

	public static function Deactivate( context : ScriptExecutionContext, subActionRecord : weak< AISubAction_Record >, const duration : Float, interrupted : Bool )
	{
		if( !( subActionRecord ) )
		{
			return;
		}
		AIScriptUtils.CallDeactivateSubAction( context, subActionRecord, duration, interrupted );
	}

	public static function GetAnimVariation( context : ScriptExecutionContext, subActionRecord : weak< AISubAction_Record >, out animVariation : Int32 ) : Bool
	{
		if( !( subActionRecord ) )
		{
			return false;
		}
		animVariation = AIScriptUtils.CallGetAnimVariation( context, subActionRecord );
		return animVariation >= 0;
	}

	public static function GetPhaseDuration( context : ScriptExecutionContext, subActionRecord : weak< AISubAction_Record >, actionPhase : EAIActionPhase, baseDuration : Float, out duration : Float ) : Bool
	{
		if( !( subActionRecord ) )
		{
			return false;
		}
		duration = AIScriptUtils.CallGetPhaseDuration( context, subActionRecord, ( ( Int32 )( actionPhase ) ), baseDuration );
		return duration >= 0.0;
	}

}

abstract class AISubActionPlayVoiceOver_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionPlayVoiceOver_Record > )
	{
		if( ( record.Delay() == 0.0 ) && IsConditionFulfilled( context, record ) )
		{
			SendVoiceOverEvent( context, record, 'Scripts:AISubActionPlayVoiceOver:Activate' );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionPlayVoiceOver_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( IsDelayConditionFulfilled( context, record, duration ) && IsConditionFulfilled( context, record ) )
		{
			SendVoiceOverEvent( context, record, 'Scripts:AISubActionPlayVoiceOver:Delayed' );
			if( !( record.Repeat() ) )
			{
				return AIbehaviorUpdateOutcome.SUCCESS;
			}
		}
		if( ( record.Delay() == 0.0 ) && !( record.Repeat() ) )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionPlayVoiceOver_Record >, const duration : Float, interrupted : Bool )
	{
		if( ( !( record.Repeat() ) && ( record.Delay() < 0.0 ) ) && IsConditionFulfilled( context, record ) )
		{
			SendVoiceOverEvent( context, record, 'Scripts:AISubActionPlayVoiceOver:Deactivate' );
		}
	}

	public static function IsSquadmateConditionFulfilled( context : ScriptExecutionContext, record : weak< AISubActionPlayVoiceOver_Record > ) : Bool
	{
		var squadmates : array< weak< Entity > >;
		return !( record.SendEventToSquadmates() ) || AISquadHelper.GetSquadmates( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), squadmates );
	}

	public static function IsCooldownConditionFulfilled( context : ScriptExecutionContext, record : weak< AISubActionPlayVoiceOver_Record > ) : Bool
	{
		return !( record.Cooldown() ) || !( AIActionHelper.IsCooldownActive( ScriptExecutionContext.GetOwner( context ), record.Cooldown() ) );
	}

	public static function IsConditionFulfilled( context : ScriptExecutionContext, record : weak< AISubActionPlayVoiceOver_Record > ) : Bool
	{
		return ( IsSquadmateConditionFulfilled( context, record ) && IsCooldownConditionFulfilled( context, record ) ) && ( !( record.Condition() ) || AICondition.CheckActionCondition( context, record.Condition() ) );
	}

	public static function SendVoiceOverEvent( context : ScriptExecutionContext, record : weak< AISubActionPlayVoiceOver_Record >, debugInitContext : CName )
	{
		var ownerPuppet : gamePuppet;
		ownerPuppet = ( ( gamePuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		if( record.SendEventToSquadmates() )
		{
			ReactionManagerComponent.SendVOEventToSquad( ownerPuppet, record.Name(), record.SetSelfAsAnsweringEntity() );
		}
		else
		{
			GameObject.PlayVoiceOver( ownerPuppet, record.Name(), debugInitContext );
		}
		if( record.Cooldown() )
		{
			AIActionHelper.StartCooldown( ownerPuppet, record.Cooldown() );
		}
	}

	public static function IsDelayConditionFulfilled( context : ScriptExecutionContext, record : weak< AISubActionPlayVoiceOver_Record >, const duration : Float ) : Bool
	{
		return ( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) ) || ( record.Repeat() && ( record.Delay() == 0.0 ) );
	}

}

abstract class AISubActionDisableCollider_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionDisableCollider_Record > )
	{
		var aiComponent : AIHumanComponent;
		if( record.Disable() && ( record.Delay() == 0.0 ) )
		{
			AIHumanComponent.Get( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), aiComponent );
			aiComponent.DisableCollider();
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionDisableCollider_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var aiComponent : AIHumanComponent;
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Disable() && ( record.Delay() > 0.0 ) ) && IsDelayConditionFulfilled( context, record, duration ) )
		{
			AIHumanComponent.Get( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), aiComponent );
			aiComponent.DisableCollider();
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionDisableCollider_Record >, const duration : Float, interrupted : Bool )
	{
		var aiComponent : AIHumanComponent;
		if( record.EnableOnDeactivate() )
		{
			AIHumanComponent.Get( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), aiComponent );
			aiComponent.EnableCollider();
		}
	}

	public static function IsDelayConditionFulfilled( context : ScriptExecutionContext, record : weak< AISubActionDisableCollider_Record >, const duration : Float ) : Bool
	{
		return ( record.Delay() > 0.0 ) && ( duration >= record.Delay() );
	}

}

abstract class AISubActionAddFact_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionAddFact_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			AddFact( ScriptExecutionContext.GetOwner( context ).GetGame(), record.Name() );
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionAddFact_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			AddFact( ScriptExecutionContext.GetOwner( context ).GetGame(), record.Name() );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionAddFact_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			AddFact( ScriptExecutionContext.GetOwner( context ).GetGame(), record.Name() );
		}
		else if( record.ResetValue() )
		{
			SetFactValue( ScriptExecutionContext.GetOwner( context ).GetGame(), record.Name(), 0 );
		}
	}

}

abstract class AISubActionQueueAIEvent_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionQueueAIEvent_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			QueueAIEvent( context, record );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionQueueAIEvent_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			QueueAIEvent( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionQueueAIEvent_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			QueueAIEvent( context, record );
		}
	}

	public static function QueueAIEvent( context : ScriptExecutionContext, record : weak< AISubActionQueueAIEvent_Record > )
	{
		var aiEvent : AIEvent;
		if( !( IsNameValid( record.Name() ) ) )
		{
			return;
		}
		aiEvent = new AIEvent;
		aiEvent.name = record.Name();
		ScriptExecutionContext.GetOwner( context ).QueueEvent( aiEvent );
	}

}

abstract class AISubActionQueueCommunicationEvent_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionQueueCommunicationEvent_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			QueueCommunicationEvent( context, record );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionQueueCommunicationEvent_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			QueueCommunicationEvent( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionQueueCommunicationEvent_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			QueueCommunicationEvent( context, record );
		}
	}

	public static function QueueCommunicationEvent( context : ScriptExecutionContext, record : weak< AISubActionQueueCommunicationEvent_Record > )
	{
		var communicationEvent : CommunicationEvent;
		var listener : weak< GameObject >;
		if( !( IsNameValid( record.Name() ) ) )
		{
			return;
		}
		if( !( AIActionTarget.GetObject( context, record.TargetListener(), listener ) ) )
		{
			return;
		}
		communicationEvent = new CommunicationEvent;
		communicationEvent.name = record.Name();
		communicationEvent.sender = ScriptExecutionContext.GetOwner( context ).GetEntityID();
		listener.QueueEvent( communicationEvent );
		ScriptExecutionContext.GetOwner( context ).QueueEvent( communicationEvent );
	}

}

abstract class AISubActionSpawnFX_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionSpawnFX_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			SpawnFX( context, record );
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionSpawnFX_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			SpawnFX( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionSpawnFX_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			SpawnFX( context, record );
		}
		else
		{
			DespawnFX( context, record );
		}
	}

	public static function SpawnFX( context : ScriptExecutionContext, record : weak< AISubActionSpawnFX_Record > )
	{
		var item : ItemObject;
		if( record.AttachmentSlot() )
		{
			item = GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetItemInSlot( ScriptExecutionContext.GetOwner( context ), record.AttachmentSlot().GetID() );
			if( !( item ) )
			{
				return;
			}
			GameObject.StartReplicatedEffectEvent( item, record.Name() );
		}
		else
		{
			GameObject.StartReplicatedEffectEvent( ScriptExecutionContext.GetOwner( context ), record.Name() );
		}
	}

	public static function DespawnFX( context : ScriptExecutionContext, record : weak< AISubActionSpawnFX_Record > )
	{
		var item : ItemObject;
		if( record.AttachmentSlot() )
		{
			item = GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetItemInSlot( ScriptExecutionContext.GetOwner( context ), record.AttachmentSlot().GetID() );
			if( !( item ) )
			{
				return;
			}
			GameObject.BreakReplicatedEffectLoopEvent( item, record.Name() );
		}
		else
		{
			GameObject.BreakReplicatedEffectLoopEvent( ScriptExecutionContext.GetOwner( context ), record.Name() );
		}
	}

}

abstract class AISubActionPlaySound_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionPlaySound_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			PlaySound( context, record );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionPlaySound_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			PlaySound( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionPlaySound_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			PlaySound( context, record );
		}
	}

	public static function PlaySound( context : ScriptExecutionContext, record : weak< AISubActionPlaySound_Record > )
	{
		var item : ItemObject;
		if( record.AttachmentSlot() )
		{
			item = GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetItemInSlot( ScriptExecutionContext.GetOwner( context ), record.AttachmentSlot().GetID() );
			if( !( item ) )
			{
				return;
			}
			GameObject.PlaySound( item, record.Name() );
		}
		else
		{
			GameObject.PlaySound( ScriptExecutionContext.GetOwner( context ), record.Name() );
		}
	}

}

abstract class AISubActionSetEquipWeaponsUtils extends IScriptable
{

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionCharacterRecordEquip_Record >, const itemsToEquip : ref< array< NPCItemToEquip > >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var puppet : ScriptedPuppet;
		if( itemsToEquip.Size() == 0 )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		puppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		if( !( puppet ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		AIActionHelper.SetItemsEquipData( puppet, itemsToEquip );
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

}

abstract class AISubActionSetEquipPrimaryWeapons_Record_Implementation extends IScriptable
{

	public static function GetItemsToEquip( context : ScriptExecutionContext, record : weak< AISubActionCharacterRecordEquip_Record >, itemsToEquip : ref< array< NPCItemToEquip > > ) : Bool
	{
		return AIActionTransactionSystem.GetEquipmentWithCondition( context, true, false, itemsToEquip );
	}

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionSetEquipPrimaryWeapons_Record > ) {}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionSetEquipPrimaryWeapons_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var itemsToEquip : array< NPCItemToEquip >;
		GetItemsToEquip( context, record, itemsToEquip );
		return AISubActionSetEquipWeaponsUtils.Update( context, ( ( AISubActionCharacterRecordEquip_Record )( record ) ), itemsToEquip, duration );
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionSetEquipPrimaryWeapons_Record >, const duration : Float, interrupted : Bool ) {}
}

abstract class AISubActionSetEquipSecondaryWeapons_Record_Implementation extends IScriptable
{

	public static function GetItemsToEquip( context : ScriptExecutionContext, record : weak< AISubActionCharacterRecordEquip_Record >, itemsToEquip : ref< array< NPCItemToEquip > > ) : Bool
	{
		var characterRecord : weak< Character_Record >;
		characterRecord = TweakDBInterface.GetCharacterRecord( ScriptExecutionContext.GetOwner( context ).GetRecordID() );
		if( !( AIActionTransactionSystem.GetEquipmentWithCondition( context, false, false, itemsToEquip ) ) )
		{
			return AIActionTransactionSystem.GetDefaultEquipment( context, characterRecord, false, itemsToEquip );
		}
		return true;
	}

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionSetEquipSecondaryWeapons_Record > ) {}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionSetEquipSecondaryWeapons_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var itemsToEquip : array< NPCItemToEquip >;
		GetItemsToEquip( context, record, itemsToEquip );
		return AISubActionSetEquipWeaponsUtils.Update( context, ( ( AISubActionCharacterRecordEquip_Record )( record ) ), itemsToEquip, duration );
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionSetEquipSecondaryWeapons_Record >, const duration : Float, interrupted : Bool ) {}
}

abstract class AISubActionEquipOnSlot_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionEquipOnSlot_Record > )
	{
		var transactionSystem : TransactionSystem;
		var itemsToEquip : array< NPCItemToEquip >;
		var itemToRemove : ItemObject;
		var BBoard : IBlackboard;
		var cleanupDone : Bool;
		var i : Int32;
		BBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		if( BBoard )
		{
			itemsToEquip = ( ( array< NPCItemToEquip > )( BBoard.GetVariant( GetAllBlackboardDefs().AIAction.ownerItemsToEquip ) ) );
			if( itemsToEquip.Size() != 0 )
			{
				transactionSystem = GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() );
				if( transactionSystem )
				{
					for( i = 0; i < itemsToEquip.Size(); i += 1 )
					{
						if( !( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).IsMechanical() ) )
						{
							if( cleanupDone )
							{
								continue;
							}
							if( !( transactionSystem.IsSlotEmpty( ScriptExecutionContext.GetOwner( context ), T"AttachmentSlots.WeaponLeft" ) ) && !( transactionSystem.IsSlotEmptySpawningItem( ScriptExecutionContext.GetOwner( context ), T"AttachmentSlots.WeaponLeft" ) ) )
							{
								itemToRemove = transactionSystem.GetItemInSlot( ScriptExecutionContext.GetOwner( context ), T"AttachmentSlots.WeaponLeft" );
								if( !( transactionSystem.HasItemInSlot( ScriptExecutionContext.GetOwner( context ), T"AttachmentSlots.WeaponLeft", itemsToEquip[ i ].itemID ) ) && transactionSystem.RemoveItemFromSlot( ScriptExecutionContext.GetOwner( context ), T"AttachmentSlots.WeaponLeft", true ) )
								{
									NPCPuppet.SetAnimWrapperBasedOnEquippedItem( ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), T"AttachmentSlots.WeaponLeft", itemToRemove.GetItemID(), 0.0 );
								}
							}
							if( !( transactionSystem.IsSlotEmpty( ScriptExecutionContext.GetOwner( context ), T"AttachmentSlots.WeaponRight" ) ) && !( transactionSystem.IsSlotEmptySpawningItem( ScriptExecutionContext.GetOwner( context ), T"AttachmentSlots.WeaponRight" ) ) )
							{
								itemToRemove = transactionSystem.GetItemInSlot( ScriptExecutionContext.GetOwner( context ), T"AttachmentSlots.WeaponRight" );
								if( !( transactionSystem.HasItemInSlot( ScriptExecutionContext.GetOwner( context ), T"AttachmentSlots.WeaponLeft", itemsToEquip[ i ].itemID ) ) && transactionSystem.RemoveItemFromSlot( ScriptExecutionContext.GetOwner( context ), T"AttachmentSlots.WeaponRight", true ) )
								{
									NPCPuppet.SetAnimWrapperBasedOnEquippedItem( ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), T"AttachmentSlots.WeaponRight", itemToRemove.GetItemID(), 0.0 );
								}
							}
							cleanupDone = true;
						}
						else if( !( transactionSystem.IsSlotEmpty( ScriptExecutionContext.GetOwner( context ), itemsToEquip[ i ].slotID ) ) && !( transactionSystem.IsSlotEmptySpawningItem( ScriptExecutionContext.GetOwner( context ), itemsToEquip[ i ].slotID ) ) )
						{
							itemToRemove = transactionSystem.GetItemInSlot( ScriptExecutionContext.GetOwner( context ), itemsToEquip[ i ].slotID );
							if( !( transactionSystem.HasItemInSlot( ScriptExecutionContext.GetOwner( context ), itemsToEquip[ i ].slotID, itemsToEquip[ i ].itemID ) ) && transactionSystem.RemoveItemFromSlot( ScriptExecutionContext.GetOwner( context ), itemsToEquip[ i ].slotID, true ) )
							{
								NPCPuppet.SetAnimWrapperBasedOnEquippedItem( ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), itemsToEquip[ i ].slotID, itemToRemove.GetItemID(), 0.0 );
							}
						}
					}
				}
				if( BBoard.GetFloat( GetAllBlackboardDefs().AIAction.ownerEquipDuration ) > 0.0 )
				{
					ApplyAnimFeature( context, itemsToEquip, record.UseItemSpawnDelayFromWeapon() );
				}
				if( !( record.UseItemSpawnDelayFromWeapon() ) || ( BBoard.GetFloat( GetAllBlackboardDefs().AIAction.ownerEquipItemTime ) == 0.0 ) )
				{
					Equip( context, itemsToEquip, record.CacheEquippedItem() );
				}
			}
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionEquipOnSlot_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var BBoard : IBlackboard;
		var itemsToEquip : array< NPCItemToEquip >;
		var equipTime : Float;
		BBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		if( BBoard )
		{
			if( duration < BBoard.GetFloat( GetAllBlackboardDefs().AIAction.ownerEquipDuration ) )
			{
				if( record.UseItemSpawnDelayFromWeapon() )
				{
					itemsToEquip = ( ( array< NPCItemToEquip > )( BBoard.GetVariant( GetAllBlackboardDefs().AIAction.ownerItemsToEquip ) ) );
					if( itemsToEquip.Size() != 0 )
					{
						equipTime = BBoard.GetFloat( GetAllBlackboardDefs().AIAction.ownerEquipItemTime );
						if( ( equipTime > 0.0 ) && ( duration > equipTime ) )
						{
							Equip( context, itemsToEquip, record.CacheEquippedItem() );
						}
					}
				}
				return AIbehaviorUpdateOutcome.IN_PROGRESS;
			}
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.FAILURE;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionEquipOnSlot_Record >, const duration : Float, interrupted : Bool )
	{
		var BBoard : IBlackboard;
		var itemsToEquip : array< NPCItemToEquip >;
		BBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		if( BBoard )
		{
			itemsToEquip = ( ( array< NPCItemToEquip > )( BBoard.GetVariant( GetAllBlackboardDefs().AIAction.ownerItemsToEquip ) ) );
			if( itemsToEquip.Size() != 0 )
			{
				Equip( context, itemsToEquip, record.CacheEquippedItem() );
			}
			if( BBoard.GetFloat( GetAllBlackboardDefs().AIAction.ownerEquipDuration ) > 0.0 )
			{
				AnimationControllerComponent.ApplyFeatureToReplicate( ScriptExecutionContext.GetOwner( context ), 'Equip', new AnimFeature_AIAction );
			}
			BBoard.SetFloat( GetAllBlackboardDefs().AIAction.ownerEquipDuration, 0.0 );
		}
	}

	public static function ApplyAnimFeature( context : ScriptExecutionContext, const itemsToEquip : ref< array< NPCItemToEquip > >, sendAnimFeature : Bool )
	{
		var animFeature : AnimFeature_AIAction;
		var i : Int32;
		animFeature = new AnimFeature_AIAction;
		animFeature.state = 1;
		animFeature.stateDuration = -1.0;
		if( itemsToEquip.Size() > 1 )
		{
			animFeature.animVariation = 2;
		}
		else
		{
			if( GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).HasTag( ScriptExecutionContext.GetOwner( context ), WeaponObject.GetMeleeWeaponTag(), itemsToEquip[ 0 ].itemID ) )
			{
				animFeature.animVariation = 1;
			}
			else
			{
				animFeature.animVariation = 0;
			}
		}
		if( sendAnimFeature )
		{
			for( i = 0; i < itemsToEquip.Size(); i += 1 )
			{
				NPCPuppet.SetAnimWrapperBasedOnEquippedItem( ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), itemsToEquip[ i ].slotID, itemsToEquip[ i ].itemID, 1.0 );
			}
		}
		AnimationControllerComponent.ApplyFeatureToReplicate( ScriptExecutionContext.GetOwner( context ), 'Equip', animFeature );
	}

	public static function Equip( context : ScriptExecutionContext, const itemsToEquip : ref< array< NPCItemToEquip > >, cacheEquipped : Bool ) : Bool
	{
		var i : Int32;
		var result : Bool;
		var equipOnBody : Bool;
		var transactionSystem : TransactionSystem;
		var reservedEquipSlotIDs : array< TweakDBID >;
		var highPriority : Bool;
		var owner : gamePuppet;
		equipOnBody = TweakDBInterface.GetBool( T"AIGeneralSettings.displayWeaponsOnBody", equipOnBody );
		highPriority = false;
		owner = ScriptExecutionContext.GetOwner( context );
		if( ScriptedPuppet.IsActive( owner ) == false )
		{
			return false;
		}
		transactionSystem = GameInstance.GetTransactionSystem( owner.GetGame() );
		if( !( transactionSystem ) )
		{
			return false;
		}
		for( i = 0; i < itemsToEquip.Size(); i += 1 )
		{
			if( reservedEquipSlotIDs.Contains( itemsToEquip[ i ].slotID ) )
			{
				continue;
			}
			if( equipOnBody && transactionSystem.HasItemInSlot( owner, itemsToEquip[ i ].bodySlotID, itemsToEquip[ i ].itemID ) )
			{
				result = transactionSystem.ChangeItemToSlot( owner, itemsToEquip[ i ].slotID, itemsToEquip[ i ].itemID );
				if( result )
				{
					reservedEquipSlotIDs.PushBack( itemsToEquip[ i ].slotID );
				}
			}
			else
			{
				highPriority = WeaponObject.GetWeaponType( itemsToEquip[ i ].itemID ) != gamedataItemType.Invalid;
				result = transactionSystem.AddItemToSlot( owner, itemsToEquip[ i ].slotID, itemsToEquip[ i ].itemID, highPriority, , , , , , , !( cacheEquipped ) );
				if( result )
				{
					reservedEquipSlotIDs.PushBack( itemsToEquip[ i ].slotID );
				}
			}
		}
		if( result )
		{
			AIActionHelper.ClearItemsToEquip( ( ( ScriptedPuppet )( owner ) ) );
		}
		return result;
	}

}

abstract class AISubActionEquipOnBody_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionEquipOnBody_Record > ) {}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionEquipOnBody_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var itemsToEquip : array< NPCItemToEquip >;
		GetItemsToEquip( context, record, itemsToEquip );
		if( EquipOnBody( context, itemsToEquip ) )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.FAILURE;
	}

	public static function GetItemsToEquip( context : ScriptExecutionContext, record : weak< AISubActionCharacterRecordEquip_Record >, itemsToEquip : ref< array< NPCItemToEquip > > ) : Bool
	{
		return AIActionTransactionSystem.GetOnBodyEquipment( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), itemsToEquip );
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionEquipOnBody_Record >, const duration : Float, interrupted : Bool ) {}

	public static function EquipOnBody( context : ScriptExecutionContext, const itemsToEquip : ref< array< NPCItemToEquip > > ) : Bool
	{
		var i : Int32;
		var equipOnBody : Bool;
		var transactionSystem : TransactionSystem;
		var highPriority : Bool;
		var result : Bool;
		var owner : gamePuppet;
		equipOnBody = TweakDBInterface.GetBool( T"AIGeneralSettings.displayWeaponsOnBody", equipOnBody );
		owner = ScriptExecutionContext.GetOwner( context );
		if( ScriptedPuppet.IsActive( owner ) == false )
		{
			return false;
		}
		transactionSystem = GameInstance.GetTransactionSystem( owner.GetGame() );
		if( !( transactionSystem ) )
		{
			return false;
		}
		if( equipOnBody )
		{
			for( i = 0; i < itemsToEquip.Size(); i += 1 )
			{
				if( !( transactionSystem.HasItem( owner, itemsToEquip[ i ].itemID ) ) )
				{
					transactionSystem.GiveItem( owner, itemsToEquip[ i ].itemID, 1 );
				}
				if( !( transactionSystem.HasItemInSlot( owner, itemsToEquip[ i ].bodySlotID, itemsToEquip[ i ].itemID ) ) )
				{
					highPriority = WeaponObject.GetWeaponType( itemsToEquip[ i ].itemID ) != gamedataItemType.Invalid;
					if( transactionSystem.AddItemToSlot( owner, itemsToEquip[ i ].bodySlotID, itemsToEquip[ i ].itemID, highPriority ) )
					{
						result = true;
					}
				}
			}
		}
		if( result )
		{
			AIActionHelper.ClearItemsToEquip( ( ( ScriptedPuppet )( owner ) ) );
		}
		return result;
	}

}

abstract class AISubActionForceEquip_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionForceEquip_Record > )
	{
		var itemsToEquip : array< NPCItemToEquip >;
		var itemToEquip : NPCItemToEquip;
		var itemID : ItemID;
		var BBoard : IBlackboard;
		if( GetItemID( context, record, itemID ) && record.AttachmentSlot() )
		{
			itemToEquip.itemID = itemID;
			itemToEquip.slotID = record.AttachmentSlot().GetID();
			BBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
			if( BBoard )
			{
				itemsToEquip = ( ( array< NPCItemToEquip > )( BBoard.GetVariant( GetAllBlackboardDefs().AIAction.ownerItemsToEquip ) ) );
			}
			itemsToEquip.PushBack( itemToEquip );
			AIActionHelper.SetItemsEquipData( ( ( weak< weak< ScriptedPuppet > > )( ScriptExecutionContext.GetOwner( context ) ) ), itemsToEquip );
			if( record.AnimationTime() > 0.0 )
			{
				ApplyAnimFeature( context, itemsToEquip, record );
			}
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionForceEquip_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( ( record.Delay() == 0.0 ) || ( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) ) )
		{
			if( record.AttachmentSlot() && Equip( context, record ) )
			{
				return AIbehaviorUpdateOutcome.SUCCESS;
			}
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionForceEquip_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.EquipDespiteInterruption() || ( record.Delay() < 0.0 ) )
		{
			if( record.AttachmentSlot() )
			{
				Equip( context, record );
			}
		}
		if( record.AnimationTime() > 0.0 )
		{
			AnimationControllerComponent.ApplyFeatureToReplicate( ScriptExecutionContext.GetOwner( context ), 'Equip', new AnimFeature_AIAction );
		}
	}

	public static function ApplyAnimFeature( context : ScriptExecutionContext, const itemsToEquip : ref< array< NPCItemToEquip > >, record : weak< AISubActionForceEquip_Record > )
	{
		var animFeature : AnimFeature_AIAction;
		var i : Int32;
		animFeature = new AnimFeature_AIAction;
		animFeature.state = 1;
		if( record.AnimationTime() >= 0.0 )
		{
			animFeature.stateDuration = record.AnimationTime();
		}
		else
		{
			animFeature.stateDuration = -1.0;
		}
		if( itemsToEquip.Size() > 1 )
		{
			animFeature.animVariation = 2;
		}
		else
		{
			if( GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).HasTag( ScriptExecutionContext.GetOwner( context ), WeaponObject.GetMeleeWeaponTag(), itemsToEquip[ 0 ].itemID ) )
			{
				animFeature.animVariation = 1;
			}
			else
			{
				animFeature.animVariation = 0;
			}
		}
		for( i = 0; i < itemsToEquip.Size(); i += 1 )
		{
			NPCPuppet.SetAnimWrapperBasedOnEquippedItem( ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), itemsToEquip[ i ].slotID, itemsToEquip[ i ].itemID, 1.0 );
		}
		AnimationControllerComponent.ApplyFeatureToReplicate( ScriptExecutionContext.GetOwner( context ), 'Equip', animFeature );
	}

	public static function Equip( context : ScriptExecutionContext, record : weak< AISubActionForceEquip_Record > ) : Bool
	{
		var transactionSystem : TransactionSystem;
		var itemID : ItemID;
		var result : Bool;
		var item : weak< ItemObject >;
		var gameObj : weak< GameObject >;
		var highPriority : Bool;
		var owner : gamePuppet;
		highPriority = false;
		owner = ScriptExecutionContext.GetOwner( context );
		if( ScriptedPuppet.IsActive( owner ) == false )
		{
			return false;
		}
		transactionSystem = GameInstance.GetTransactionSystem( owner.GetGame() );
		if( !( transactionSystem ) )
		{
			return false;
		}
		if( record.ItemObject() )
		{
			if( !( AIActionTarget.GetObject( context, record.ItemObject(), gameObj ) ) )
			{
				return false;
			}
			item = ( ( weak< weak< gameItemDropObject > > )( gameObj ) ).GetItemObject();
			if( !( item ) )
			{
				return false;
			}
			if( transactionSystem.TakeItem( owner, item ) )
			{
				highPriority = WeaponObject.GetWeaponType( item.GetItemID() ) != gamedataItemType.Invalid;
				result = transactionSystem.AddItemToSlot( owner, record.AttachmentSlot().GetID(), item.GetItemID(), highPriority, item );
			}
			return result;
		}
		if( !( GetItemID( context, record, itemID ) ) )
		{
			return false;
		}
		if( transactionSystem.HasItemInAnySlot( owner, itemID ) )
		{
			if( record.ItemID() && !( transactionSystem.HasItem( owner, itemID ) ) )
			{
				transactionSystem.GiveItem( owner, itemID, 1 );
			}
			result = transactionSystem.ChangeItemToSlot( owner, record.AttachmentSlot().GetID(), itemID );
		}
		else
		{
			if( record.ItemID() && !( transactionSystem.HasItem( owner, itemID ) ) )
			{
				transactionSystem.GiveItem( owner, itemID, 1 );
			}
			highPriority = WeaponObject.GetWeaponType( itemID ) != gamedataItemType.Invalid;
			result = transactionSystem.AddItemToSlot( owner, record.AttachmentSlot().GetID(), itemID, highPriority );
		}
		if( result )
		{
			AIActionHelper.ClearItemsToEquip( ( ( ScriptedPuppet )( owner ) ) );
		}
		return result;
	}

	public static function GetItemID( context : ScriptExecutionContext, record : weak< AISubActionForceEquip_Record >, out itemID : ItemID ) : Bool
	{
		if( record.ItemID() )
		{
			itemID = ItemID.CreateQuery( record.ItemID().GetID() );
			return true;
		}
		if( record.ItemType() )
		{
			return AIActionTransactionSystem.GetFirstItemID( ScriptExecutionContext.GetOwner( context ), record.ItemType(), record.ItemTag(), itemID );
		}
		if( record.ItemCategory() )
		{
			return AIActionTransactionSystem.GetFirstItemID( ScriptExecutionContext.GetOwner( context ), record.ItemCategory(), record.ItemTag(), itemID );
		}
		if( AIActionTransactionSystem.GetFirstItemID( ScriptExecutionContext.GetOwner( context ), record.ItemTag(), itemID ) )
		{
			return true;
		}
		return false;
	}

}

abstract class AISubActionSetUnequipWeaponsUtils extends IScriptable
{

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionCharacterRecordUnequip_Record >, const itemsToUnequip : ref< array< NPCItemToEquip > >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var puppet : ScriptedPuppet;
		if( itemsToUnequip.Size() == 0 )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		puppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		if( !( puppet ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		AIActionHelper.SetItemsUnequipData( puppet, itemsToUnequip, record.DropItem() );
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

}

abstract class AISubActionSetUnequipPrimaryWeapons_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionSetUnequipPrimaryWeapons_Record > ) {}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionSetUnequipPrimaryWeapons_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var itemsToUnequip : array< NPCItemToEquip >;
		GetItemsToUnequip( context, record, itemsToUnequip );
		return AISubActionSetUnequipWeaponsUtils.Update( context, ( ( AISubActionCharacterRecordUnequip_Record )( record ) ), itemsToUnequip, duration );
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionSetUnequipPrimaryWeapons_Record >, const duration : Float, interrupted : Bool ) {}

	public static function GetItemsToUnequip( context : ScriptExecutionContext, record : weak< AISubActionCharacterRecordUnequip_Record >, itemsToUnequip : ref< array< NPCItemToEquip > > ) : Bool
	{
		return AIActionTransactionSystem.GetEquipmentWithCondition( context, true, true, itemsToUnequip );
	}

}

abstract class AISubActionSetUnequipSecondaryWeapons_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionSetUnequipSecondaryWeapons_Record > ) {}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionSetUnequipSecondaryWeapons_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var itemsToUnequip : array< NPCItemToEquip >;
		GetItemsToUnequip( context, record, itemsToUnequip );
		return AISubActionSetUnequipWeaponsUtils.Update( context, ( ( AISubActionCharacterRecordUnequip_Record )( record ) ), itemsToUnequip, duration );
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionSetUnequipSecondaryWeapons_Record >, const duration : Float, interrupted : Bool ) {}

	public static function GetItemsToUnequip( context : ScriptExecutionContext, record : weak< AISubActionCharacterRecordUnequip_Record >, itemsToUnequip : ref< array< NPCItemToEquip > > ) : Bool
	{
		var characterRecord : weak< Character_Record >;
		characterRecord = TweakDBInterface.GetCharacterRecord( ScriptExecutionContext.GetOwner( context ).GetRecordID() );
		if( !( AIActionTransactionSystem.GetEquipmentWithCondition( context, false, true, itemsToUnequip ) ) )
		{
			return AIActionTransactionSystem.GetDefaultEquipment( context, characterRecord, true, itemsToUnequip );
		}
		return true;
	}

}

abstract class AISubActionUnequipOnSlot_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionUnequipOnSlot_Record > )
	{
		var itemsToUnequip : array< NPCItemToEquip >;
		var BBoard : IBlackboard;
		BBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		if( BBoard )
		{
			itemsToUnequip = ( ( array< NPCItemToEquip > )( BBoard.GetVariant( GetAllBlackboardDefs().AIAction.ownerItemsToEquip ) ) );
			if( ( itemsToUnequip.Size() != 0 ) && ( BBoard.GetFloat( GetAllBlackboardDefs().AIAction.ownerEquipDuration ) > 0.0 ) )
			{
				ApplyAnimFeature( context, itemsToUnequip );
			}
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionUnequipOnSlot_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var itemsToUnequip : array< NPCItemToEquip >;
		var BBoard : IBlackboard;
		var equipTime : Float;
		BBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		if( BBoard )
		{
			if( record.UseItemSpawnDelayFromWeapon() )
			{
				itemsToUnequip = ( ( array< NPCItemToEquip > )( BBoard.GetVariant( GetAllBlackboardDefs().AIAction.ownerItemsToEquip ) ) );
				if( itemsToUnequip.Size() != 0 )
				{
					equipTime = BBoard.GetFloat( GetAllBlackboardDefs().AIAction.ownerEquipItemTime );
					if( ( equipTime > 0.0 ) && ( duration > equipTime ) )
					{
						Unequip( context, BBoard.GetBool( GetAllBlackboardDefs().AIAction.dropItemOnUnequip ), itemsToUnequip );
					}
				}
			}
			if( duration < BBoard.GetFloat( GetAllBlackboardDefs().AIAction.ownerEquipDuration ) )
			{
				return AIbehaviorUpdateOutcome.IN_PROGRESS;
			}
		}
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionUnequipOnSlot_Record >, const duration : Float, interrupted : Bool )
	{
		var itemsToUnequip : array< NPCItemToEquip >;
		var BBoard : IBlackboard;
		var i : Int32;
		BBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		if( BBoard )
		{
			itemsToUnequip = ( ( array< NPCItemToEquip > )( BBoard.GetVariant( GetAllBlackboardDefs().AIAction.ownerItemsToEquip ) ) );
			if( itemsToUnequip.Size() > 0 )
			{
				Unequip( context, BBoard.GetBool( GetAllBlackboardDefs().AIAction.dropItemOnUnequip ), itemsToUnequip );
			}
			itemsToUnequip.Clear();
			itemsToUnequip = ( ( array< NPCItemToEquip > )( BBoard.GetVariant( GetAllBlackboardDefs().AIAction.ownerItemsUnequipped ) ) );
			for( i = 0; i < itemsToUnequip.Size(); i += 1 )
			{
				NPCPuppet.SetAnimWrapperBasedOnEquippedItem( ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), itemsToUnequip[ i ].slotID, itemsToUnequip[ i ].itemID, 0.0 );
			}
			AIActionHelper.ClearItemsUnequipped( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ) );
			if( BBoard.GetFloat( GetAllBlackboardDefs().AIAction.ownerEquipDuration ) > 0.0 )
			{
				AnimationControllerComponent.ApplyFeatureToReplicate( ScriptExecutionContext.GetOwner( context ), 'Unequip', new AnimFeature_AIAction );
			}
		}
	}

	public static function Unequip( context : ScriptExecutionContext, dropItem : Bool, itemsToUnequip : array< NPCItemToEquip > ) : Bool
	{
		var i : Int32;
		var equipOnBody : Bool;
		var itemsUnequipped : array< ItemID >;
		var BBoard : IBlackboard;
		equipOnBody = TweakDBInterface.GetBool( T"AIGeneralSettings.displayWeaponsOnBody", equipOnBody );
		if( itemsToUnequip.Size() > 0 )
		{
			BBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
			if( BBoard )
			{
				for( i = 0; i < itemsToUnequip.Size(); i += 1 )
				{
					if( dropItem )
					{
						if( Drop( context, itemsToUnequip[ i ] ) )
						{
							itemsUnequipped.PushBack( itemsToUnequip[ i ].itemID );
						}
					}
					else
					{
						if( TDBID.IsValid( itemsToUnequip[ i ].bodySlotID ) && equipOnBody )
						{
							if( GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).ChangeItemToSlot( ScriptExecutionContext.GetOwner( context ), itemsToUnequip[ i ].bodySlotID, itemsToUnequip[ i ].itemID ) )
							{
								itemsUnequipped.PushBack( itemsToUnequip[ i ].itemID );
							}
						}
						else
						{
							if( GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).RemoveItemFromSlot( ScriptExecutionContext.GetOwner( context ), itemsToUnequip[ i ].slotID, true ) )
							{
								itemsUnequipped.PushBack( itemsToUnequip[ i ].itemID );
							}
						}
					}
				}
				if( itemsUnequipped.Size() > 0 )
				{
					BBoard.SetVariant( GetAllBlackboardDefs().AIAction.ownerLastEquippedItems, itemsUnequipped );
					BBoard.SetVariant( GetAllBlackboardDefs().AIAction.ownerItemsUnequipped, itemsToUnequip );
					BBoard.SetFloat( GetAllBlackboardDefs().AIAction.ownerLastUnequipTimestamp, EngineTime.ToFloat( GameInstance.GetSimTime( ScriptExecutionContext.GetOwner( context ).GetGame() ) ) );
					AIActionHelper.ClearItemsToUnequip( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ) );
					return true;
				}
			}
		}
		return false;
	}

	public static function Drop( context : ScriptExecutionContext, itemToUnequip : NPCItemToEquip ) : Bool
	{
		ScriptedPuppet.DropItemFromSlot( ScriptExecutionContext.GetOwner( context ), itemToUnequip.slotID );
		if( !( GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).RemoveItem( ScriptExecutionContext.GetOwner( context ), itemToUnequip.itemID, 1 ) ) )
		{
			return false;
		}
		return true;
	}

	public static function ApplyAnimFeature( context : ScriptExecutionContext, const itemsToUnequip : ref< array< NPCItemToEquip > > )
	{
		var animFeature : AnimFeature_AIAction;
		var itemID : ItemID;
		var i : Int32;
		animFeature = new AnimFeature_AIAction;
		animFeature.state = 1;
		animFeature.stateDuration = -1.0;
		for( i = 0; i < itemsToUnequip.Size(); i += 1 )
		{
			itemID = itemsToUnequip[ i ].itemID;
			animFeature.animVariation = 0;
			if( GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).HasTag( ScriptExecutionContext.GetOwner( context ), WeaponObject.GetMeleeWeaponTag(), itemID ) )
			{
				animFeature.animVariation = 1;
			}
			AnimationControllerComponent.ApplyFeatureToReplicate( ScriptExecutionContext.GetOwner( context ), 'Unequip', animFeature );
		}
	}

}

abstract class AISubActionForceUnequip_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionForceUnequip_Record > )
	{
		if( record.AttachmentSlot() && ( record.AnimationTime() > 0.0 ) )
		{
			ApplyAnimFeature( context, record );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionForceUnequip_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( ( record.Delay() == 0.0 ) || ( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) ) )
		{
			if( Unequip( context, record ) )
			{
				return AIbehaviorUpdateOutcome.SUCCESS;
			}
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionForceUnequip_Record >, const duration : Float, interrupted : Bool )
	{
		var itemsToUnequip : array< NPCItemToEquip >;
		var BBoard : IBlackboard;
		var i : Int32;
		if( record.UnequipDespiteInterruption() || ( record.Delay() < 0.0 ) )
		{
			Unequip( context, record );
		}
		BBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		if( BBoard )
		{
			itemsToUnequip = ( ( array< NPCItemToEquip > )( BBoard.GetVariant( GetAllBlackboardDefs().AIAction.ownerItemsForceUnequipped ) ) );
			if( itemsToUnequip.Size() > 0 )
			{
				for( i = 0; i < itemsToUnequip.Size(); i += 1 )
				{
					NPCPuppet.SetAnimWrapperBasedOnEquippedItem( ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), itemsToUnequip[ i ].slotID, itemsToUnequip[ i ].itemID, 0.0 );
				}
				AIActionHelper.ClearItemsForceUnequipped( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ) );
			}
		}
		if( record.AnimationTime() > 0.0 )
		{
			AnimationControllerComponent.ApplyFeatureToReplicate( ScriptExecutionContext.GetOwner( context ), 'Unequip', new AnimFeature_AIAction );
		}
	}

	public static function ApplyAnimFeature( context : ScriptExecutionContext, record : weak< AISubActionForceUnequip_Record > )
	{
		var animFeature : AnimFeature_AIAction;
		var itemID : ItemID;
		var itemObj : ItemObject;
		animFeature = new AnimFeature_AIAction;
		animFeature.state = 1;
		if( record.AnimationTime() >= 0.0 )
		{
			animFeature.stateDuration = record.AnimationTime();
		}
		else
		{
			animFeature.stateDuration = -1.0;
		}
		itemObj = GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetItemInSlot( ScriptExecutionContext.GetOwner( context ), record.AttachmentSlot().GetID() );
		if( itemObj )
		{
			itemID = itemObj.GetItemID();
		}
		if( GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).HasTag( ScriptExecutionContext.GetOwner( context ), WeaponObject.GetMeleeWeaponTag(), itemID ) )
		{
			animFeature.animVariation = 1;
		}
		else
		{
			animFeature.animVariation = 0;
		}
		AnimationControllerComponent.ApplyFeatureToReplicate( ScriptExecutionContext.GetOwner( context ), 'Unequip', animFeature );
	}

	public static function Unequip( context : ScriptExecutionContext, record : weak< AISubActionForceUnequip_Record > ) : Bool
	{
		var itemObj : ItemObject;
		var itemID : ItemID;
		var bodySlotID : TweakDBID;
		var result : Bool;
		var equipOnBody : Bool;
		var itemsToUnequip : array< NPCItemToEquip >;
		var itemToUnequip : NPCItemToEquip;
		var BBoard : IBlackboard;
		equipOnBody = TweakDBInterface.GetBool( T"AIGeneralSettings.displayWeaponsOnBody", equipOnBody );
		if( record.AttachmentSlot() )
		{
			itemObj = GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetItemInSlot( ScriptExecutionContext.GetOwner( context ), record.AttachmentSlot().GetID() );
			if( record.DropItem() )
			{
				result = Drop( context, record ) || !( itemObj );
			}
			else
			{
				if( itemObj )
				{
					itemID = itemObj.GetItemID();
					if( equipOnBody && AIActionTransactionSystem.GetItemsBodySlot( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), itemID, bodySlotID ) )
					{
						result = GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).ChangeItemToSlot( ScriptExecutionContext.GetOwner( context ), bodySlotID, itemID );
					}
					else
					{
						result = GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).RemoveItemFromAnySlot( ScriptExecutionContext.GetOwner( context ), itemID );
					}
				}
				else if( !( equipOnBody ) )
				{
					result = GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).RemoveItemFromSlot( ScriptExecutionContext.GetOwner( context ), record.AttachmentSlot().GetID(), true );
				}
			}
		}
		if( result )
		{
			itemToUnequip.itemID = itemID;
			itemToUnequip.slotID = record.AttachmentSlot().GetID();
			BBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
			if( BBoard )
			{
				itemsToUnequip = ( ( array< NPCItemToEquip > )( BBoard.GetVariant( GetAllBlackboardDefs().AIAction.ownerItemsForceUnequipped ) ) );
				itemsToUnequip.PushBack( itemToUnequip );
				BBoard.SetVariant( GetAllBlackboardDefs().AIAction.ownerItemsForceUnequipped, itemsToUnequip );
			}
			return true;
		}
		return false;
	}

	public static function Drop( context : ScriptExecutionContext, record : weak< AISubActionForceUnequip_Record > ) : Bool
	{
		var weapon : ItemObject;
		weapon = GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetItemInSlot( ScriptExecutionContext.GetOwner( context ), record.AttachmentSlot().GetID() );
		ScriptedPuppet.DropItemFromSlot( ScriptExecutionContext.GetOwner( context ), record.AttachmentSlot().GetID() );
		if( weapon )
		{
			if( GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).RemoveItemFromAnySlot( ScriptExecutionContext.GetOwner( context ), weapon.GetItemID(), 1 ) )
			{
				return true;
			}
		}
		return false;
	}

}

abstract class AISubActionDisableAimAssist_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionDisableAimAssist_Record > )
	{
		if( record.Delay() <= 0.0 )
		{
			DisableAimAssist( context, record.Reason() );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionDisableAimAssist_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( duration >= record.Delay() )
		{
			DisableAimAssist( context, record.Reason() );
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionDisableAimAssist_Record >, const duration : Float, interrupted : Bool )
	{
		EnableAimAssist( context );
	}

	public static function EnableAimAssist( context : ScriptExecutionContext )
	{
		var puppet : NPCPuppet;
		puppet = ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		if( puppet.IsAimAssistEnabled() )
		{
			return;
		}
		puppet.QueueEvent( new EnableAimAssist );
	}

	public static function DisableAimAssist( context : ScriptExecutionContext, optional reason : CName )
	{
		var player : PlayerPuppet;
		var puppet : NPCPuppet;
		if( reason == TimeDilationHelper.GetTimeDilationKey() )
		{
			player = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetLocalPlayerMainGameObject() ) );
			if( GameInstance.GetTimeSystem( player.GetGame() ).IsTimeDilationActive() )
			{
				EnableAimAssist( context );
				return;
			}
		}
		puppet = ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		if( !( puppet.IsAimAssistEnabled() ) )
		{
			return;
		}
		puppet.QueueEvent( new DisableAimAssist );
	}

}

abstract class AISubActionApplyTimeDilation_Record_Implementation extends IScriptable
{

	private static function IsConditionFulfilled( context : ScriptExecutionContext, record : weak< AISubActionApplyTimeDilation_Record > ) : Bool
	{
		return !( record.Condition() ) || AICondition.CheckActionCondition( context, record.Condition() );
	}

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionApplyTimeDilation_Record > )
	{
		var blackboard : IBlackboard;
		var player : PlayerPuppet;
		var playerTimeDilation : Float;
		if( !( IsConditionFulfilled( context, record ) ) )
		{
			return;
		}
		if( record.Reason() != TimeDilationHelper.GetSandevistanVersusSandevistanKey() )
		{
			return;
		}
		blackboard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		if( !( blackboard ) )
		{
			return;
		}
		player = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetLocalPlayerMainGameObject() ) );
		if( player )
		{
			playerTimeDilation = 1.0 / GameInstance.GetTimeSystem( player.GetGame() ).GetActiveTimeDilation( TimeDilationHelper.GetSandevistanKey(), true );
			blackboard.SetFloat( GetAllBlackboardDefs().AIAction.ownerGlobalTimeDilation, MinF( playerTimeDilation, record.OverrideMultiplerWhenPlayerInTimeDilation() ) );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionApplyTimeDilation_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( !( IsConditionFulfilled( context, record ) ) )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		SetTimeDilation( context, record );
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionApplyTimeDilation_Record >, const duration : Float, interrupted : Bool )
	{
		var blackboard : IBlackboard;
		var resetTimeDilationEvent : ResetTimeDilation;
		var isGlobalSandevistan : Bool;
		if( !( IsConditionFulfilled( context, record ) ) )
		{
			return;
		}
		blackboard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		if( !( blackboard ) )
		{
			return;
		}
		isGlobalSandevistan = record.Reason() == TimeDilationHelper.GetSandevistanVersusSandevistanKey();
		if( ( blackboard.GetFloat( GetAllBlackboardDefs().AIAction.ownerTimeDilation ) != -1.0 ) && !( ScriptExecutionContext.GetOwner( context ).HasIndividualTimeDilation() ) )
		{
			resetTimeDilationEvent = new ResetTimeDilation;
			resetTimeDilationEvent.easeOut = record.EaseOut();
			resetTimeDilationEvent.global = isGlobalSandevistan;
			ScriptExecutionContext.GetOwner( context ).QueueEvent( resetTimeDilationEvent );
		}
		else
		{
			ScriptExecutionContext.GetOwner( context ).UnsetIndividualTimeDilation( record.EaseOut() );
			blackboard.SetFloat( GetAllBlackboardDefs().AIAction.ownerTimeDilation, -1.0 );
			if( isGlobalSandevistan )
			{
				blackboard.SetFloat( GetAllBlackboardDefs().AIAction.ownerGlobalTimeDilation, -1.0 );
			}
		}
	}

	public static function SetTimeDilation( context : ScriptExecutionContext, record : weak< AISubActionApplyTimeDilation_Record > ) : Bool
	{
		var player : PlayerPuppet;
		var blackboard : IBlackboard;
		var currentDilation : Float;
		var globalDilation : Float;
		var dilation : Float;
		var duration : Float;
		var isGlobalSandevistan : Bool;
		var globalSandevistanActive : Bool;
		var canUsePlayerDilationOverride : Bool;
		if( record.Duration() == 0.0 )
		{
			return false;
		}
		blackboard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		if( !( blackboard ) )
		{
			return false;
		}
		currentDilation = blackboard.GetFloat( GetAllBlackboardDefs().AIAction.ownerTimeDilation );
		globalDilation = blackboard.GetFloat( GetAllBlackboardDefs().AIAction.ownerGlobalTimeDilation );
		isGlobalSandevistan = record.Reason() == TimeDilationHelper.GetSandevistanVersusSandevistanKey();
		if( isGlobalSandevistan )
		{
			dilation = globalDilation;
		}
		else
		{
			player = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetLocalPlayerMainGameObject() ) );
			canUsePlayerDilationOverride = ( ( record.OverrideMultiplerWhenPlayerInTimeDilation() > 0.0 ) && player ) && GameInstance.GetTimeSystem( player.GetGame() ).IsTimeDilationActive();
			if( !( canUsePlayerDilationOverride ) )
			{
				dilation = record.Multiplier();
			}
			else if( globalDilation <= 0.0 )
			{
				dilation = record.OverrideMultiplerWhenPlayerInTimeDilation();
			}
			else
			{
				dilation = MaxF( globalDilation + 1.0, record.OverrideMultiplerWhenPlayerInTimeDilation() );
			}
		}
		if( ( dilation < 0.0 ) || ( dilation == currentDilation ) )
		{
			return false;
		}
		globalSandevistanActive = isGlobalSandevistan || ScriptExecutionContext.GetOwner( context ).HasIndividualTimeDilation( TimeDilationHelper.GetSandevistanVersusSandevistanKey() );
		if( globalSandevistanActive && ( dilation < currentDilation ) )
		{
			return false;
		}
		blackboard.SetFloat( GetAllBlackboardDefs().AIAction.ownerTimeDilation, dilation );
		if( ScriptExecutionContext.GetOwner( context ).HasIndividualTimeDilation() )
		{
			ScriptExecutionContext.GetOwner( context ).UnsetIndividualTimeDilation();
		}
		duration = ( ( record.Duration() < 0.0 ) ? ( 600.0 ) : ( record.Duration() * dilation ) );
		ScriptExecutionContext.GetOwner( context ).SetIndividualTimeDilation( record.Reason(), dilation, duration, record.EaseIn(), record.EaseOut(), false, record.UseRealTime() );
		return true;
	}

}

abstract class AISubActionModifyStatPool_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionModifyStatPool_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			ModifyStatPool( context, record );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionModifyStatPool_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			ModifyStatPool( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionModifyStatPool_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			ModifyStatPool( context, record );
		}
	}

	public static function ModifyStatPool( context : ScriptExecutionContext, record : weak< AISubActionModifyStatPool_Record > )
	{
		if( record.StatPool() && ( record.Amount() != 0.0 ) )
		{
			GameInstance.GetStatPoolsSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).RequestChangingStatPoolValue( ScriptExecutionContext.GetOwner( context ).GetEntityID(), record.StatPool().StatPoolType(), record.Amount(), NULL, false, record.Perc() );
		}
	}

}

abstract class AISubActionForceDeath_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionForceDeath_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			ForceDeath( context, record );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionForceDeath_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			ForceDeath( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionForceDeath_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			ForceDeath( context, record );
		}
	}

	public static function ForceDeath( context : ScriptExecutionContext, record : weak< AISubActionForceDeath_Record > )
	{
		var forcedDeathEvent : ForcedDeathEvent;
		forcedDeathEvent = new ForcedDeathEvent;
		forcedDeathEvent.hitIntensity = record.HitIntensity();
		forcedDeathEvent.hitSource = record.HitSource();
		forcedDeathEvent.hitBodyPart = record.HitBodyPart();
		forcedDeathEvent.hitDirection = record.HitDirection();
		ScriptExecutionContext.GetOwner( context ).QueueEvent( forcedDeathEvent );
	}

}

abstract class AISubActionStatusEffect_Record_Implementation extends IScriptable
{

	private static function IsConditionFulfilled( context : ScriptExecutionContext, record : weak< AISubActionStatusEffect_Record > ) : Bool
	{
		return !( record.Condition() ) || AICondition.CheckActionCondition( context, record.Condition() );
	}

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionStatusEffect_Record > )
	{
		if( ( record.Delay() == 0.0 ) && IsConditionFulfilled( context, record ) )
		{
			ApplyRemoveStatusEffect( context, record );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionStatusEffect_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( !( IsConditionFulfilled( context, record ) ) )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			ApplyRemoveStatusEffect( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionStatusEffect_Record >, const duration : Float, interrupted : Bool )
	{
		if( !( IsConditionFulfilled( context, record ) ) )
		{
			return;
		}
		if( record.Delay() < 0.0 )
		{
			ApplyRemoveStatusEffect( context, record );
		}
		else if( record.Remove() )
		{
			RemoveStatusEffect( context, record );
		}
	}

	public static function ApplyRemoveStatusEffect( context : ScriptExecutionContext, record : weak< AISubActionStatusEffect_Record > )
	{
		if( record.Apply() )
		{
			ApplyStatusEffect( context, record );
		}
		else if( record.Remove() )
		{
			RemoveStatusEffect( context, record );
		}
	}

	public static function ApplyStatusEffect( context : ScriptExecutionContext, record : weak< AISubActionStatusEffect_Record > )
	{
		var i : Int32;
		var count : Int32;
		var target : weak< GameObject >;
		if( !( AIActionTarget.GetObject( context, record.Target(), target ) ) )
		{
			return;
		}
		count = record.GetStatusEffectsCount();
		for( i = 0; i < count; i += 1 )
		{
			GameInstance.GetStatusEffectSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).ApplyStatusEffect( target.GetEntityID(), record.GetStatusEffectsItem( i ).GetID() );
		}
	}

	public static function RemoveStatusEffect( context : ScriptExecutionContext, record : weak< AISubActionStatusEffect_Record > )
	{
		var i : Int32;
		var count : Int32;
		var target : weak< GameObject >;
		if( !( AIActionTarget.GetObject( context, record.Target(), target ) ) )
		{
			return;
		}
		count = record.GetStatusEffectsCount();
		for( i = 0; i < count; i += 1 )
		{
			GameInstance.GetStatusEffectSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).RemoveStatusEffect( target.GetEntityID(), record.GetStatusEffectsItem( i ).GetID() );
		}
	}

}

abstract class AISubActionGameplayLogicPackage_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionGameplayLogicPackage_Record > )
	{
		ApplyGameplayLogicPackage( context, record );
	}

	public constexpr static function Update( context : ScriptExecutionContext, record : weak< AISubActionGameplayLogicPackage_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionGameplayLogicPackage_Record >, const duration : Float, interrupted : Bool )
	{
		RemoveGameplayLogicPackage( context, record );
	}

	public static function ApplyGameplayLogicPackage( context : ScriptExecutionContext, record : weak< AISubActionGameplayLogicPackage_Record > )
	{
		var i : Int32;
		var count : Int32;
		count = record.GetPackagesCount();
		for( i = 0; i < count; i += 1 )
		{
			GameInstance.GetGameplayLogicPackageSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).ApplyPackage( ScriptExecutionContext.GetOwner( context ), ScriptExecutionContext.GetOwner( context ), record.GetPackagesItem( i ).GetID() );
		}
	}

	public static function RemoveGameplayLogicPackage( context : ScriptExecutionContext, record : weak< AISubActionGameplayLogicPackage_Record > )
	{
		var i : Int32;
		var count : Int32;
		count = record.GetPackagesCount();
		for( i = 0; i < count; i += 1 )
		{
			GameInstance.GetGameplayLogicPackageSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).RemovePackage( ScriptExecutionContext.GetOwner( context ), record.GetPackagesItem( i ).GetID() );
		}
	}

}

abstract class AISubActionSetInt_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionSetInt_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			ScriptExecutionContext.SetArgumentInt( context, record.Name(), record.Value() );
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionSetInt_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			ScriptExecutionContext.SetArgumentInt( context, record.Name(), record.Value() );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionSetInt_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			ScriptExecutionContext.SetArgumentInt( context, record.Name(), record.Value() );
		}
	}

}

abstract class AISubActionReloadWeapon_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionReloadWeapon_Record > )
	{
		var weapon : weak< WeaponObject >;
		if( !( GetWeapon( context, record, weapon ) ) )
		{
			return;
		}
		weapon.StartReload( record.Duration() );
		WeaponObject.TriggerWeaponEffects( weapon, gamedataFxAction.EnterReload );
		AnimationControllerComponent.PushEventToReplicate( weapon, 'Reload' );
		AnimationControllerComponent.PushEventToReplicate( ScriptExecutionContext.GetOwner( context ), 'Reload' );
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionReloadWeapon_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var weapon : weak< WeaponObject >;
		if( !( GetWeapon( context, record, weapon ) ) )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( duration >= record.Duration() )
		{
			weapon.StopReload( gameweaponReloadStatus.Standard );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionReloadWeapon_Record >, const duration : Float, interrupted : Bool )
	{
		var weapon : weak< WeaponObject >;
		if( ( duration < record.Duration() ) && GetWeapon( context, record, weapon ) )
		{
			weapon.StopReload( gameweaponReloadStatus.Interrupted );
			WeaponObject.TriggerWeaponEffects( weapon, gamedataFxAction.ExitReload );
			WeaponObject.SendAmmoUpdateEvent( ScriptExecutionContext.GetOwner( context ), weapon );
			AnimationControllerComponent.PushEventToReplicate( weapon, 'InterruptReload' );
			AnimationControllerComponent.PushEventToReplicate( ScriptExecutionContext.GetOwner( context ), 'InterruptReload' );
		}
	}

	public static function GetWeapon( context : ScriptExecutionContext, record : weak< AISubActionReloadWeapon_Record >, out weapon : weak< WeaponObject > ) : Bool
	{
		weapon = ( ( WeaponObject )( GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetItemInSlot( ScriptExecutionContext.GetOwner( context ), record.WeaponSlot().GetID() ) ) );
		return weapon != NULL;
	}

}

abstract class AISubActionTriggerStim_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionTriggerStim_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			TriggerStim( context, record );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionTriggerStim_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			TriggerStim( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionTriggerStim_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			TriggerStim( context, record );
		}
	}

	public static function TriggerStim( context : ScriptExecutionContext, record : weak< AISubActionTriggerStim_Record > )
	{
		var sourceObj : weak< GameObject >;
		var directTarget : weak< GameObject >;
		var broadcaster : StimBroadcasterComponent;
		if( AIActionTarget.GetObject( context, record.StimSource(), sourceObj ) )
		{
			broadcaster = sourceObj.GetStimBroadcasterComponent();
			if( broadcaster )
			{
				if( record.Direct() )
				{
					if( AIActionTarget.GetObject( context, record.Target(), directTarget ) )
					{
						broadcaster.SendDrirectStimuliToTarget( ScriptExecutionContext.GetOwner( context ), record.StimType().Type(), directTarget, , , record.PurelyDirect() );
					}
				}
				else
				{
					broadcaster.TriggerSingleBroadcast( ScriptExecutionContext.GetOwner( context ), record.StimType().Type(), record.Radius() );
				}
			}
		}
	}

}

abstract class AISubActionChangeAttitude_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionChangeAttitude_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			ChangeAttitude( context, record );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionChangeAttitude_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			ChangeAttitude( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionChangeAttitude_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			ChangeAttitude( context, record );
		}
	}

	public static function ChangeAttitude( context : ScriptExecutionContext, record : weak< AISubActionChangeAttitude_Record > )
	{
		var attitudeOwner : AttitudeAgent;
		var attitudeTarget : AttitudeAgent;
		var target : weak< GameObject >;
		var desiredAttitude : EAIAttitude;
		if( !( AIActionTarget.GetObject( context, record.Target(), target ) ) )
		{
			return;
		}
		desiredAttitude = ( ( EAIAttitude )( ( ( Int32 )( EnumValueFromName( 'EAIAttitude', record.Attitude() ) ) ) ) );
		if( desiredAttitude == EAIAttitude.AIA_Hostile )
		{
			AIActionHelper.TryChangingAttitudeToHostile( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), target );
			return;
		}
		attitudeOwner = ScriptExecutionContext.GetOwner( context ).GetAttitudeAgent();
		attitudeTarget = target.GetAttitudeAgent();
		if( ( attitudeOwner && attitudeTarget ) && attitudeOwner.GetAttitudeTowards( attitudeTarget ) != desiredAttitude )
		{
			attitudeOwner.SetAttitudeTowardsAgentGroup( attitudeTarget, attitudeOwner, desiredAttitude );
		}
	}

}

abstract class AISubActionThrowItem_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionThrowItem_Record > )
	{
		if( record.Delay() > 0.0 )
		{
			ThrowInit( context, record );
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionThrowItem_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( ( record.Delay() <= 0.0 ) || ( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) ) )
		{
			if( ThrowItem( context, record ) )
			{
				return AIbehaviorUpdateOutcome.SUCCESS;
			}
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionThrowItem_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			ThrowItem( context, record );
		}
		if( ( record.Delay() > 0.0 ) && ScriptExecutionContext.GetOwner( context ).IsNPC() )
		{
			( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().NULLCachedThrowGrenadeAtTargetQuery();
		}
		if( record.DropItemOnInterruption() )
		{
			DropItem( context, record );
		}
	}

	public static function ThrowInit( context : ScriptExecutionContext, record : weak< AISubActionThrowItem_Record > )
	{
		var target : weak< GameObject >;
		if( record.Target() && !( AIActionTarget.GetObject( context, record.Target(), target ) ) )
		{
			return;
		}
		if( target && ScriptExecutionContext.GetOwner( context ).IsNPC() )
		{
			( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().CacheThrowGrenadeAtTargetQuery( target );
		}
	}

	public static function GetCachedGrenadeQuery( context : ScriptExecutionContext, out targetPosition : Vector4, out throwAngle : Float, outStartType : gameGrenadeThrowStartType ) : Bool
	{
		if( !( ScriptExecutionContext.GetOwner( context ).IsNPC() ) )
		{
			return false;
		}
		throwAngle = ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetCombatGadgetBlackboard().GetFloat( GetAllBlackboardDefs().CombatGadget.lastThrowAngle );
		if( throwAngle == 0.0 )
		{
			return false;
		}
		outStartType = ( ( gameGrenadeThrowStartType )( ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetCombatGadgetBlackboard().GetVariant( GetAllBlackboardDefs().CombatGadget.lastThrowStartType ) ) );
		if( outStartType == gameGrenadeThrowStartType.Invalid )
		{
			return false;
		}
		targetPosition = ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetCombatGadgetBlackboard().GetVector4( GetAllBlackboardDefs().CombatGadget.lastThrowPosition );
		return true;
	}

	public static function ThrowItem( context : ScriptExecutionContext, record : weak< AISubActionThrowItem_Record > ) : Bool
	{
		var ownerPosition : Vector4;
		var targetPosition : Vector4;
		var targetVelocity : Vector4;
		var target : weak< GameObject >;
		var throwAngle : Float;
		var distanceToTarget : Float;
		var startType : gameGrenadeThrowStartType;
		var item : weak< ItemObject >;
		var launchEvent : gameprojectileSetUpAndLaunchEvent;
		var isGrenade : Bool;
		var isNPCThrowableKnife : Bool;
		var angleToTarget : Float;
		var ownerPuppet : gamePuppet;
		var throwableKnife : ThrowableKnifeNPC;
		if( !( record.AttachmentSlot() ) || !( record.Target() ) )
		{
			return false;
		}
		ownerPuppet = ScriptExecutionContext.GetOwner( context );
		item = GameInstance.GetTransactionSystem( ownerPuppet.GetGame() ).GetItemInSlot( ownerPuppet, record.AttachmentSlot().GetID() );
		if( !( item ) )
		{
			return false;
		}
		if( record.Target() && !( AIActionTarget.Get( context, record.Target(), false, target, targetPosition ) ) )
		{
			return false;
		}
		isGrenade = ( ( BaseGrenade )( item ) ) != NULL;
		isNPCThrowableKnife = ( ( ThrowableKnifeNPC )( item ) ) != NULL;
		if( isGrenade )
		{
			( ( ScriptedPuppet )( ownerPuppet ) ).GetAIControllerComponent().GetActionBlackboard().SetFloat( GetAllBlackboardDefs().AIAction.lastGrenadeThrowTimestamp, EngineTime.ToFloat( ScriptExecutionContext.GetAITime( context ) ) );
		}
		if( isGrenade || isNPCThrowableKnife )
		{
			if( ( !( GetCachedGrenadeQuery( context, targetPosition, throwAngle, startType ) ) && target ) && ownerPuppet.IsNPC() )
			{
				if( record.CheckThrowQuery() && !( ( ( NPCPuppet )( ownerPuppet ) ).GetAIControllerComponent().CanThrowGrenadeAtTarget( target, targetPosition, throwAngle, startType ) ) )
				{
					return false;
				}
			}
			if( !( target ) )
			{
				throwAngle = record.ThrowAngle();
			}
			else if( IsNameValid( record.ThrowType() ) )
			{
				if( record.ThrowType() == 'smoke_defensive' )
				{
					ownerPosition = ownerPuppet.GetWorldPosition();
					targetPosition = target.GetWorldPosition();
					if( ( ownerPosition.Z - targetPosition.Z ) > 1.0 )
					{
						distanceToTarget = Vector4.Distance( targetPosition, ownerPosition );
						targetPosition = ownerPosition + Vector4.ClampLength( targetPosition - ownerPosition, 2.5, distanceToTarget - 4.0 );
					}
					else
					{
						targetPosition = ownerPosition + Vector4.ClampLength( targetPosition - ownerPosition, 0.0, 2.5 );
					}
				}
				else if( record.ThrowType() == 'smoke_offensive' )
				{
					ownerPosition = ownerPuppet.GetWorldPosition();
					targetPosition = target.GetWorldPosition();
					distanceToTarget = Vector4.Distance( targetPosition, ownerPosition );
					targetPosition = ownerPosition + Vector4.ClampLength( targetPosition - ownerPosition, 2.5, distanceToTarget - 4.0 );
				}
			}
			SetNPCThrowingGrenade( context );
		}
		else
		{
			ScriptExecutionContext.SetArgumentObject( context, 'TargetItem', item );
			throwAngle = record.ThrowAngle();
			targetPosition = ownerPuppet.GetWorldPosition() + ( ownerPuppet.GetWorldForward() * 15.0 );
			if( target )
			{
				angleToTarget = Vector4.GetAngleDegAroundAxis( target.GetWorldPosition() - ownerPuppet.GetWorldPosition(), ownerPuppet.GetWorldForward(), ownerPuppet.GetWorldUp() );
				if( AbsF( angleToTarget ) <= 70.0 )
				{
					AIActionHelper.GetTargetSlotPosition( target, 'Chest', targetPosition );
					if( ( record.PositionPredictionTime() > 0.0 ) && ( ( gamePuppet )( target ) ) )
					{
						targetVelocity = ( ( gamePuppet )( target ) ).GetVelocity();
						targetVelocity.Z = 0.0;
						targetPosition += ( Vector4.ClampLength( targetVelocity, 0.0, 4.5 ) * record.PositionPredictionTime() );
					}
				}
			}
			targetPosition = ownerPuppet.GetWorldPosition() + Vector4.ClampLength( targetPosition - ownerPuppet.GetWorldPosition(), 7.5, 20.0 );
		}
		launchEvent = new gameprojectileSetUpAndLaunchEvent;
		launchEvent.launchParams.launchMode = gameprojectileELaunchMode.FromVisuals;
		launchEvent.launchParams.logicalPositionProvider = IPositionProvider.CreateEntityPositionProvider( item );
		launchEvent.launchParams.logicalOrientationProvider = IOrientationProvider.CreateEntityOrientationProvider( NULL, '', ownerPuppet );
		launchEvent.launchParams.visualPositionProvider = IPositionProvider.CreateEntityPositionProvider( item );
		launchEvent.launchParams.visualOrientationProvider = IOrientationProvider.CreateEntityOrientationProvider( NULL, '', item );
		launchEvent.launchParams.ownerVelocityProvider = MoveComponentVelocityProvider.CreateMoveComponentVelocityProvider( ownerPuppet );
		launchEvent.lerpMultiplier = 15.0;
		launchEvent.owner = ownerPuppet;
		if( isNPCThrowableKnife )
		{
			throwableKnife = ( ( ThrowableKnifeNPC )( item ) );
			if( throwableKnife.isFollowingKnife() )
			{
				launchEvent.trajectoryParams = CreateCurvedTrajectoryFollowTargetSlot( target, 'Chest', T"projectile.npc_throwable_knife_params" );
			}
			else
			{
				launchEvent.trajectoryParams = CreateCurvedTrajectory( target, T"projectile.npc_throwable_knife_params", record.PositionPredictionTime() );
			}
		}
		else
		{
			launchEvent.trajectoryParams = CreateParabolicTrajectory( record, targetPosition, throwAngle );
		}
		launchEvent.projectileParams.shootingOffset = 2.0;
		if( isGrenade || isNPCThrowableKnife )
		{
			item.QueueEvent( launchEvent );
			GameInstance.GetTransactionSystem( ownerPuppet.GetGame() ).RemoveItemFromSlot( ownerPuppet, record.AttachmentSlot().GetID(), false );
		}
		else
		{
			GameInstance.GetTransactionSystem( ownerPuppet.GetGame() ).ThrowItem( ownerPuppet, item, launchEvent );
		}
		return true;
	}

	private static function CreateParabolicTrajectory( record : weak< AISubActionThrowItem_Record >, targetPosition : Vector4, throwAngle : Float ) : gameprojectileTrajectoryParams
	{
		return ParabolicTrajectoryParams.GetAccelTargetAngleParabolicParams( Vector4( 0.0, 0.0, record.TrajectoryGravity(), 0.0 ), targetPosition, throwAngle );
	}

	private static function CreateCurvedTrajectory( target : weak< GameObject >, paramsTDBRecord : TweakDBID, predictionTime : Float ) : gameprojectileTrajectoryParams
	{
		var trajectoryParams : FollowCurveTrajectoryParams;
		var targetPosition : Vector4;
		var targetVelocity : Vector4;
		AIActionHelper.GetTargetSlotPosition( target, 'Chest', targetPosition );
		trajectoryParams = new FollowCurveTrajectoryParams;
		ReadCurvedTrajectoryTDBParams( trajectoryParams, paramsTDBRecord );
		if( ( predictionTime > 0.0 ) && ( ( gamePuppet )( target ) ) )
		{
			targetVelocity = ( ( gamePuppet )( target ) ).GetVelocity();
			targetVelocity.Z = 0.0;
			targetPosition += ( Vector4.ClampLength( targetVelocity, 0.0, 4.5 ) * predictionTime );
		}
		trajectoryParams.targetPosition = targetPosition;
		return trajectoryParams;
	}

	private static function CreateCurvedTrajectoryFollowTargetSlot( target : weak< GameObject >, slotName : CName, paramsTDBRecord : TweakDBID ) : gameprojectileTrajectoryParams
	{
		var trajectoryParams : FollowCurveTrajectoryParams;
		trajectoryParams = new FollowCurveTrajectoryParams;
		ReadCurvedTrajectoryTDBParams( trajectoryParams, paramsTDBRecord );
		trajectoryParams.target = target;
		trajectoryParams.targetSlotName = slotName;
		return trajectoryParams;
	}

	private static function ReadCurvedTrajectoryTDBParams( out trajectoryParams : FollowCurveTrajectoryParams, paramsTDBRecord : TweakDBID )
	{
		trajectoryParams.startVelocity = TDB.GetFloat( paramsTDBRecord + T".startVelocity", -1.0 );
		trajectoryParams.linearTimeRatio = TDB.GetFloat( paramsTDBRecord + T".linearTimeRatio", -1.0 );
		trajectoryParams.interpolationTimeRatio = TDB.GetFloat( paramsTDBRecord + T".interpolationTimeRatio", -1.0 );
		trajectoryParams.returnTimeMargin = TDB.GetFloat( paramsTDBRecord + T".returnTimeMargin", -1.0 );
		trajectoryParams.bendTimeRatio = TDB.GetFloat( paramsTDBRecord + T".bendTimeRatio", -1.0 );
		trajectoryParams.bendFactor = TDB.GetFloat( paramsTDBRecord + T".bendFactor", -1.0 );
		trajectoryParams.halfLeanAngle = TDB.GetFloat( paramsTDBRecord + T".halfLeanAngle", -1.0 );
		trajectoryParams.endLeanAngle = TDB.GetFloat( paramsTDBRecord + T".endLeanAngle", -1.0 );
		trajectoryParams.angleInterpolationDuration = TDB.GetFloat( paramsTDBRecord + T".angleInterpolationDuration", -1.0 );
		trajectoryParams.angleInHitPlane = TDB.GetFloat( paramsTDBRecord + T".angleInHitPlane", 30.0 );
		trajectoryParams.angleInVerticalPlane = TDB.GetFloat( paramsTDBRecord + T".angleInVerticalPlane", 0.0 );
		trajectoryParams.accuracy = TDB.GetFloat( paramsTDBRecord + T".accuracy", -1.0 );
	}

	public static function DropItem( context : ScriptExecutionContext, record : weak< AISubActionThrowItem_Record > )
	{
		var dir : Vector4;
		var rot : EulerAngles;
		var orientation : Quaternion;
		var item : weak< ItemObject >;
		var launchEvent : gameprojectileSetUpAndLaunchEvent;
		var ownerPuppet : gamePuppet;
		if( !( record.AttachmentSlot() ) )
		{
			return;
		}
		ownerPuppet = ScriptExecutionContext.GetOwner( context );
		item = GameInstance.GetTransactionSystem( ownerPuppet.GetGame() ).GetItemInSlot( ownerPuppet, record.AttachmentSlot().GetID() );
		if( !( item ) )
		{
			return;
		}
		launchEvent = new gameprojectileSetUpAndLaunchEvent;
		dir = ownerPuppet.GetWorldUp() * -1.0;
		rot = Vector4.ToRotation( dir );
		orientation = EulerAngles.ToQuat( rot );
		launchEvent.launchParams.logicalPositionProvider = IPositionProvider.CreateEntityPositionProvider( item );
		launchEvent.launchParams.logicalOrientationProvider = IOrientationProvider.CreateStaticOrientationProvider( orientation );
		Quaternion.SetIdentity( orientation );
		launchEvent.launchParams.visualPositionProvider = IPositionProvider.CreateEntityPositionProvider( item );
		launchEvent.launchParams.visualOrientationProvider = IOrientationProvider.CreateStaticOrientationProvider( orientation );
		launchEvent.launchParams.ownerVelocityProvider = MoveComponentVelocityProvider.CreateMoveComponentVelocityProvider( ownerPuppet );
		launchEvent.owner = ownerPuppet;
		launchEvent.trajectoryParams = ParabolicTrajectoryParams.GetAccelVelParabolicParams( Vector4( 0.0, 0.0, -9.80000019, 0.0 ), 0.1 );
		item.QueueEvent( launchEvent );
		GameInstance.GetTransactionSystem( ownerPuppet.GetGame() ).RemoveItemFromSlot( ownerPuppet, record.AttachmentSlot().GetID(), false );
	}

	protected static function SetNPCThrowingGrenade( context : ScriptExecutionContext )
	{
		var throwingGrenadeEvent : NPCThrowingGrenadeEvent;
		var combatTarget : weak< GameObject >;
		combatTarget = ScriptExecutionContext.GetArgumentObject( context, 'CombatTarget' );
		if( combatTarget )
		{
			throwingGrenadeEvent = new NPCThrowingGrenadeEvent;
			throwingGrenadeEvent.target = combatTarget;
			ScriptExecutionContext.GetOwner( context ).QueueEvent( throwingGrenadeEvent );
		}
	}

}

abstract class AISubActionTriggerItemActivation_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionTriggerItemActivation_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			TriggerActivation( context, record );
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionTriggerItemActivation_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			TriggerActivation( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionTriggerItemActivation_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			TriggerActivation( context, record );
		}
	}

	public static function TriggerActivation( context : ScriptExecutionContext, record : weak< AISubActionTriggerItemActivation_Record > )
	{
		var item : weak< ItemObject >;
		var launchEvent : gameprojectileSetUpAndLaunchEvent;
		var forceActivationEvent : gameprojectileForceActivationEvent;
		var ownerPuppet : gamePuppet;
		var orientation : Quaternion;
		if( !( record.AttachmentSlot() ) )
		{
			return;
		}
		ownerPuppet = ScriptExecutionContext.GetOwner( context );
		item = GameInstance.GetTransactionSystem( ownerPuppet.GetGame() ).GetItemInSlot( ownerPuppet, record.AttachmentSlot().GetID() );
		if( !( item ) )
		{
			return;
		}
		launchEvent = new gameprojectileSetUpAndLaunchEvent;
		forceActivationEvent = new gameprojectileForceActivationEvent;
		GameInstance.GetTransactionSystem( ownerPuppet.GetGame() ).RemoveItemFromSlot( ownerPuppet, record.AttachmentSlot().GetID(), false );
		launchEvent.launchParams.logicalPositionProvider = IPositionProvider.CreateEntityPositionProvider( item );
		launchEvent.launchParams.logicalOrientationProvider = IOrientationProvider.CreateEntityOrientationProvider( NULL, '', ownerPuppet );
		launchEvent.launchParams.visualPositionProvider = IPositionProvider.CreateEntityPositionProvider( item );
		Quaternion.SetIdentity( orientation );
		launchEvent.launchParams.visualOrientationProvider = IOrientationProvider.CreateStaticOrientationProvider( orientation );
		launchEvent.launchParams.ownerVelocityProvider = MoveComponentVelocityProvider.CreateMoveComponentVelocityProvider( ownerPuppet );
		launchEvent.owner = ownerPuppet;
		item.QueueEvent( launchEvent );
		item.QueueEvent( forceActivationEvent );
		return;
	}

}

abstract class AISubActionAttackWithWeapon_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionAttackWithWeapon_Record > )
	{
		if( record.AttackTime() == 0.0 )
		{
			AttackWithWeapon( context, record );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionAttackWithWeapon_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var weapon : weak< WeaponObject >;
		if( ( record.StopContinuousAttackOnDurationEnd() && GetWeapon( context, record, weapon ) ) && weapon.IsContinuousAttackStarted() )
		{
			if( duration >= ( record.AttackTime() + record.AttackDuration() ) )
			{
				GameObject.ToggleForcedVisibilityInAnimSystemEvent( ScriptExecutionContext.GetOwner( context ), 'ContinuousAttack', false );
				GameObject.ToggleForcedVisibilityInAnimSystemEvent( weapon, 'ContinuousAttack', false );
				weapon.StopContinuousAttack();
				return AIbehaviorUpdateOutcome.SUCCESS;
			}
		}
		else if( record.AttackTime() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		else if( duration >= record.AttackTime() )
		{
			return AttackWithWeapon( context, record );
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionAttackWithWeapon_Record >, const duration : Float, interrupted : Bool )
	{
		var weapon : weak< WeaponObject >;
		if( record.AttackTime() < 0.0 )
		{
			AttackWithWeapon( context, record );
		}
		if( GetWeapon( context, record, weapon ) && weapon.IsContinuousAttackStarted() )
		{
			weapon.StopContinuousAttack();
			GameObject.ToggleForcedVisibilityInAnimSystemEvent( ScriptExecutionContext.GetOwner( context ), 'ContinuousAttack', false );
			GameObject.ToggleForcedVisibilityInAnimSystemEvent( weapon, 'ContinuousAttack', false );
		}
	}

	public static function AttackWithWeapon( context : ScriptExecutionContext, record : weak< AISubActionAttackWithWeapon_Record > ) : AIbehaviorUpdateOutcome
	{
		var weapon : weak< WeaponObject >;
		var attack : weak< Attack_GameEffect >;
		var continuousAttack : weak< Attack_Continuous >;
		var effect : weak< EffectInstance >;
		var weaponType : gamedataItemType;
		var isQuickMelee : Bool;
		if( !( GetWeapon( context, record, weapon ) ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		weapon.QueueEventForEntityID( weapon.GetEntityID(), new SetWeaponOwnerEvent );
		if( record.Attack() && !( weapon.SetAttack( record.Attack().GetID() ) ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		attack = ( ( Attack_GameEffect )( weapon.GetCurrentAttack() ) );
		if( !( attack ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		continuousAttack = ( ( Attack_Continuous )( attack ) );
		if( continuousAttack )
		{
			PrepareContinuousAttack( weapon );
			effect = continuousAttack.GetRunningContinuousEffect();
			if( !( effect ) )
			{
				return AIbehaviorUpdateOutcome.FAILURE;
			}
			FillEffectData( context, record, attack, effect );
			StartPreparedContinuousAttack( context, weapon );
			SetAttackNameInBlackBoard( context, record.AttackName() );
			return AIbehaviorUpdateOutcome.IN_PROGRESS;
		}
		effect = attack.PrepareAttack( ScriptExecutionContext.GetOwner( context ) );
		if( !( effect ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		if( weapon.IsMelee() )
		{
			weapon.AI_SetAttackData( attack );
		}
		FillEffectData( context, record, attack, effect );
		attack.StartAttack();
		SetAttackNameInBlackBoard( context, record.AttackName() );
		weaponType = WeaponObject.GetWeaponType( weapon.GetItemID() );
		switch( weaponType )
		{
			case gamedataItemType.Wea_Axe:
			case gamedataItemType.Wea_Chainsword:
			case gamedataItemType.Wea_Fists:
			case gamedataItemType.Wea_Knife:
			case gamedataItemType.Wea_Machete:
			case gamedataItemType.Wea_Melee:
			case gamedataItemType.Wea_Hammer:
			case gamedataItemType.Wea_Katana:
			case gamedataItemType.Wea_Sword:
			case gamedataItemType.Wea_LongBlade:
			case gamedataItemType.Wea_OneHandedClub:
			case gamedataItemType.Wea_ShortBlade:
			case gamedataItemType.Wea_TwoHandedClub:
				isQuickMelee = false;
			break;
			default:
				isQuickMelee = true;
			break;
		}
		weapon.AI_PlayMeleeAttackSound( isQuickMelee );
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

	public static function PrepareContinuousAttack( weapon : weak< WeaponObject > )
	{
		weapon.PrepareContinuousAttack( weapon.GetWorldPosition(), weapon.GetWorldForward() );
	}

	public static function StartPreparedContinuousAttack( context : ScriptExecutionContext, weapon : weak< WeaponObject > )
	{
		weapon.StartPreparedContinuousAttack();
		GameObject.ToggleForcedVisibilityInAnimSystemEvent( weapon, 'ContinuousAttack', true );
		GameObject.ToggleForcedVisibilityInAnimSystemEvent( ScriptExecutionContext.GetOwner( context ), 'ContinuousAttack', true );
	}

	public static function StartContinuousAttack( context : ScriptExecutionContext, weapon : weak< WeaponObject > )
	{
		PrepareContinuousAttack( weapon );
		StartPreparedContinuousAttack( context, weapon );
	}

	public static function FillEffectData( context : ScriptExecutionContext, record : weak< AISubActionAttackWithWeapon_Record >, attack : weak< Attack_GameEffect >, effect : weak< EffectInstance > )
	{
		var startPosition : Vector4;
		var endPosition : Vector4;
		var yOffset : Float;
		var attackStartPositionWorld : Vector4;
		var attackEndPositionWorld : Vector4;
		var attackDirectionWorld : Vector4;
		var attackTransform : Transform;
		var colliderBoxSizeV3 : Vector3;
		var colliderBoxSizeV4 : Vector4;
		var positionOffset : Vector4;
		var position : Vector4;
		var rotation : Quaternion;
		var direction : Vector4;
		var range : Float;
		var axisConstraints : Vector4;
		var meleeAttackRecord : weak< Attack_Melee_Record >;
		var attackDirection : gamedataMeleeAttackDirection;
		meleeAttackRecord = ( ( Attack_Melee_Record )( record.Attack() ) );
		if( !( meleeAttackRecord ) )
		{
			return;
		}
		range = record.AttackRange();
		if( range < 0.0 )
		{
			range = attack.GetRecord().Range();
		}
		colliderBoxSizeV3 = record.ColliderBoxSize();
		if( colliderBoxSizeV3.Y <= 0.0 )
		{
			colliderBoxSizeV4 = Vector4( colliderBoxSizeV3.X, range * 0.5, colliderBoxSizeV3.Z, 0.0 );
		}
		else
		{
			colliderBoxSizeV4 = Vector4( colliderBoxSizeV3.X, colliderBoxSizeV3.Y, colliderBoxSizeV3.Z, 0.0 );
		}
		yOffset = ( colliderBoxSizeV4.Y * 0.5 ) + 0.1;
		Transform.SetPosition( attackTransform, ScriptExecutionContext.GetOwner( context ).GetWorldPosition() );
		attackTransform.position.Z += 1.5;
		Transform.SetOrientationFromDir( attackTransform, ScriptExecutionContext.GetOwner( context ).GetWorldForward() );
		attackDirection = meleeAttackRecord.AttackDirection().Direction().Type();
		if( attackDirection == gamedataMeleeAttackDirection.Center )
		{
			startPosition = Vector4( 0.0, yOffset, 0.0, 0.0 );
			endPosition = Vector4( 0.0, 0.0, 0.0, 0.0 );
		}
		else if( attackDirection == gamedataMeleeAttackDirection.DownToUp )
		{
			startPosition = Vector4( 0.0, yOffset, -0.5, 0.0 );
			endPosition = Vector4( 0.0, 0.0, 0.30000001, 0.0 );
		}
		else if( attackDirection == gamedataMeleeAttackDirection.LeftDownToRightUp )
		{
			startPosition = Vector4( -0.5, yOffset, -0.5, 0.0 );
			endPosition = Vector4( 0.5, 0.0, 0.30000001, 0.0 );
		}
		else if( attackDirection == gamedataMeleeAttackDirection.LeftToRight )
		{
			startPosition = Vector4( -0.5, yOffset, 0.0, 0.0 );
			endPosition = Vector4( 0.5, 0.0, 0.0, 0.0 );
		}
		else if( attackDirection == gamedataMeleeAttackDirection.LeftUpToRightDown )
		{
			startPosition = Vector4( -0.5, yOffset, 0.30000001, 0.0 );
			endPosition = Vector4( 0.5, 0.0, -0.5, 0.0 );
		}
		else if( attackDirection == gamedataMeleeAttackDirection.RightDownToLeftUp )
		{
			startPosition = Vector4( 0.5, yOffset, -0.5, 0.0 );
			endPosition = Vector4( -0.5, 0.0, 0.30000001, 0.0 );
		}
		else if( attackDirection == gamedataMeleeAttackDirection.RightToLeft )
		{
			startPosition = Vector4( 0.5, yOffset, 0.0, 0.0 );
			endPosition = Vector4( -0.5, 0.0, 0.0, 0.0 );
		}
		else if( attackDirection == gamedataMeleeAttackDirection.RightUpToLeftDown )
		{
			startPosition = Vector4( 0.5, yOffset, 0.30000001, 0.0 );
			endPosition = Vector4( -0.5, 0.0, -0.5, 0.0 );
		}
		else if( attackDirection == gamedataMeleeAttackDirection.UpToDown )
		{
			startPosition = Vector4( 0.0, yOffset, 0.30000001, 0.0 );
			endPosition = Vector4( 0.0, 0.0, -0.5, 0.0 );
		}
		endPosition.Y = range - ( colliderBoxSizeV4.Y * 0.5 );
		attackStartPositionWorld = Transform.TransformPoint( attackTransform, startPosition );
		attackEndPositionWorld = Transform.TransformPoint( attackTransform, endPosition );
		attackDirectionWorld = attackEndPositionWorld - attackStartPositionWorld;
		positionOffset = Vector4.Vector3To4( record.PositionOffset() );
		position = Transform.TransformPoint( attackTransform, startPosition + positionOffset );
		rotation = attackTransform.orientation;
		range = Vector4.Length( attackDirectionWorld );
		direction = attackDirectionWorld;
		if( record.ConeHalfAngle() > 0.0 )
		{
			direction = Transform.TransformVector( attackTransform, Vector4.Vector3To4( record.ConeDirection() ) );
		}
		Vector4.Normalize( direction );
		axisConstraints = Vector4( 0.0, -( record.AxisLowerMargin() ), record.AxisUpperMargin(), 0.0 );
		EffectDataHelper.FillMeleeEffectData( effect.GetSharedData(), colliderBoxSizeV4, record.AttackDuration(), position, rotation, direction, range, record.AttackInitRange(), record.AttackWidth(), axisConstraints, record.ConeHalfAngle() );
	}

	public static function GetWeapon( context : ScriptExecutionContext, record : weak< AISubActionAttackWithWeapon_Record >, out weapon : weak< WeaponObject > ) : Bool
	{
		var i : Int32;
		var count : Int32;
		count = record.GetWeaponSlotsCount();
		for( i = 0; i < count; i += 1 )
		{
			weapon = ( ( WeaponObject )( GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetItemInSlot( ScriptExecutionContext.GetOwner( context ), record.GetWeaponSlotsItem( i ).GetID() ) ) );
			if( weapon )
			{
				return true;
			}
		}
		return false;
	}

	public static function SetAttackNameInBlackBoard( context : ScriptExecutionContext, const attackName : CName )
	{
		var blackBoard : IBlackboard;
		if( attackName != '' )
		{
			blackBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
			blackBoard.SetName( GetAllBlackboardDefs().AIAction.ownerLastAttackName, attackName );
		}
		blackBoard.SetFloat( GetAllBlackboardDefs().AIAction.ownerLastAttackTimeStamp, EngineTime.ToFloat( GameInstance.GetSimTime( ScriptExecutionContext.GetOwner( context ).GetGame() ) ) );
	}

}

abstract class AISubActionRegisterActionName_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionRegisterActionName_Record > )
	{
		AISubActionAttackWithWeapon_Record_Implementation.SetAttackNameInBlackBoard( context, record.ActionName() );
	}

}

abstract class AISubActionMeleeAttackManager_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionMeleeAttackManager_Record > )
	{
		var weapons : array< weak< ItemObject > >;
		var blackBoard : IBlackboard;
		if( record.SpawnTrail() && ( record.TrailDelay() <= 0.0 ) )
		{
			blackBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
			AIActionHelper.GetItemsFromWeaponSlots( ScriptExecutionContext.GetOwner( context ), weapons );
			blackBoard.SetBool( GetAllBlackboardDefs().AIAction.weaponTrailInitialised, true );
			StartWeaponTrailEffect( context, weapons );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionMeleeAttackManager_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var weapons : array< weak< ItemObject > >;
		var blackBoard : IBlackboard;
		blackBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		if( record.SpawnTrail() )
		{
			if( ( ( record.TrailDelay() > 0.0 ) && ( duration >= record.TrailDelay() ) ) && !( blackBoard.GetBool( GetAllBlackboardDefs().AIAction.weaponTrailInitialised ) ) )
			{
				blackBoard.SetBool( GetAllBlackboardDefs().AIAction.weaponTrailInitialised, true );
				AIActionHelper.GetItemsFromWeaponSlots( ScriptExecutionContext.GetOwner( context ), weapons );
				StartWeaponTrailEffect( context, weapons );
			}
			if( ( record.TrailDuration() >= 0.0 ) && !( blackBoard.GetBool( GetAllBlackboardDefs().AIAction.weaponTrailAborted ) ) )
			{
				if( ( record.TrailDelay() >= 0.0 ) && ( duration >= ( record.TrailDelay() + record.TrailDuration() ) ) )
				{
					blackBoard.SetBool( GetAllBlackboardDefs().AIAction.weaponTrailAborted, true );
					AIActionHelper.GetItemsFromWeaponSlots( ScriptExecutionContext.GetOwner( context ), weapons );
					StopWeaponTrailEffect( context, weapons );
				}
				else if( duration >= record.TrailDuration() )
				{
					blackBoard.SetBool( GetAllBlackboardDefs().AIAction.weaponTrailAborted, true );
					AIActionHelper.GetItemsFromWeaponSlots( ScriptExecutionContext.GetOwner( context ), weapons );
					StopWeaponTrailEffect( context, weapons );
				}
			}
		}
		if( record.SpawnTrail() && !( blackBoard.GetBool( GetAllBlackboardDefs().AIAction.weaponTrailAborted ) ) )
		{
			return AIbehaviorUpdateOutcome.IN_PROGRESS;
		}
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionMeleeAttackManager_Record >, const duration : Float, interrupted : Bool )
	{
		var weapons : array< weak< ItemObject > >;
		var blackBoard : IBlackboard;
		blackBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		if( record.SpawnTrail() )
		{
			if( blackBoard.GetBool( GetAllBlackboardDefs().AIAction.weaponTrailInitialised ) && !( blackBoard.GetBool( GetAllBlackboardDefs().AIAction.weaponTrailAborted ) ) )
			{
				AIActionHelper.GetItemsFromWeaponSlots( ScriptExecutionContext.GetOwner( context ), weapons );
				StopWeaponTrailEffect( context, weapons );
			}
			blackBoard.SetBool( GetAllBlackboardDefs().AIAction.weaponTrailInitialised, false );
			blackBoard.SetBool( GetAllBlackboardDefs().AIAction.weaponTrailAborted, false );
		}
	}

	public static function StartWeaponTrailEffect( context : ScriptExecutionContext, const weapons : ref< array< weak< ItemObject > > > )
	{
		var i : Int32;
		var weaponRecord : WeaponItem_Record;
		for( i = 0; i < weapons.Size(); i += 1 )
		{
			weaponRecord = ( ( WeaponItem_Record )( TweakDBInterface.GetItemRecord( ItemID.GetTDBID( weapons[ i ].GetItemID() ) ) ) );
			if( weaponRecord.ItemType().Type() == gamedataItemType.Cyb_StrongArms )
			{
				StartStrongArmsTrailEffect( ScriptExecutionContext.GetOwner( context ), weapons[ i ] );
			}
			else
			{
				( ( WeaponObject )( weapons[ i ] ) ).StartCurrentMeleeTrailEffect();
			}
		}
	}

	public static function StartStrongArmsTrailEffect( owner : GameObject, weapon : ItemObject )
	{
		var trailName : CName;
		trailName = AIActionHelper.GetCurrentStrongArmsTrailEffect( weapon );
		GameObjectEffectHelper.StartEffectEvent( owner, trailName );
	}

	public static function StopWeaponTrailEffect( context : ScriptExecutionContext, const weapons : ref< array< weak< ItemObject > > > )
	{
		var i : Int32;
		var weaponRecord : WeaponItem_Record;
		for( i = 0; i < weapons.Size(); i += 1 )
		{
			weaponRecord = ( ( WeaponItem_Record )( TweakDBInterface.GetItemRecord( ItemID.GetTDBID( weapons[ i ].GetItemID() ) ) ) );
			if( weaponRecord.ItemType().Type() == gamedataItemType.Cyb_StrongArms )
			{
				stopStrongArmsTrailEffect( ScriptExecutionContext.GetOwner( context ), weapons[ i ] );
			}
			else
			{
				( ( WeaponObject )( weapons[ i ] ) ).StopCurrentMeleeTrailEffect();
			}
		}
	}

	public static function stopStrongArmsTrailEffect( owner : GameObject, weapon : ItemObject )
	{
		var trailName : CName;
		trailName = AIActionHelper.GetCurrentStrongArmsTrailEffect( weapon );
		GameObjectEffectHelper.BreakEffectLoopEvent( owner, trailName );
	}

}

abstract class AISubActionShootToPoint_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionShootToPoint_Record > )
	{
		AISubActionShootWithWeapon_Record_Implementation.Activate( context, ( ( AISubActionShootWithWeapon_Record )( record ) ) );
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionShootToPoint_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		return AISubActionShootWithWeapon_Record_Implementation.Update( context, ( ( AISubActionShootWithWeapon_Record )( record ) ), duration );
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionShootToPoint_Record >, const duration : Float, interrupted : Bool )
	{
		return AISubActionShootWithWeapon_Record_Implementation.Deactivate( context, ( ( AISubActionShootWithWeapon_Record )( record ) ), duration, interrupted );
	}

}

abstract class AISubActionMissileRainGrid_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionMissileRainGrid_Record > )
	{
		AISubActionShootWithWeapon_Record_Implementation.Activate( context, ( ( AISubActionShootWithWeapon_Record )( record ) ) );
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionMissileRainGrid_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		return AISubActionShootWithWeapon_Record_Implementation.Update( context, ( ( AISubActionShootWithWeapon_Record )( record ) ), duration );
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionMissileRainGrid_Record >, const duration : Float, interrupted : Bool )
	{
		return AISubActionShootWithWeapon_Record_Implementation.Deactivate( context, ( ( AISubActionShootWithWeapon_Record )( record ) ), duration, interrupted );
	}

}

abstract class AISubActionMissileRainCircular_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionMissileRainCircular_Record > )
	{
		AISubActionShootWithWeapon_Record_Implementation.Activate( context, ( ( AISubActionShootWithWeapon_Record )( record ) ) );
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionMissileRainCircular_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		return AISubActionShootWithWeapon_Record_Implementation.Update( context, ( ( AISubActionShootWithWeapon_Record )( record ) ), duration );
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionMissileRainCircular_Record >, const duration : Float, interrupted : Bool )
	{
		return AISubActionShootWithWeapon_Record_Implementation.Deactivate( context, ( ( AISubActionShootWithWeapon_Record )( record ) ), duration, interrupted );
	}

}

abstract class AISubActionChimeraMetalstorm_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionChimeraMetalstorm_Record > )
	{
		AISubActionShootWithWeapon_Record_Implementation.Activate( context, ( ( AISubActionShootWithWeapon_Record )( record ) ) );
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionChimeraMetalstorm_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		return AISubActionShootWithWeapon_Record_Implementation.Update( context, ( ( AISubActionShootWithWeapon_Record )( record ) ), duration );
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionChimeraMetalstorm_Record >, const duration : Float, interrupted : Bool )
	{
		return AISubActionShootWithWeapon_Record_Implementation.Deactivate( context, ( ( AISubActionShootWithWeapon_Record )( record ) ), duration, interrupted );
	}

}

abstract class AISubActionShootFromCar_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionShootFromCar_Record > )
	{
		var vehicle : weak< VehicleObject >;
		var bboard : IBlackboard;
		if( VehicleComponent.GetVehicle( ScriptExecutionContext.GetOwner( context ).GetGame(), ScriptExecutionContext.GetOwner( context ).GetEntityID(), vehicle ) )
		{
			if( vehicle.IsArmedVehicle() && !( vehicle.IsNPCShooting() ) )
			{
				vehicle.EnableNPCCombat( true );
				bboard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetShootingBlackboard();
				bboard.SetBool( GetAllBlackboardDefs().AIShooting.shootingFromCar, false );
			}
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionShootFromCar_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var target : weak< GameObject >;
		var bboard : IBlackboard;
		var targetPosition : Vector4;
		var vehicle : weak< VehicleObject >;
		var minBurstProjecitles : Int32;
		var maxBurstProjecitles : Int32;
		if( ( record.Delay() > 0.0 ) && ( duration < record.Delay() ) )
		{
			return AIbehaviorUpdateOutcome.IN_PROGRESS;
		}
		AIActionTarget.Get( context, record.Target(), false, target, targetPosition );
		if( VehicleComponent.GetVehicle( ScriptExecutionContext.GetOwner( context ).GetGame(), ScriptExecutionContext.GetOwner( context ).GetEntityID(), vehicle ) && vehicle.IsArmedVehicle() )
		{
			bboard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetShootingBlackboard();
			if( !( bboard.GetBool( GetAllBlackboardDefs().AIShooting.shootingFromCar ) ) )
			{
				minBurstProjecitles = TweakDBInterface.GetInt( T"vehicles.npc_armed_car.minBurstProjectiles", minBurstProjecitles );
				maxBurstProjecitles = TweakDBInterface.GetInt( T"vehicles.npc_armed_car.maxBurstProjectiles", maxBurstProjecitles );
				vehicle.NPCShoot( targetPosition, ( ( Uint32 )( RandRange( minBurstProjecitles, maxBurstProjecitles ) ) ) );
				bboard.SetBool( GetAllBlackboardDefs().AIShooting.shootingFromCar, true );
				return AIbehaviorUpdateOutcome.IN_PROGRESS;
			}
			else if( vehicle.IsNPCShooting() )
			{
				return AIbehaviorUpdateOutcome.IN_PROGRESS;
			}
			else
			{
				return AIbehaviorUpdateOutcome.SUCCESS;
			}
		}
		else
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionShootFromCar_Record >, const duration : Float, interrupted : Bool )
	{
		var bboard : IBlackboard;
		bboard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetShootingBlackboard();
		bboard.SetBool( GetAllBlackboardDefs().AIShooting.shootingFromCar, false );
	}

}

abstract class AISubActionShootWithWeapon_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionShootWithWeapon_Record > )
	{
		var weapons : array< weak< WeaponObject > >;
		var weaponRecord : weak< WeaponItem_Record >;
		var target : weak< GameObject >;
		var targetPosition : Vector4;
		var desiredNumberOfShots : Int32;
		var i : Int32;
		if( !( GetWeapon( context, record, weapons ) ) )
		{
			return;
		}
		( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetShootingBlackboard().SetFloat( GetAllBlackboardDefs().AIShooting.pauseConditionCheckTimeStamp, 0.0 );
		for( i = 0; i < weapons.Size(); i += 1 )
		{
			if( record.TriggerMode() )
			{
				WeaponObject.ChangeTriggerMode( weapons[ i ], record.TriggerMode().Type() );
				weapons[ i ].GetAIBlackboard().SetInt( GetAllBlackboardDefs().AIShooting.requestedTriggerMode, ( ( Int32 )( record.TriggerMode().Type() ) ) );
			}
			else
			{
				weaponRecord = ( ( weak< weak< WeaponItem_Record > > )( TweakDBInterface.GetItemRecord( ItemID.GetTDBID( weapons[ i ].GetItemID() ) ) ) );
				if( AIActionHelper.WeaponHasTriggerMode( weapons[ i ], weaponRecord, gamedataTriggerMode.Burst ) )
				{
					weapons[ i ].GetAIBlackboard().SetInt( GetAllBlackboardDefs().AIShooting.requestedTriggerMode, ( ( Int32 )( gamedataTriggerMode.Burst ) ) );
				}
				else if( weaponRecord.PrimaryTriggerMode().Type() == gamedataTriggerMode.Charge )
				{
					weapons[ i ].GetAIBlackboard().SetInt( GetAllBlackboardDefs().AIShooting.requestedTriggerMode, ( ( Int32 )( gamedataTriggerMode.SemiAuto ) ) );
				}
				else
				{
					weapons[ i ].GetAIBlackboard().SetInt( GetAllBlackboardDefs().AIShooting.requestedTriggerMode, ( ( Int32 )( weaponRecord.PrimaryTriggerMode().Type() ) ) );
				}
			}
			AIActionTarget.Get( context, record.Target(), false, target, targetPosition );
			AIWeapon.SelectShootingPattern( record, weapons[ i ], ScriptExecutionContext.GetOwner( context ), true );
			if( record.MaxNumberOfShots() > record.NumberOfShots() )
			{
				desiredNumberOfShots = Max( 0, RandRange( record.NumberOfShots(), record.MaxNumberOfShots() + 1 ) );
			}
			else
			{
				desiredNumberOfShots = record.NumberOfShots();
			}
			AIWeapon.OnStartShooting( weapons[ i ], desiredNumberOfShots );
			QueueFirstShot( weapons[ i ] );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionShootWithWeapon_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var weapons : array< weak< WeaponObject > >;
		var target : weak< GameObject >;
		var requestedTriggerMode : gamedataTriggerMode;
		var bboard : IBlackboard;
		var targetPosition : Vector4;
		var pauseConditionCheckInterval : Float;
		var pauseConditionCheckTimeStamp : Float;
		var chargeLevel : Float;
		var didShoot : Bool;
		var numberOfShots : Int32;
		var count : Int32;
		var vehicle : weak< VehicleObject >;
		var i, j : Int32;
		if( !( GetWeapon( context, record, weapons ) ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		if( ( record.Delay() > 0.0 ) && ( duration < record.Delay() ) )
		{
			return AIbehaviorUpdateOutcome.IN_PROGRESS;
		}
		count = record.GetPauseConditionCount();
		if( count > 0 )
		{
			pauseConditionCheckInterval = record.PauseConditionCheckInterval();
			bboard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetShootingBlackboard();
			pauseConditionCheckTimeStamp = bboard.GetFloat( GetAllBlackboardDefs().AIShooting.pauseConditionCheckTimeStamp );
			if( ( pauseConditionCheckInterval <= 0.0 ) || ( ( ( pauseConditionCheckInterval > 0.0 ) && ( duration >= ( pauseConditionCheckTimeStamp + pauseConditionCheckInterval ) ) ) || ( pauseConditionCheckTimeStamp == 0.0 ) ) )
			{
				for( i = 0; i < count; i += 1 )
				{
					if( AICondition.CheckActionCondition( context, record.GetPauseConditionItem( i ) ) )
					{
						break;
					}
				}
				if( i < count )
				{
					return AIbehaviorUpdateOutcome.IN_PROGRESS;
				}
				bboard.SetFloat( GetAllBlackboardDefs().AIShooting.pauseConditionCheckTimeStamp, duration );
			}
		}
		i = 0;
		if( ( weapons.Size() > 1 ) && record.DualWieldShootingStyle() == 'Sequence' )
		{
			for( j = 0; j < weapons.Size(); j += 1 )
			{
				numberOfShots += AIWeapon.GetTotalNumberOfShots( weapons[ j ] );
			}
			if( ( numberOfShots % 2 ) != 0 )
			{
				i = 1;
			}
		}
		while( i < weapons.Size() )
		{
			if( !( weapons[ i ].IsAttached() ) )
			{
				return AIbehaviorUpdateOutcome.IN_PROGRESS;
			}
			if( AIWeapon.HasExceededDesiredNumberOfShots( weapons[ i ] ) )
			{
				return AIbehaviorUpdateOutcome.SUCCESS;
			}
			GameInstance.GetStatPoolsSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).RequestSettingStatPoolValue( weapons[ i ].GetEntityID(), gamedataStatPoolType.WeaponCharge, chargeLevel, ScriptExecutionContext.GetOwner( context ) );
			if( duration < AIWeapon.GetNextShotTimeStamp( weapons[ i ] ) )
			{
				return AIbehaviorUpdateOutcome.IN_PROGRESS;
			}
			requestedTriggerMode = AIActionHelper.GetLastRequestedTriggerMode( weapons[ i ] );
			if( requestedTriggerMode == gamedataTriggerMode.Charge && AIWeapon.UpdateCharging( weapons[ i ], duration, ScriptExecutionContext.GetOwner( context ), chargeLevel ) )
			{
				return AIbehaviorUpdateOutcome.IN_PROGRESS;
			}
			AIActionTarget.Get( context, record.Target(), false, target, targetPosition );
			didShoot = false;
			if( record.IsA( 'gamedataAISubActionShootToPoint_Record' ) )
			{
				didShoot = ShootToPoints( context, ( ( AISubActionShootToPoint_Record )( record ) ), weapons[ i ], requestedTriggerMode, duration );
			}
			else if( record.IsA( 'gamedataAISubActionMissileRainGrid_Record' ) )
			{
				didShoot = ShootMissileRainGrid( context, ( ( AISubActionMissileRainGrid_Record )( record ) ), weapons[ i ], requestedTriggerMode, target, targetPosition, duration );
			}
			else if( record.IsA( 'gamedataAISubActionMissileRainCircular_Record' ) )
			{
				didShoot = ShootMissileRainCircular( context, ( ( AISubActionMissileRainCircular_Record )( record ) ), weapons[ i ], requestedTriggerMode, target, targetPosition, duration );
			}
			else if( record.IsA( 'gamedataAISubActionChimeraMetalstorm_Record' ) )
			{
				didShoot = ShootChimeraMetalstorm( context, ( ( AISubActionChimeraMetalstorm_Record )( record ) ), weapons[ i ], requestedTriggerMode, target, targetPosition, duration );
			}
			if( !( didShoot ) )
			{
				if( target.IsPlayer() )
				{
					if( VehicleComponent.GetVehicle( target.GetGame(), target.GetEntityID(), vehicle ) )
					{
						if( ( ( TankObject )( vehicle ) ) )
						{
							target = vehicle;
						}
					}
				}
				Shoot( context, record, duration, weapons[ i ], requestedTriggerMode, targetPosition, target, , record.PredictionTime(), , record.WeaponCustomEvent() );
			}
			QueueNextShot( weapons[ i ], requestedTriggerMode, duration );
			if( record.DualWieldShootingStyle() == 'Sequence' )
			{
				for( j = 0; j < weapons.Size(); j += 1 )
				{
					weapons[ j ].GetAIBlackboard().SetFloat( GetAllBlackboardDefs().AIShooting.nextShotTimeStamp, weapons[ i ].GetAIBlackboard().GetFloat( GetAllBlackboardDefs().AIShooting.nextShotTimeStamp ) );
				}
				break;
			}
			i += 1;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionShootWithWeapon_Record >, const duration : Float, interrupted : Bool )
	{
		var weapons : array< weak< WeaponObject > >;
		var i : Int32;
		if( !( GetWeapon( context, record, weapons ) ) )
		{
			return;
		}
		for( i = 0; i < weapons.Size(); i += 1 )
		{
			AIWeapon.OnStopShooting( weapons[ i ], duration );
			WeaponObject.ChangeTriggerMode( weapons[ i ], weapons[ i ].GetWeaponRecord().PrimaryTriggerMode().Type() );
		}
	}

	public static function Shoot( context : ScriptExecutionContext, record : weak< AISubActionShootWithWeapon_Record >, const duration : Float, weapon : weak< WeaponObject >, requestedTriggerMode : gamedataTriggerMode, targetPosition : Vector4, target : weak< GameObject >, optional offset : Vector4, optional predictionTime : Float, optional muzzleOffset : Vector4, optional weaponCustomEvent : CName )
	{
		var rangedAttack : TweakDBID;
		if( record.RangedAttack() )
		{
			rangedAttack = record.RangedAttack().GetID();
		}
		AIWeapon.Fire( ScriptExecutionContext.GetOwner( context ), weapon, duration, record.TbhCoefficient(), requestedTriggerMode, targetPosition, target, rangedAttack, 0.0, record.AimingDelay(), Vector4.Vector3To4( record.TargetOffset() ) + offset, ShouldTrackTarget( ScriptExecutionContext.GetOwner( context ), record, weapon ), predictionTime, , muzzleOffset, weaponCustomEvent );
	}

	private static function ShouldTrackTarget( owner : weak< gamePuppet >, record : weak< AISubActionShootWithWeapon_Record >, weapon : weak< WeaponObject > ) : Bool
	{
		if( ( ( ( AISubActionMissileRainGrid_Record )( record ) ) || ( ( AISubActionMissileRainCircular_Record )( record ) ) ) || ( ( AISubActionChimeraMetalstorm_Record )( record ) ) )
		{
			return true;
		}
		if( StatusEffectSystem.ObjectHasStatusEffectWithTag( owner, 'WeaponJam' ) )
		{
			return false;
		}
		return TDB.GetWeaponItemRecord( ItemID.GetTDBID( weapon.GetItemID() ) ).Evolution().Type() == gamedataWeaponEvolution.Smart && weapon.IsTargetLocked();
	}

	public static function QueueNextShot( weapon : weak< WeaponObject >, requestedTriggerMode : gamedataTriggerMode, const duration : Float )
	{
		var pattern : weak< AIPattern_Record >;
		var delayFromPattern : Float;
		pattern = AIWeapon.GetShootingPattern( weapon );
		if( pattern )
		{
			delayFromPattern = AIWeapon.GetShootingPatternDelayBetweenShots( AIWeapon.GetTotalNumberOfShots( weapon ), pattern );
		}
		AIWeapon.QueueNextShot( weapon, requestedTriggerMode, duration, delayFromPattern );
	}

	public static function QueueFirstShot( weapon : weak< WeaponObject > )
	{
		var pattern : weak< AIPattern_Record >;
		var delayFromPattern : Float;
		pattern = AIWeapon.GetShootingPattern( weapon );
		if( pattern )
		{
			delayFromPattern = AIWeapon.GetShootingPatternDelayBetweenShots( 0, pattern );
		}
		weapon.GetAIBlackboard().SetFloat( GetAllBlackboardDefs().AIShooting.nextShotTimeStamp, delayFromPattern );
	}

	public static function ShootToPoints( context : ScriptExecutionContext, record : weak< AISubActionShootToPoint_Record >, weapon : weak< WeaponObject >, requestedTriggerMode : gamedataTriggerMode, duration : Float ) : Bool
	{
		var scriptedPuppet : ScriptedPuppet;
		var targetPositionObj : weak< GameObject >;
		var target : weak< GameObject >;
		var waypointTag : array< CName >;
		var shootPointPosition : array< Vector4 >;
		var i : Int32;
		var coordinateArray : array< Vector4 >;
		var coordinateArrayV3 : array< Vector3 >;
		if( !( record ) )
		{
			return false;
		}
		coordinateArrayV3 = record.PointPosition();
		waypointTag = record.WaypointTag();
		if( coordinateArrayV3.Size() > 0 )
		{
			AIActionTarget.GetObject( context, record.TargetPositionObj(), targetPositionObj );
			coordinateArray = ConvertVector3ArrayToVector4Array( coordinateArrayV3 );
			SetShootPointsByCoordinate( context, targetPositionObj, coordinateArray, shootPointPosition );
		}
		else if( waypointTag.Size() > 0 )
		{
			SetShootPointsBytag( context, waypointTag, shootPointPosition );
		}
		else
		{
			return false;
		}
		if( shootPointPosition.Size() == 0 )
		{
			return false;
		}
		for( i = 0; i < shootPointPosition.Size(); i += 1 )
		{
			Shoot( context, record, duration, weapon, requestedTriggerMode, shootPointPosition[ i ], target, , , , record.WeaponCustomEvent() );
		}
		scriptedPuppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		if( scriptedPuppet.IsBoss() )
		{
			GameObject.StartReplicatedEffectEvent( scriptedPuppet, 'rocket_flaps_heat' );
		}
		return true;
	}

	private static function ShootMissileRainGrid( context : ScriptExecutionContext, record : weak< AISubActionMissileRainGrid_Record >, weapon : weak< WeaponObject >, requestedTriggerMode : gamedataTriggerMode, target : weak< GameObject >, targetPosition : Vector4, duration : Float ) : Bool
	{
		var scriptedPuppet : ScriptedPuppet;
		var missileOffsets : array< Vector3 >;
		var i, numMissiles : Int32;
		if( !( record ) )
		{
			return false;
		}
		missileOffsets = record.MissileOffsets();
		numMissiles = missileOffsets.Size();
		if( numMissiles == 0 )
		{
			return false;
		}
		for( i = 0; i < numMissiles; i += 1 )
		{
			Shoot( context, record, duration, weapon, requestedTriggerMode, targetPosition, target, Vector4.Vector3To4( missileOffsets[ i ] ), , , record.WeaponCustomEvent() );
		}
		scriptedPuppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		if( scriptedPuppet.IsBoss() )
		{
			GameObject.StartReplicatedEffectEvent( scriptedPuppet, 'rocket_flaps_heat' );
		}
		return true;
	}

	private static function ShootMissileRainCircular( context : ScriptExecutionContext, record : weak< AISubActionMissileRainCircular_Record >, weapon : weak< WeaponObject >, requestedTriggerMode : gamedataTriggerMode, target : weak< GameObject >, targetPosition : Vector4, duration : Float ) : Bool
	{
		var scriptedPuppet : ScriptedPuppet;
		var minRadius, maxRadius : Float;
		var i, missilesPerLaunch : Int32;
		if( !( record ) )
		{
			return false;
		}
		minRadius = record.MinRadius();
		maxRadius = record.MaxRadius();
		missilesPerLaunch = record.MissilesPerLaunch();
		if( ( minRadius > maxRadius ) || ( missilesPerLaunch < 1 ) )
		{
			return false;
		}
		scriptedPuppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		for( i = 0; i < missilesPerLaunch; i += 1 )
		{
			Shoot( context, record, duration, weapon, requestedTriggerMode, targetPosition, target, Vector4.RandRing( minRadius, maxRadius ) );
		}
		if( scriptedPuppet.IsBoss() )
		{
			GameObject.StartReplicatedEffectEvent( scriptedPuppet, 'rocket_flaps_heat' );
		}
		return true;
	}

	private static function ShootChimeraMetalstorm( context : ScriptExecutionContext, record : weak< AISubActionChimeraMetalstorm_Record >, weapon : weak< WeaponObject >, requestedTriggerMode : gamedataTriggerMode, target : weak< GameObject >, targetPosition : Vector4, duration : Float ) : Bool
	{
		var jv, jh : Int32;
		var i : Int32;
		var isOdd : Bool;
		var muzzleTransform : Transform;
		var muzzleRotation : Quaternion;
		var muzzleOffset : Vector4;
		var targetOffset : Vector4;
		if( !( record ) )
		{
			return false;
		}
		muzzleTransform = weapon.GetMuzzleSlotWorldTransform();
		muzzleRotation = Quaternion.BuildFromDirectionVector( targetPosition - Transform.GetPosition( muzzleTransform ) );
		jv = RandRange( -2, 2 );
		jh = RandRange( -9, 9 );
		isOdd = ( jv % 2 ) != 0;
		muzzleOffset.X = ( ( Float )( jv ) ) * 0.1;
		muzzleOffset.Y = 0.0;
		muzzleOffset.Z = ( ( ( Float )( jh ) ) * 0.1 ) + ( ( isOdd ) ? ( 0.05 ) : ( 0.0 ) );
		targetOffset.X = muzzleOffset.Z;
		targetOffset.Y = muzzleOffset.Y;
		targetOffset.Z = -( muzzleOffset.X );
		targetOffset = Quaternion.Transform( muzzleRotation, targetOffset );
		Shoot( context, record, duration, weapon, requestedTriggerMode, targetPosition, target, targetOffset, , muzzleOffset, record.WeaponCustomEvent() );
		for( i = 0; i < 2; i += 1 )
		{
			jv = RandRange( -2, 2 );
			jh = RandRange( -9, 9 );
			isOdd = ( jv % 2 ) != 0;
			muzzleOffset.X = ( ( Float )( jv ) ) * 0.1;
			muzzleOffset.Y = 0.0;
			muzzleOffset.Z = ( ( ( Float )( jh ) ) * 0.1 ) + ( ( isOdd ) ? ( 0.05 ) : ( 0.0 ) );
			targetOffset.X = muzzleOffset.Z;
			targetOffset.Y = muzzleOffset.Y;
			targetOffset.Z = -( muzzleOffset.X ) + 1.5;
			targetOffset = Quaternion.Transform( muzzleRotation, targetOffset );
			Shoot( context, record, duration, weapon, requestedTriggerMode, targetPosition, NULL, targetOffset, , muzzleOffset, record.WeaponCustomEvent() );
		}
		return true;
	}

	public static function SetShootPointsBytag( context : ScriptExecutionContext, const tags : ref< array< CName > >, shootPointPosition : ref< array< Vector4 > > ) : Bool
	{
		var targetsPosition : array< Vector4 >;
		if( tags.Size() <= 0 )
		{
			return false;
		}
		GameInstance.FindWaypointsByTag( ScriptExecutionContext.GetOwner( context ).GetGame(), tags[ 0 ], targetsPosition );
		shootPointPosition = targetsPosition;
		return true;
	}

	public static function ConvertVector3ArrayToVector4Array( const v3 : ref< array< Vector3 > > ) : array< Vector4 >
	{
		var i : Int32;
		var tempVector4 : Vector4;
		var tempVector4Array : array< Vector4 >;
		for( i = 0; i < v3.Size(); i += 1 )
		{
			tempVector4.X = v3[ i ].X;
			tempVector4.Y = v3[ i ].Y;
			tempVector4.Z = v3[ i ].Z;
			tempVector4Array.PushBack( tempVector4 );
		}
		return tempVector4Array;
	}

	public static function SetShootPointsByCoordinate( context : ScriptExecutionContext, target : weak< GameObject >, const coordinateArray : ref< array< Vector4 > >, shootPointPosition : ref< array< Vector4 > > ) : Bool
	{
		var targetPosition : Vector4;
		var i : Int32;
		var tempVector : Vector4;
		targetPosition = target.GetWorldPosition();
		for( i = 0; i < coordinateArray.Size(); i += 1 )
		{
			tempVector = targetPosition + coordinateArray[ i ];
			shootPointPosition.PushBack( tempVector );
		}
		return true;
	}

	public static function GetWeapon( context : ScriptExecutionContext, record : weak< AISubActionShootWithWeapon_Record >, weaponsList : ref< array< weak< WeaponObject > > > ) : Bool
	{
		var i : Int32;
		var count : Int32;
		var weapon : weak< WeaponObject >;
		count = record.GetWeaponSlotsCount();
		for( i = 0; i < count; i += 1 )
		{
			weapon = ( ( WeaponObject )( GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetItemInSlot( ScriptExecutionContext.GetOwner( context ), record.GetWeaponSlotsItem( i ).GetID() ) ) );
			if( weapon )
			{
				weaponsList.PushBack( weapon );
			}
		}
		return weaponsList.Size() > 0;
	}

}

abstract class AISubActionCreateGameEffect_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionCreateGameEffect_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			CreateGameEffect( context, record );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionCreateGameEffect_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			CreateGameEffect( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionCreateGameEffect_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			CreateGameEffect( context, record );
		}
	}

	public static function CreateGameEffect( context : ScriptExecutionContext, record : weak< AISubActionCreateGameEffect_Record > )
	{
		var effect : EffectInstance;
		var positionObj : weak< GameObject >;
		var rotationObj : weak< GameObject >;
		var targetPositionObj : weak< GameObject >;
		var target : weak< GameObject >;
		var vecToTarget : Vector4;
		var colliderBoxSize : Vector3;
		effect = GameInstance.GetGameEffectSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).CreateEffectStatic( record.EffectName(), record.EffectTag(), ScriptExecutionContext.GetOwner( context ) );
		if( !( effect ) )
		{
			return;
		}
		if( AIActionTarget.GetObject( context, record.Target(), target ) )
		{
			EffectData.SetVector( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.position, target.GetWorldPosition() );
			EffectData.SetEntity( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.entity, target );
			effect.Run();
			return;
		}
		EffectData.SetFloat( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.duration, record.Duration() );
		if( AIActionTarget.GetObject( context, record.PositionObj(), positionObj ) )
		{
			EffectData.SetVector( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.position, positionObj.GetWorldPosition() );
		}
		if( !( positionObj ) )
		{
			return;
		}
		if( positionObj && AIActionTarget.GetObject( context, record.TargetPositionObj(), targetPositionObj ) )
		{
			vecToTarget = targetPositionObj.GetWorldPosition() - positionObj.GetWorldPosition();
			EffectData.SetFloat( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.range, Vector4.Length( vecToTarget ) );
			EffectData.SetFloat( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.radius, Vector4.Length( vecToTarget ) );
			EffectData.SetVector( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.forward, Vector4.Normalize( vecToTarget ) );
			EffectData.SetQuat( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.rotation, Quaternion.BuildFromDirectionVector( vecToTarget, positionObj.GetWorldUp() ) );
		}
		else
		{
			if( AIActionTarget.GetObject( context, record.RotationObj(), rotationObj ) )
			{
				EffectData.SetQuat( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.rotation, rotationObj.GetWorldOrientation() );
				EffectData.SetVector( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.forward, rotationObj.GetWorldForward() );
			}
			else
			{
				EffectData.SetQuat( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.rotation, positionObj.GetWorldOrientation() );
				EffectData.SetVector( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.forward, positionObj.GetWorldForward() );
			}
			EffectData.SetFloat( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.range, record.Range() );
			EffectData.SetFloat( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.radius, record.Range() );
		}
		colliderBoxSize = record.ColliderBoxSize();
		EffectData.SetVector( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.box, Vector4( colliderBoxSize.X, colliderBoxSize.Y, colliderBoxSize.Z, 0.0 ) );
		effect.Run();
	}

}

abstract class AISubActionInAir_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionInAir_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetPuppetStateBlackboard().SetBool( GetAllBlackboardDefs().PuppetState.InAirAnimation, true );
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionInAir_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( ( record.Delay() >= 0.0 ) && ( duration >= record.Delay() ) )
		{
			( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetPuppetStateBlackboard().SetBool( GetAllBlackboardDefs().PuppetState.InAirAnimation, true );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionInAir_Record >, const duration : Float, interrupted : Bool )
	{
		( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetPuppetStateBlackboard().SetBool( GetAllBlackboardDefs().PuppetState.InAirAnimation, false );
	}

}

abstract class AISubActionSetTargetByTag_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionSetTargetByTag_Record > ) {}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionSetTargetByTag_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( ( record.Delay() >= 0.0 ) && ( duration >= record.Delay() ) )
		{
			if( SetTargetByTag( context, record ) )
			{
				return AIbehaviorUpdateOutcome.SUCCESS;
			}
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionSetTargetByTag_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			SetTargetByTag( context, record );
		}
	}

	public static function SetTargetByTag( context : ScriptExecutionContext, record : weak< AISubActionSetTargetByTag_Record > ) : Bool
	{
		var targetPosition : Vector4;
		var targetsObject : array< Entity >;
		var lineOfSightTargetPosition : Vector4;
		var positions : array< Vector4 >;
		var desiredDistance : Vector2;
		var desiredDistanceFromObj : Vector2;
		var toOwnerDistances : array< Float >;
		var toTargetsDistances : array< Float >;
		var allowedOffMeshTags : array< CName >;
		var index, i : Int32;
		var itemObject : ItemObject;
		if( !( IsNameValid( record.Tag() ) ) )
		{
			return false;
		}
		AIActionTarget.GetPosition( context, record.RangeObj(), targetPosition, false );
		if( Vector4.IsZero( targetPosition ) )
		{
			targetPosition = ScriptExecutionContext.GetOwner( context ).GetWorldPosition();
		}
		desiredDistance = record.RangeFromOwner();
		desiredDistanceFromObj = record.RangeFromObj();
		allowedOffMeshTags = record.AllowedOffMeshTags();
		if( record.LineOfSightTarget() )
		{
			AIActionTarget.GetPosition( context, record.RangeObj(), lineOfSightTargetPosition, false );
		}
		GameInstance.GetGameTagSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetAllMatchingEntities( record.Tag(), targetsObject );
		GetPositionsFromEntity( context, targetsObject, positions );
		GetDistancesFromTargetToPositions( context, ScriptExecutionContext.GetOwner( context ).GetWorldPosition(), positions, toOwnerDistances );
		GetDistancesFromTargetToPositions( context, targetPosition, positions, toTargetsDistances );
		index = SelectIndex( context, record.SelectionMethod(), desiredDistance.X, desiredDistance.Y, toOwnerDistances, desiredDistanceFromObj.X, desiredDistanceFromObj.Y, toTargetsDistances, positions, allowedOffMeshTags, lineOfSightTargetPosition, record.BlockLoSByNonPenetrableObj() );
		if( index < 0 )
		{
			return false;
		}
		targetPosition = positions[ index ];
		itemObject = ( ( ItemObject )( targetsObject[ index ] ) );
		if( itemObject && itemObject.IsConnectedWithDrop() )
		{
			return AIActionTarget.Set( context, record.Target(), itemObject.GetConnectedItemDrop(), targetPosition );
		}
		else
		{
			for( i = 0; i < targetsObject.Size(); i += 1 )
			{
				itemObject = ( ( ItemObject )( targetsObject[ i ] ) );
				if( itemObject && itemObject.IsConnectedWithDrop() )
				{
					return AIActionTarget.Set( context, record.Target(), itemObject.GetConnectedItemDrop(), targetPosition );
				}
			}
		}
		AIActionTarget.Set( context, record.Target(), NULL, targetPosition );
		return false;
	}

	public static function GetDistancesFromTargetToPositions( context : ScriptExecutionContext, const target : Vector4, const positions : ref< array< Vector4 > >, outDistances : ref< array< Float > > ) : Bool
	{
		var i : Int32;
		if( positions.Size() <= 0 )
		{
			return false;
		}
		outDistances.Clear();
		outDistances.Resize( positions.Size() );
		for( i = 0; i < positions.Size(); i += 1 )
		{
			outDistances[ i ] = Vector4.Distance( target, positions[ i ] );
		}
		return outDistances.Size() > 0;
	}

	public static function GetDistancesFromEntity( context : ScriptExecutionContext, const targets : ref< array< Entity > >, distances : ref< array< Float > > ) : Bool
	{
		var ownerRefVector : Vector4;
		var i : Int32;
		if( targets.Size() <= 0 )
		{
			return false;
		}
		ownerRefVector = ScriptExecutionContext.GetOwner( context ).GetWorldPosition();
		distances.Clear();
		distances.Resize( targets.Size() );
		for( i = 0; i < targets.Size(); i += 1 )
		{
			distances[ i ] = Vector4.Distance( ownerRefVector, targets[ i ].GetWorldPosition() );
		}
		return distances.Size() > 0;
	}

	public static function GetPositionsFromEntity( context : ScriptExecutionContext, const targets : ref< array< Entity > >, positions : ref< array< Vector4 > > ) : Bool
	{
		var i : Int32;
		if( targets.Size() <= 0 )
		{
			return false;
		}
		positions.Clear();
		positions.Resize( targets.Size() );
		for( i = 0; i < targets.Size(); i += 1 )
		{
			positions[ i ] = targets[ i ].GetWorldPosition();
		}
		return positions.Size() > 0;
	}

	public static function SelectIndex( context : ScriptExecutionContext, selectionPreference : CName, minDistance : Float, maxDistance : Float, const distances : ref< array< Float > >, minDistanceObj : Float, maxDistanceObj : Float, const distancesObj : ref< array< Float > >, optional targetsPosition : array< Vector4 >, const allowedOffMeshTags : ref< array< CName > >, lineOfSightTarget : Vector4, blockLoSByNonPenetrableObj : Bool ) : Int32
	{
		if( distances.Size() == 0 )
		{
			return -1;
		}
		if( selectionPreference == 'Farthest' )
		{
			return GetFarthestIndexInRange( context, minDistance, maxDistance, distances, minDistanceObj, maxDistanceObj, distancesObj, targetsPosition, allowedOffMeshTags, lineOfSightTarget, blockLoSByNonPenetrableObj );
		}
		else if( selectionPreference == 'Closest' )
		{
			return GetClosestIndexInRange( context, minDistance, maxDistance, distances, minDistanceObj, maxDistanceObj, distancesObj, targetsPosition, allowedOffMeshTags, lineOfSightTarget, blockLoSByNonPenetrableObj );
		}
		return GetRandomIndexInRange( context, minDistance, maxDistance, distances, minDistanceObj, maxDistanceObj, distancesObj, allowedOffMeshTags, targetsPosition, lineOfSightTarget, blockLoSByNonPenetrableObj );
	}

	public static function CheckPath( context : ScriptExecutionContext, startPosition : Vector4, endPosition : Vector4, optional offMeshTags : array< CName > ) : Bool
	{
		var query : AINavigationSystemQuery;
		var result : AINavigationSystemResult;
		var start : AIPositionSpec;
		var end : AIPositionSpec;
		var startWP : WorldPosition;
		var endWP : WorldPosition;
		var requestID : Uint32;
		var navigationSystem : AINavigationSystem;
		var pathfindingResult : Bool;
		WorldPosition.SetVector4( startWP, startPosition );
		WorldPosition.SetVector4( endWP, endPosition );
		AIPositionSpec.SetWorldPosition( start, startWP );
		AIPositionSpec.SetWorldPosition( end, endWP );
		if( offMeshTags.Size() > 0 )
		{
			query.allowedTags = offMeshTags;
		}
		query.source = start;
		query.target = end;
		navigationSystem = GameInstance.GetAINavigationSystem( ScriptExecutionContext.GetOwner( context ).GetGame() );
		requestID = navigationSystem.StartPathfinding( query );
		pathfindingResult = navigationSystem.GetResult( requestID, result );
		navigationSystem.StopPathfinding( requestID );
		if( pathfindingResult )
		{
			if( !( result.hasFailed ) )
			{
				return true;
			}
		}
		return false;
	}

	public static function GetClosestIndexInRange( context : ScriptExecutionContext, minOwnerDistance : Float, maxOwnerDistance : Float, const ownerDistances : ref< array< Float > >, minDistanceObj : Float, maxDistanceObj : Float, const distancesObj : ref< array< Float > >, const targetsPosition : array< Vector4 >, const allowedOffMeshTags : ref< array< CName > >, lineOfSightTarget : Vector4, blockLoSByNonPenetrableObj : Bool ) : Int32
	{
		var extremeDistance : Float;
		var targetPositionOffset : Vector4;
		var closestPointIndex : Int32;
		var currentMinDistanceObj : Float;
		var isMinDistanceSpecified : Bool;
		var isMaxDistanceSpecified : Bool;
		var isWithinMinDistance : Bool;
		var isWithinMaxDistance : Bool;
		var hasLoSTarget : Bool;
		var i : Int32;
		extremeDistance = 9999.0;
		targetPositionOffset = Vector4( 0.0, 0.0, 1.79999995, 0.0 );
		closestPointIndex = -1;
		if( ( targetsPosition.Size() != ownerDistances.Size() ) || ( targetsPosition.Size() != distancesObj.Size() ) )
		{
			return closestPointIndex;
		}
		if( maxDistanceObj < 0.0 )
		{
			maxDistanceObj = extremeDistance;
		}
		if( maxOwnerDistance < 0.0 )
		{
			maxOwnerDistance = extremeDistance;
		}
		currentMinDistanceObj = extremeDistance;
		isMinDistanceSpecified = ( minOwnerDistance >= 0.0 ) || ( minDistanceObj >= 0.0 );
		isMaxDistanceSpecified = ( maxOwnerDistance != extremeDistance ) || ( maxDistanceObj != extremeDistance );
		if( !( CheckPath( context, ScriptExecutionContext.GetOwner( context ).GetWorldPosition(), lineOfSightTarget, allowedOffMeshTags ) ) )
		{
			lineOfSightTarget = ScriptExecutionContext.GetOwner( context ).GetWorldPosition();
		}
		for( i = 0; i < ownerDistances.Size(); i += 1 )
		{
			isWithinMinDistance = ( ownerDistances[ i ] >= minOwnerDistance ) && ( distancesObj[ i ] >= minDistanceObj );
			if( isMinDistanceSpecified && !( isWithinMinDistance ) )
			{
				continue;
			}
			isWithinMaxDistance = ( ownerDistances[ i ] <= maxOwnerDistance ) && ( distancesObj[ i ] <= maxDistanceObj );
			if( isMaxDistanceSpecified && !( isWithinMaxDistance ) )
			{
				continue;
			}
			hasLoSTarget = !( Vector4.IsZero( lineOfSightTarget ) );
			if( hasLoSTarget && !( GameInstance.GetSenseManager( ScriptExecutionContext.GetOwner( context ).GetGame() ).IsPositionVisible( lineOfSightTarget + targetPositionOffset, targetsPosition[ i ] + targetPositionOffset, blockLoSByNonPenetrableObj ) ) )
			{
				continue;
			}
			if( !( CheckPath( context, ScriptExecutionContext.GetOwner( context ).GetWorldPosition(), targetsPosition[ i ], allowedOffMeshTags ) ) )
			{
				continue;
			}
			if( distancesObj[ i ] >= currentMinDistanceObj )
			{
				continue;
			}
			currentMinDistanceObj = distancesObj[ i ];
			closestPointIndex = i;
		}
		return closestPointIndex;
	}

	public static function GetFarthestIndexInRange( context : ScriptExecutionContext, minOwnerDistance : Float, maxOwnerDistance : Float, const ownerDistances : ref< array< Float > >, minDistanceObj : Float, maxDistanceObj : Float, const distancesObj : ref< array< Float > >, const targetsPosition : array< Vector4 >, const allowedOffMeshTags : ref< array< CName > >, lineOfSightTarget : Vector4, blockLoSByNonPenetrableObj : Bool ) : Int32
	{
		var extremeDistance : Float;
		var targetPositionOffset : Vector4;
		var farthestPointIndex : Int32;
		var currentMaxDistanceObj : Float;
		var isMinDistanceSpecified : Bool;
		var isMaxDistanceSpecified : Bool;
		var isWithinMinDistance : Bool;
		var isWithinMaxDistance : Bool;
		var hasLoSTarget : Bool;
		var i : Int32;
		extremeDistance = 9999.0;
		targetPositionOffset = Vector4( 0.0, 0.0, 1.79999995, 0.0 );
		farthestPointIndex = -1;
		if( ( targetsPosition.Size() != ownerDistances.Size() ) || ( targetsPosition.Size() != distancesObj.Size() ) )
		{
			return farthestPointIndex;
		}
		if( maxDistanceObj < 0.0 )
		{
			maxDistanceObj = extremeDistance;
		}
		if( maxOwnerDistance < 0.0 )
		{
			maxOwnerDistance = extremeDistance;
		}
		currentMaxDistanceObj = -( extremeDistance );
		isMinDistanceSpecified = ( minOwnerDistance >= 0.0 ) || ( minDistanceObj >= 0.0 );
		isMaxDistanceSpecified = ( maxOwnerDistance != extremeDistance ) || ( maxDistanceObj != extremeDistance );
		if( !( CheckPath( context, ScriptExecutionContext.GetOwner( context ).GetWorldPosition(), lineOfSightTarget, allowedOffMeshTags ) ) )
		{
			lineOfSightTarget = ScriptExecutionContext.GetOwner( context ).GetWorldPosition();
		}
		for( i = 0; i < ownerDistances.Size(); i += 1 )
		{
			isWithinMinDistance = ( ownerDistances[ i ] >= minOwnerDistance ) && ( distancesObj[ i ] >= minDistanceObj );
			if( isMinDistanceSpecified && !( isWithinMinDistance ) )
			{
				continue;
			}
			isWithinMaxDistance = ( ownerDistances[ i ] <= maxOwnerDistance ) && ( distancesObj[ i ] <= maxDistanceObj );
			if( isMaxDistanceSpecified && !( isWithinMaxDistance ) )
			{
				continue;
			}
			hasLoSTarget = !( Vector4.IsZero( lineOfSightTarget ) );
			if( hasLoSTarget && !( GameInstance.GetSenseManager( ScriptExecutionContext.GetOwner( context ).GetGame() ).IsPositionVisible( lineOfSightTarget + targetPositionOffset, targetsPosition[ i ] + targetPositionOffset, blockLoSByNonPenetrableObj ) ) )
			{
				continue;
			}
			if( !( CheckPath( context, ScriptExecutionContext.GetOwner( context ).GetWorldPosition(), targetsPosition[ i ], allowedOffMeshTags ) ) )
			{
				continue;
			}
			if( distancesObj[ i ] <= currentMaxDistanceObj )
			{
				continue;
			}
			currentMaxDistanceObj = distancesObj[ i ];
			farthestPointIndex = i;
		}
		return farthestPointIndex;
	}

	public static function GetRandomIndexInRange( context : ScriptExecutionContext, minOwnerDistance : Float, maxOwnerDistance : Float, const ownerDistances : ref< array< Float > >, minDistanceObj : Float, maxDistanceObj : Float, const distancesObj : ref< array< Float > >, const allowedOffMeshTags : ref< array< CName > >, optional targetsPosition : array< Vector4 >, lineOfSightTarget : Vector4, blockLoSByNonPenetrableObj : Bool ) : Int32
	{
		var extremeDistance : Float;
		var targetPositionOffset : Vector4;
		var selectedIndex : Int32;
		var filteredIndexes : array< Int32 >;
		var isMinDistanceSpecified : Bool;
		var isMaxDistanceSpecified : Bool;
		var isWithinMinDistance : Bool;
		var isWithinMaxDistance : Bool;
		var hasLoSTarget : Bool;
		var i : Int32;
		extremeDistance = 9999.0;
		targetPositionOffset = Vector4( 0.0, 0.0, 1.79999995, 0.0 );
		selectedIndex = -1;
		if( ( targetsPosition.Size() != ownerDistances.Size() ) || ( targetsPosition.Size() != distancesObj.Size() ) )
		{
			return selectedIndex;
		}
		if( maxDistanceObj < 0.0 )
		{
			maxDistanceObj = extremeDistance;
		}
		if( maxOwnerDistance < 0.0 )
		{
			maxOwnerDistance = extremeDistance;
		}
		isMinDistanceSpecified = ( minOwnerDistance >= 0.0 ) || ( minDistanceObj >= 0.0 );
		isMaxDistanceSpecified = ( maxOwnerDistance != extremeDistance ) || ( maxDistanceObj != extremeDistance );
		if( !( CheckPath( context, ScriptExecutionContext.GetOwner( context ).GetWorldPosition(), lineOfSightTarget, allowedOffMeshTags ) ) )
		{
			lineOfSightTarget = ScriptExecutionContext.GetOwner( context ).GetWorldPosition();
		}
		for( i = 0; i < ownerDistances.Size(); i += 1 )
		{
			isWithinMinDistance = ( ownerDistances[ i ] >= minOwnerDistance ) && ( distancesObj[ i ] >= minDistanceObj );
			if( isMinDistanceSpecified && !( isWithinMinDistance ) )
			{
				continue;
			}
			isWithinMaxDistance = ( ownerDistances[ i ] <= maxOwnerDistance ) && ( distancesObj[ i ] <= maxDistanceObj );
			if( isMaxDistanceSpecified && !( isWithinMaxDistance ) )
			{
				continue;
			}
			hasLoSTarget = !( Vector4.IsZero( lineOfSightTarget ) );
			if( hasLoSTarget && !( GameInstance.GetSenseManager( ScriptExecutionContext.GetOwner( context ).GetGame() ).IsPositionVisible( lineOfSightTarget + targetPositionOffset, targetsPosition[ i ] + targetPositionOffset, blockLoSByNonPenetrableObj ) ) )
			{
				continue;
			}
			if( !( CheckPath( context, ScriptExecutionContext.GetOwner( context ).GetWorldPosition(), targetsPosition[ i ], allowedOffMeshTags ) ) )
			{
				continue;
			}
			filteredIndexes.PushBack( i );
		}
		if( filteredIndexes.Size() > 0 )
		{
			selectedIndex = filteredIndexes[ RandRange( 0, filteredIndexes.Size() ) ];
		}
		return selectedIndex;
	}

}

abstract class AISubActionSetWaypointByTag_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionSetWaypointByTag_Record > ) {}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionSetWaypointByTag_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( ( record.Delay() >= 0.0 ) && ( duration >= record.Delay() ) )
		{
			if( SetWaypointByTag( context, record ) )
			{
				return AIbehaviorUpdateOutcome.SUCCESS;
			}
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionSetWaypointByTag_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			SetWaypointByTag( context, record );
		}
	}

	public static function SetWaypointByTag( context : ScriptExecutionContext, record : weak< AISubActionSetWaypointByTag_Record > ) : Bool
	{
		var targetPosition : Vector4;
		var lineOfSightTargetPosition : Vector4;
		var positions : array< Vector4 >;
		var excludedWaypoints : array< Vector4 >;
		var desiredDistance : Vector2;
		var desiredDistanceFromObj : Vector2;
		var toOwnerDistances : array< Float >;
		var toTargetsDistances : array< Float >;
		var allowedOffMeshTags : array< CName >;
		var blackboard : IBlackboard;
		var searchingForPosition : Bool;
		var index, i : Int32;
		if( !( IsNameValid( record.Tag() ) ) )
		{
			return false;
		}
		AIActionTarget.GetPosition( context, record.RangeObj(), targetPosition, false );
		if( Vector4.IsZero( targetPosition ) )
		{
			targetPosition = ScriptExecutionContext.GetOwner( context ).GetWorldPosition();
		}
		desiredDistance = record.RangeFromOwner();
		desiredDistanceFromObj = record.RangeFromObj();
		allowedOffMeshTags = record.AllowedOffMeshTags();
		blackboard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		searchingForPosition = record.Target().IsPosition();
		if( record.LineOfSightTarget() )
		{
			AIActionTarget.GetPosition( context, record.RangeObj(), lineOfSightTargetPosition, false );
		}
		GameInstance.FindWaypointsByTag( ScriptExecutionContext.GetOwner( context ).GetGame(), record.Tag(), positions );
		if( searchingForPosition && ( record.AvoidSelectingSameTargetMethod() == 1 ) )
		{
			excludedWaypoints = ( ( array< Vector4 > )( blackboard.GetVariant( GetAllBlackboardDefs().AIActionBossData.excludedWaypointPosition ) ) );
			if( excludedWaypoints.Size() > 0 )
			{
				index = positions.FindFirst( excludedWaypoints[ 0 ] );
				if( index >= 0 )
				{
					positions.EraseFast( index );
				}
				index = -1;
			}
		}
		else if( searchingForPosition && ( record.AvoidSelectingSameTargetMethod() == 2 ) )
		{
			excludedWaypoints = ( ( array< Vector4 > )( blackboard.GetVariant( GetAllBlackboardDefs().AIActionBossData.excludedWaypointPosition ) ) );
			if( excludedWaypoints.Size() > 0 )
			{
				for( i = 0; i < positions.Size(); i += 1 )
				{
					if( excludedWaypoints.Contains( positions[ i ] ) )
					{
						positions.EraseFast( i );
						i -= 1;
					}
				}
			}
		}
		AISubActionSetTargetByTag_Record_Implementation.GetDistancesFromTargetToPositions( context, ScriptExecutionContext.GetOwner( context ).GetWorldPosition(), positions, toOwnerDistances );
		AISubActionSetTargetByTag_Record_Implementation.GetDistancesFromTargetToPositions( context, targetPosition, positions, toTargetsDistances );
		index = AISubActionSetTargetByTag_Record_Implementation.SelectIndex( context, record.SelectionMethod(), desiredDistance.X, desiredDistance.Y, toOwnerDistances, desiredDistanceFromObj.X, desiredDistanceFromObj.Y, toTargetsDistances, positions, allowedOffMeshTags, lineOfSightTargetPosition, record.BlockLoSByNonPenetrableObj() );
		if( index < 0 )
		{
			return false;
		}
		targetPosition = positions[ index ];
		if( record.AvoidSelectingSameTargetMethod() == 1 )
		{
			excludedWaypoints.Clear();
			excludedWaypoints.PushBack( targetPosition );
			blackboard.SetVariant( GetAllBlackboardDefs().AIActionBossData.excludedWaypointPosition, excludedWaypoints );
		}
		else if( record.AvoidSelectingSameTargetMethod() == 2 )
		{
			excludedWaypoints.PushBack( targetPosition );
			blackboard.SetVariant( GetAllBlackboardDefs().AIActionBossData.excludedWaypointPosition, excludedWaypoints );
		}
		return AIActionTarget.Set( context, record.Target(), NULL, targetPosition );
	}

}

abstract class AISubActionSetInfluenceMap_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionSetInfluenceMap_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			SetInfluenceMap( context, record );
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionSetInfluenceMap_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			SetInfluenceMap( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionSetInfluenceMap_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			SetInfluenceMap( context, record );
		}
	}

	public static function SetInfluenceMap( context : ScriptExecutionContext, record : weak< AISubActionSetInfluenceMap_Record > )
	{
		var object : weak< GameObject >;
		var lerp : Vector2;
		if( AIActionTarget.GetObject( context, record.PositionObj(), object ) )
		{
			lerp = record.Lerp();
			if( !( record.Threat() ) )
			{
				if( ( lerp.X >= 0.0 ) && ( lerp.Y >= 0.0 ) )
				{
					GameInstance.GetInfluenceMapSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).SetSearchValueLerp( object.GetWorldPosition(), record.Radius(), lerp.X, lerp.Y );
				}
				else
				{
					GameInstance.GetInfluenceMapSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).SetSearchValue( object.GetWorldPosition(), record.Radius() );
				}
			}
		}
	}

}

abstract class AISubActionSetStimSource_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionSetStimSource_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			SetStimSource( context, record );
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionSetStimSource_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			SetStimSource( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionSetStimSource_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			SetStimSource( context, record );
		}
	}

	public static function SetStimSource( context : ScriptExecutionContext, record : weak< AISubActionSetStimSource_Record > )
	{
		var object : weak< GameObject >;
		var position : Vector4;
		var investigateData : stimInvestigateData;
		var puppet : weak< ScriptedPuppet >;
		var reactionData : AIReactionData;
		var investigationPositions : array< Vector4 >;
		var distance : Float;
		var closestDistance : Float;
		var i : Int32;
		if( record.UseInvestigateData() )
		{
			puppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
			investigateData = puppet.GetStimReactionComponent().GetActiveReactionData().stimInvestigateData;
			investigationPositions = ( ( Device )( investigateData.controllerEntity ) ).GetNodePosition();
			for( i = 0; i < investigationPositions.Size(); i += 1 )
			{
				distance = Vector4.Distance( investigationPositions[ i ], ScriptExecutionContext.GetOwner( context ).GetWorldPosition() );
				if( ( distance < closestDistance ) || ( closestDistance == 0.0 ) )
				{
					closestDistance = distance;
					position = investigationPositions[ i ];
				}
			}
			if( !( Vector4.IsZero( position ) ) )
			{
				SetStimSourcePosition( context, record, position );
			}
			else
			{
				SetStimSourcePosition( context, record, investigateData.controllerEntity.GetWorldPosition() );
			}
			ScriptExecutionContext.SetArgumentObject( context, 'StimTarget', ( ( GameObject )( investigateData.controllerEntity ) ) );
		}
		else if( record.StimTarget().IsObject() )
		{
			if( AIActionTarget.GetObject( context, record.StimTarget(), object ) )
			{
				ScriptExecutionContext.SetArgumentObject( context, 'StimTarget', object );
				SetStimSourcePosition( context, record, object.GetWorldPosition() );
			}
		}
		else if( record.StimTarget().IsPosition() )
		{
			if( AIActionTarget.GetPosition( context, record.StimTarget(), position, false ) )
			{
				SetStimSourcePosition( context, record, position );
			}
		}
		else
		{
			puppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
			reactionData = puppet.GetStimReactionComponent().GetDesiredReactionData();
			ScriptExecutionContext.SetArgumentObject( context, 'StimTarget', reactionData.stimTarget );
			SetStimSourcePosition( context, record, reactionData.stimSource );
		}
	}

	private static function SetStimSourcePosition( context : ScriptExecutionContext, record : weak< AISubActionSetStimSource_Record >, position : Vector4 )
	{
		if( record.RevertStimSourceDirection() )
		{
			position = ( 2.0 * ScriptExecutionContext.GetOwner( context ).GetWorldPosition() ) - position;
		}
		ScriptExecutionContext.SetArgumentVector( context, 'StimSource', position );
	}

}

abstract class AISubActionWorkspot_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionWorkspot_Record > )
	{
		ReserveWorkspot( context, record );
	}

	public constexpr static function Update( context : ScriptExecutionContext, record : weak< AISubActionWorkspot_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionWorkspot_Record >, const duration : Float, interrupted : Bool )
	{
		ReleaseWorkspot( context, record );
	}

	public static function ReserveWorkspot( context : ScriptExecutionContext, record : weak< AISubActionWorkspot_Record > )
	{
		var object : weak< GameObject >;
		var reserveWorkspotEvent : OnReserveWorkspotEvent;
		var workspotData : WorkspotEntryData;
		if( AIActionTarget.GetObject( context, record.WorkspotObject(), object ) )
		{
			reserveWorkspotEvent = new OnReserveWorkspotEvent;
			workspotData = object.GetFreeWorkspotDataForAIAction( gamedataWorkspotActionType.DeviceInvestigation );
			workspotData.isAvailable = false;
			ScriptExecutionContext.SetArgumentNodeRef( context, 'WorkspotNode', workspotData.workspotRef );
			reserveWorkspotEvent.workspotRef = workspotData.workspotRef;
			object.QueueEvent( reserveWorkspotEvent );
		}
	}

	public static function ReleaseWorkspot( context : ScriptExecutionContext, record : weak< AISubActionWorkspot_Record > )
	{
		var object : weak< GameObject >;
		var workspotRef : NodeRef;
		var releaseWorkspotEvent : OnReleaseWorkspotEvent;
		if( AIActionTarget.GetObject( context, record.WorkspotObject(), object ) )
		{
			releaseWorkspotEvent = new OnReleaseWorkspotEvent;
			workspotRef = ScriptExecutionContext.GetArgumentNodeRef( context, 'WorkspotNode' );
			releaseWorkspotEvent.workspotRef = workspotRef;
			object.QueueEvent( releaseWorkspotEvent );
		}
	}

}

abstract class AISubActionChangeCoverSelectionPreset_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionChangeCoverSelectionPreset_Record > )
	{
		var presetName : CName;
		var presetThreshold : Float;
		var object : weak< GameObject >;
		var blackboard : IBlackboard;
		blackboard = AICoverHelper.GetCoverBlackboard( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ) );
		if( IsNameValid( record.Preset() ) )
		{
			ScriptExecutionContext.SetArgumentName( context, 'CoverSelectionPreset', record.Preset() );
			blackboard.SetName( GetAllBlackboardDefs().AICover.lastCoverPreset, record.Preset() );
		}
		else if( record.FallbackToLastSelectedPreset() )
		{
			presetName = blackboard.GetName( GetAllBlackboardDefs().AICover.lastCoverPreset );
			if( IsNameValid( presetName ) )
			{
				blackboard.SetName( GetAllBlackboardDefs().AICover.lastCoverPreset, presetName );
			}
		}
		AIActionTarget.GetObject( context, record.GatheringObjectCenter(), object );
		ScriptExecutionContext.SetArgumentObject( context, 'CoverGatheringCenterObject', object );
		ScriptExecutionContext.SetArgumentFloat( context, 'CoverDisablingDuration', record.CoverDisablingDuration() );
		if( IsNameValid( record.InitialPreset() ) )
		{
			ScriptExecutionContext.SetArgumentName( context, 'CoverSelectionInitialPreset', record.InitialPreset() );
			blackboard.SetName( GetAllBlackboardDefs().AICover.lastInitialCoverPreset, record.Preset() );
		}
		else if( record.FallbackToLastSelectedPreset() )
		{
			presetName = blackboard.GetName( GetAllBlackboardDefs().AICover.lastInitialCoverPreset );
			if( IsNameValid( presetName ) )
			{
				blackboard.SetName( GetAllBlackboardDefs().AICover.lastInitialCoverPreset, presetName );
			}
		}
		if( record.ChangeThreshold() >= 0.0 )
		{
			ScriptExecutionContext.SetArgumentFloat( context, 'CoverSelectionChangeThreshold', record.ChangeThreshold() );
			blackboard.SetFloat( GetAllBlackboardDefs().AICover.lastCoverChangeThreshold, record.ChangeThreshold() );
		}
		else if( record.FallbackToLastSelectedPreset() )
		{
			presetThreshold = blackboard.GetFloat( GetAllBlackboardDefs().AICover.lastCoverChangeThreshold );
			if( presetThreshold >= 0.0 )
			{
				blackboard.SetFloat( GetAllBlackboardDefs().AICover.lastCoverChangeThreshold, presetThreshold );
			}
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionChangeCoverSelectionPreset_Record >, duration : Float ) : AIbehaviorUpdateOutcome
	{
		var object : weak< GameObject >;
		if( !( IsNameValid( ScriptExecutionContext.GetArgumentName( context, 'CoverSelectionPreset' ) ) ) && !( IsNameValid( ScriptExecutionContext.GetArgumentName( context, 'CoverSelectionInitialPreset' ) ) ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		AIActionTarget.GetObject( context, record.GatheringObjectCenter(), object );
		ScriptExecutionContext.SetArgumentObject( context, 'CoverGatheringCenterObject', object );
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionChangeCoverSelectionPreset_Record >, const duration : Float, interrupted : Bool ) {}
}

abstract class AISubActionStartCooldown_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionStartCooldown_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			StartCooldowns( context, record );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionStartCooldown_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.MinActionDuration() > 0.0 ) && ( record.MinActionDuration() > duration ) )
		{
			return AIbehaviorUpdateOutcome.IN_PROGRESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			StartCooldowns( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionStartCooldown_Record >, const duration : Float, interrupted : Bool )
	{
		if( ( record.MinActionDuration() > 0.0 ) && ( record.MinActionDuration() > duration ) )
		{
			return;
		}
		if( record.Delay() < 0.0 )
		{
			StartCooldowns( context, record );
		}
	}

	public static function StartCooldowns( context : ScriptExecutionContext, record : AISubActionStartCooldown_Record )
	{
		var i : Int32;
		var count : Int32;
		var puppet : gamePuppet;
		count = record.GetCooldownsCount();
		if( count > 0 )
		{
			puppet = ScriptExecutionContext.GetOwner( context );
			for( i = 0; i < count; i += 1 )
			{
				AIActionHelper.StartCooldown( puppet, record.GetCooldownsItem( i ) );
			}
		}
	}

}

abstract class AISubActionSquadSync_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionSquadSync_Record > )
	{
		SquadSync( context, record );
	}

	public constexpr static function Update( context : ScriptExecutionContext, record : weak< AISubActionSquadSync_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionSquadSync_Record >, const duration : Float, interrupted : Bool )
	{
		SquadSync( context, record );
	}

	public static function SquadSync( context : ScriptExecutionContext, record : weak< AISubActionSquadSync_Record > )
	{
		var puppet : ScriptedPuppet;
		var squadType : AISquadType;
		puppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		if( !( puppet ) )
		{
			return;
		}
		squadType = AISquadType.Combat;
		if( !( StatusEffectSystem.ObjectHasStatusEffectWithTag( ScriptExecutionContext.GetOwner( context ), 'ResetSquadSync' ) ) )
		{
			if( record.Pull() )
			{
				AISquadHelper.PullSquadSync( puppet, squadType );
			}
			else
			{
				puppet.GetTargetTrackerComponent().PushSquadSync( squadType );
			}
		}
	}

}

abstract class AISubActionSecuritySystemNotification_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionSecuritySystemNotification_Record > )
	{
		NotifySecuritySystem( context, record );
	}

	public constexpr export static function Update( context : ScriptExecutionContext, record : weak< AISubActionSecuritySystemNotification_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionSecuritySystemNotification_Record >, const duration : Float, interrupted : Bool ) {}

	public static function NotifySecuritySystem( context : ScriptExecutionContext, record : weak< AISubActionSecuritySystemNotification_Record > )
	{
		var puppet : weak< ScriptedPuppet >;
		var threat : weak< GameObject >;
		var threatLocation : TrackedLocation;
		var notificationType : ESecurityNotificationType;
		var pos : Vector4;
		puppet = ( ( weak< weak< ScriptedPuppet > > )( ScriptExecutionContext.GetOwner( context ) ) );
		if( !( AIActionTarget.GetObject( context, record.Threat(), threat ) ) )
		{
			AIActionHelper.GetActiveTopHostilePuppetThreat( puppet, threatLocation );
			threat = ( ( weak< weak< GameObject > > )( threatLocation.entity ) );
		}
		notificationType = ( ( ESecurityNotificationType )( ( ( Int32 )( EnumValueFromName( 'ESecurityNotificationType', record.NotificationType().EnumName() ) ) ) ) );
		if( threat )
		{
			pos = threatLocation.sharedLocation.position;
			if( Vector4.IsZero( pos ) )
			{
				pos = threatLocation.location.position;
			}
			puppet.TriggerSecuritySystemNotification( pos, threat, notificationType );
		}
	}

}

abstract class AISubActionCallSquadSearchBackUp_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionCallSquadSearchBackUp_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			CallBackup( context, record );
		}
	}

	public constexpr static function Update( context : ScriptExecutionContext, record : weak< AISubActionCallSquadSearchBackUp_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			CallBackup( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionCallSquadSearchBackUp_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			CallBackup( context, record );
		}
	}

	public static function CallBackup( context : ScriptExecutionContext, record : weak< AISubActionCallSquadSearchBackUp_Record > )
	{
		var owner : GameObject;
		var broadcaster : StimBroadcasterComponent;
		var psi : PuppetSquadInterface;
		var member : weak< Entity >;
		var members : array< weak< Entity > >;
		var membersDistances : array< Float >;
		var memberObject : GameObject;
		var ownerPosition : Vector4;
		var diff : Vector4;
		var distance : Float;
		var i : Int32;
		var j : Int32;
		var commsCallEffects : array< StatusEffect >;
		var whistleEffects : array< StatusEffect >;
		var combatVersion : Bool;
		var numberOfTargets : Int32;
		var statsSystem : StatsSystem;
		var player : GameObject;
		var maxDistance : Float;
		var minDistance : Float;
		var minSkipThreshold : Int32;
		var skippedCount : Int32;
		var calledCount : Int32;
		var remainingDuration : Float;
		var ownerReactionComp : ReactionManagerComponent;
		owner = ScriptExecutionContext.GetOwner( context );
		numberOfTargets = 1;
		maxDistance = 0.0;
		AISquadHelper.GetSquadBaseInterface( owner, psi );
		members = psi.ListMembersWeak();
		members.Remove( owner );
		if( members.Size() == 0 )
		{
			return;
		}
		if( record.UseCommsCallLogic() || ( record.NumberOfTargets() > 0.0 ) )
		{
			ownerPosition = owner.GetWorldPosition();
			for( i = 0; i < members.Size(); i += 1 )
			{
				diff = members[ i ].GetWorldPosition() - ownerPosition;
				distance = Vector4.Length( diff );
				membersDistances.PushBack( distance );
			}
			for( i = 0; i < ( members.Size() - 1 ); i += 1 )
			{
				for( j = 0; j < ( ( members.Size() - i ) - 1 ); j += 1 )
				{
					if( membersDistances[ j ] > membersDistances[ ( j + 1 ) ] )
					{
						member = members[ j ];
						members[ j ] = members[ j + 1 ];
						members[ j + 1 ] = member;
						distance = membersDistances[ j ];
						membersDistances[ j ] = membersDistances[ j + 1 ];
						membersDistances[ j + 1 ] = distance;
					}
				}
			}
		}
		if( !( record.UseCommsCallLogic() ) )
		{
			broadcaster = owner.GetStimBroadcasterComponent();
			if( !( broadcaster ) )
			{
				return;
			}
			for( i = 0; ( i < members.Size() ) && ( ( record.NumberOfTargets() <= 0.0 ) || ( i < ( ( Int32 )( record.NumberOfTargets() ) ) ) ); i += 1 )
			{
				memberObject = ( ( GameObject )( members[ i ] ) );
				broadcaster.SendDrirectStimuliToTarget( owner, gamedataStimType.Call, memberObject );
			}
			return;
		}
		StatusEffectHelper.GetAppliedEffectsWithTag( owner, 'CommsCallIn', commsCallEffects );
		if( commsCallEffects.Size() == 0 )
		{
			return;
		}
		StatusEffectHelper.GetAppliedEffectsWithTag( owner, 'Whistle', whistleEffects );
		if( whistleEffects.Size() > 0 )
		{
			if( StatusEffectSystem.ObjectHasStatusEffectWithTag( owner, 'CommsCallInMultipleOnWhistle' ) )
			{
				numberOfTargets = 4;
			}
			else if( StatusEffectSystem.ObjectHasStatusEffectWithTag( owner, 'CommsCallInMultipleOnWhistle2' ) )
			{
				numberOfTargets = 5;
			}
			if( whistleEffects[ 0 ].GetLastApplicationSimTimestamp() < commsCallEffects[ 0 ].GetLastApplicationSimTimestamp() )
			{
				StatusEffectHelper.RemoveStatusEffectsWithTag( owner, 'Whistle' );
				ownerReactionComp = ( ( ScriptedPuppet )( owner ) ).GetStimReactionComponent();
				if( ownerReactionComp && ownerReactionComp.GetPendingReactionName() == gamedataOutput.PlayerCall )
				{
					ownerReactionComp.ClearPendingReaction();
				}
			}
		}
		statsSystem = GameInstance.GetStatsSystem( owner.GetGame() );
		player = GameInstance.GetPlayerSystem( owner.GetGame() ).GetLocalPlayerControlledGameObject();
		maxDistance = statsSystem.GetStatValue( player.GetEntityID(), gamedataStatType.CommsCallDistance );
		combatVersion = StatusEffectSystem.ObjectHasStatusEffectWithTag( owner, 'CombatCommsCallIn' );
		remainingDuration = commsCallEffects[ 0 ].GetRemainingDuration();
		if( record.Invert() )
		{
			memberObject = ( ( GameObject )( members[ 0 ] ) );
			for( i = 1; i < members.Size(); i += 1 )
			{
				if( membersDistances[ i ] > maxDistance )
				{
					break;
				}
				memberObject = ( ( GameObject )( members[ i ] ) );
			}
			CallBackupOneTarget( memberObject, owner, combatVersion, remainingDuration, true );
			return;
		}
		calledCount = 0;
		skippedCount = 0;
		minDistance = 4.0;
		minSkipThreshold = 2;
		for( i = 0; ( i < members.Size() ) && ( calledCount < numberOfTargets ); i += 1 )
		{
			if( ( i > 0 ) && ( membersDistances[ i ] > maxDistance ) )
			{
				break;
			}
			if( ( i < minSkipThreshold ) && ( membersDistances[ i ] < minDistance ) )
			{
				skippedCount += 1;
				continue;
			}
			memberObject = ( ( GameObject )( members[ i ] ) );
			CallBackupOneTarget( owner, memberObject, combatVersion, remainingDuration, false );
			calledCount += 1;
		}
		for( i = 0; ( i < skippedCount ) && ( calledCount < numberOfTargets ); i += 1 )
		{
			memberObject = ( ( GameObject )( members[ i ] ) );
			CallBackupOneTarget( owner, memberObject, combatVersion, remainingDuration, false );
			calledCount += 1;
		}
	}

	private static function CallBackupOneTarget( source : GameObject, target : GameObject, combatVersion : Bool, remainingDuration : Float, purelyDirect : Bool )
	{
		var broadcaster : StimBroadcasterComponent;
		broadcaster = source.GetStimBroadcasterComponent();
		if( !( broadcaster ) )
		{
			return;
		}
		broadcaster.SendDrirectStimuliToTarget( source, ( ( combatVersion ) ? ( gamedataStimType.CombatCall ) : ( gamedataStimType.Call ) ), target, , , purelyDirect );
		if( combatVersion )
		{
			StatusEffectHelper.ApplyStatusEffectForTimeWindow( target, T"BaseStatusEffect.CommsCallCombatTargetHelper", source.GetEntityID(), 0.0, remainingDuration );
		}
	}

}

abstract class AISubActionQuickHack_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionQuickHack_Record > )
	{
		VisualiseConnection( context, record );
		Hack( context, record );
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionQuickHack_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var signalTable : gameBoolSignalTable;
		var signalId : Uint16;
		signalTable = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetSignalTable();
		if( signalTable )
		{
			signalId = signalTable.GetOrCreateSignal( 'HackingCompleted' );
			if( signalTable.GetCurrentValue( signalId ) )
			{
				return AIbehaviorUpdateOutcome.SUCCESS;
			}
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionQuickHack_Record >, const duration : Float, interrupted : Bool )
	{
		CancelConnection( context, record );
	}

	public static function VisualiseConnection( context : ScriptExecutionContext, record : weak< AISubActionQuickHack_Record > )
	{
		var target : weak< GameObject >;
		var proxy : weak< GameObject >;
		var linkedStatusEffect : LinkedStatusEffect;
		if( !( AIActionTarget.GetObject( context, record.Target(), target ) ) )
		{
			return;
		}
		if( target == ScriptExecutionContext.GetOwner( context ) )
		{
			return;
		}
		linkedStatusEffect = ( ( ScriptedPuppet )( target ) ).GetLinkedStatusEffect();
		if( !( linkedStatusEffect.netrunnerIDs.Contains( ScriptExecutionContext.GetOwner( context ).GetEntityID() ) ) && ( GameInstance.GetPlayerSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetLocalPlayerMainGameObject() == target ) )
		{
			GameObjectEffectHelper.StartEffectEvent( target, 'disabling_connectivity_glitch' );
		}
		proxy = AIActionTarget.GetNetrunnerProxy( context );
		if( proxy )
		{
			ScriptExecutionContext.SetArgumentObject( context, 'NetrunnerProxy', proxy );
			SendNetworkLinkEvent( ScriptExecutionContext.GetOwner( context ), proxy, target, ScriptExecutionContext.GetOwner( context ), proxy );
			SendNetworkLinkEvent( ScriptExecutionContext.GetOwner( context ), proxy, target, proxy, target );
		}
		else
		{
			ScriptExecutionContext.SetArgumentObject( context, 'NetrunnerProxy', NULL );
			SendNetworkLinkEvent( ScriptExecutionContext.GetOwner( context ), proxy, target, ScriptExecutionContext.GetOwner( context ), target );
		}
	}

	public static function CancelConnection( context : ScriptExecutionContext, record : weak< AISubActionQuickHack_Record > )
	{
		var signalTable : gameBoolSignalTable;
		var signalId : Uint16;
		signalTable = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetSignalTable();
		if( signalTable )
		{
			signalId = signalTable.GetOrCreateSignal( 'HackingCompleted' );
			if( !( signalTable.GetCurrentValue( signalId ) ) )
			{
				if( StatusEffectSystem.ObjectHasStatusEffect( ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetLocalPlayerMainGameObject() ) ), T"StatusEffect.HackReveal" ) )
				{
					StatusEffectHelper.ApplyStatusEffect( ScriptExecutionContext.GetOwner( context ), T"AIQuickHackStatusEffect.HackRevealInterrupted", ScriptExecutionContext.GetOwner( context ).GetEntityID() );
				}
				else
				{
					StatusEffectHelper.ApplyStatusEffect( ScriptExecutionContext.GetOwner( context ), T"AIQuickHackStatusEffect.HackingInterrupted", ScriptExecutionContext.GetOwner( context ).GetEntityID() );
				}
			}
		}
		ScriptExecutionContext.SetArgumentObject( context, 'NetrunnerProxy', NULL );
	}

	public static function Hack( context : ScriptExecutionContext, record : weak< AISubActionQuickHack_Record > )
	{
		var target : weak< GameObject >;
		var evt : HackTargetEvent;
		if( !( AIActionTarget.GetObject( context, record.Target(), target ) ) )
		{
			return;
		}
		if( StatusEffectSystem.ObjectHasStatusEffect( ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetLocalPlayerMainGameObject() ) ), T"StatusEffect.HackReveal" ) )
		{
			StatusEffectHelper.RemoveStatusEffect( ScriptExecutionContext.GetOwner( context ), T"AIQuickHackStatusEffect.HackRevealInterrupted" );
		}
		else
		{
			StatusEffectHelper.RemoveStatusEffect( ScriptExecutionContext.GetOwner( context ), T"AIQuickHackStatusEffect.HackingInterrupted" );
		}
		evt = new HackTargetEvent;
		evt.targetID = target.GetEntityID();
		evt.netrunnerID = ScriptExecutionContext.GetOwner( context ).GetEntityID();
		evt.objectRecord = record.ActionResult();
		evt.settings.isRevealPositionAction = evt.objectRecord.GetRecordID() == T"AIQuickHack.HackReveal";
		target.QueueEvent( evt );
	}

	public static function SendNetworkLinkEvent( netrunner, proxy, target, from, to : weak< GameObject > )
	{
		var evt : NetworkLinkQuickhackEvent;
		evt = new NetworkLinkQuickhackEvent;
		evt.netrunnerID = netrunner.GetEntityID();
		evt.proxyID = proxy.GetEntityID();
		evt.targetID = target.GetEntityID();
		evt.from = from.GetEntityID();
		evt.to = to.GetEntityID();
		from.QueueEvent( evt );
	}

}

abstract class AISubActionForceHitReaction_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionForceHitReaction_Record > )
	{
		var directTarget : weak< GameObject >;
		if( record.Delay() == 0.0 )
		{
			AIActionTarget.GetObject( context, record.Target(), directTarget );
			if( record.HitType() == 0 )
			{
				SendForcedTwitchDataToAnimationGraph( directTarget, record.HitDirection(), record.HitIntensity(), record.HitType(), record.HitBodyPart(), record.Stance(), record.AnimVariation(), record.HitSource() );
			}
			else
			{
				SendForcedHitDataToAIBehavior( directTarget, record.HitDirection(), record.HitIntensity(), record.HitType(), record.HitBodyPart(), record.Stance(), record.AnimVariation(), record.HitSource() );
			}
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionForceHitReaction_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var directTarget : weak< GameObject >;
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			AIActionTarget.GetObject( context, record.Target(), directTarget );
			if( record.HitType() == 1 )
			{
				SendForcedTwitchDataToAnimationGraph( directTarget, record.HitDirection(), record.HitIntensity(), record.HitType(), record.HitBodyPart(), record.Stance(), record.AnimVariation(), record.HitSource() );
			}
			else
			{
				SendForcedHitDataToAIBehavior( directTarget, record.HitDirection(), record.HitIntensity(), record.HitType(), record.HitBodyPart(), record.Stance(), record.AnimVariation(), record.HitSource() );
			}
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionForceHitReaction_Record >, const duration : Float, interrupted : Bool ) {}

	public static function SendForcedTwitchDataToAnimationGraph( target : GameObject, hitDirection : Int32, hitIntensity : Int32, hitType : Int32, hitBodyPart : Int32, stance : Int32, animVariation : Int32, hitSource : Int32 )
	{
		var animHitReaction : AnimFeature_HitReactionsData;
		animHitReaction = new AnimFeature_HitReactionsData;
		animHitReaction.hitDirection = hitDirection;
		animHitReaction.hitIntensity = hitIntensity;
		animHitReaction.hitType = 0;
		animHitReaction.hitBodyPart = hitBodyPart;
		animHitReaction.stance = stance;
		animHitReaction.animVariation = animVariation;
		animHitReaction.hitSource = hitSource;
		AnimationControllerComponent.ApplyFeatureToReplicate( target, 'hit', animHitReaction );
		AnimationControllerComponent.PushEventToReplicate( target, 'hit' );
	}

	public static function SendForcedHitDataToAIBehavior( target : GameObject, hitDirection : Int32, hitIntensity : Int32, hitType : Int32, hitBodyPart : Int32, stance : Int32, animVariation : Int32, hitSource : Int32 )
	{
		var hitAIEvent : StimuliEvent;
		var hitDataEvent : NewHitDataEvent;
		hitAIEvent = new StimuliEvent;
		hitAIEvent.id = ( ( ScriptedPuppet )( target ) ).GetHitReactionComponent().UpdateLastStimID();
		hitDataEvent = new NewHitDataEvent;
		hitDataEvent.hitIntensity = hitIntensity;
		hitDataEvent.hitDirection = hitDirection;
		hitDataEvent.hitSource = hitSource;
		hitDataEvent.hitType = hitType;
		hitDataEvent.hitBodyPart = hitBodyPart;
		hitDataEvent.stance = stance;
		hitDataEvent.animVariation = animVariation;
		switch( hitType )
		{
			case 1:
				hitAIEvent.name = 'Twitch';
			break;
			case 2:
				hitAIEvent.name = 'Impact';
			break;
			case 3:
				hitAIEvent.name = 'Stagger';
			break;
			case 4:
				hitAIEvent.name = 'Knockdown';
			break;
			case 9:
				hitAIEvent.name = 'GuardBreak';
			break;
			default:
				return;
		}
		( ( ScriptedPuppet )( target ) ).GetHitReactionComponent().SetLastStimName( hitAIEvent.name );
		target.QueueEvent( hitDataEvent );
		target.QueueEvent( hitAIEvent );
	}

}

abstract class AISubActionActivateStrongArmsFX_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionActivateStrongArmsFX_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			SpawnStrongArmsFX( context );
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionActivateStrongArmsFX_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			SpawnStrongArmsFX( context );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionActivateStrongArmsFX_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			SpawnStrongArmsFX( context );
		}
	}

	public static function SpawnStrongArmsFX( context : ScriptExecutionContext )
	{
		var cachedThreshold : Float;
		var statSystem : StatsSystem;
		var weaponID : StatsObjectID;
		var damageType : gamedataDamageType;
		var weapon : weak< WeaponObject >;
		weapon = ScriptedPuppet.GetWeaponRight( ScriptExecutionContext.GetOwner( context ) );
		if( !( weapon ) )
		{
			return;
		}
		statSystem = GameInstance.GetStatsSystem( weapon.GetGame() );
		weaponID = weapon.GetEntityID();
		cachedThreshold = statSystem.GetStatValue( weaponID, gamedataStatType.PhysicalDamage );
		damageType = gamedataDamageType.Physical;
		if( statSystem.GetStatValue( weaponID, gamedataStatType.ThermalDamage ) > cachedThreshold )
		{
			cachedThreshold = statSystem.GetStatValue( weaponID, gamedataStatType.ThermalDamage );
			damageType = gamedataDamageType.Thermal;
		}
		if( statSystem.GetStatValue( weaponID, gamedataStatType.ElectricDamage ) > cachedThreshold )
		{
			cachedThreshold = statSystem.GetStatValue( weaponID, gamedataStatType.ElectricDamage );
			damageType = gamedataDamageType.Electric;
		}
		if( statSystem.GetStatValue( weaponID, gamedataStatType.ChemicalDamage ) > cachedThreshold )
		{
			cachedThreshold = statSystem.GetStatValue( weaponID, gamedataStatType.ChemicalDamage );
			damageType = gamedataDamageType.Chemical;
		}
		if( damageType == gamedataDamageType.Physical )
		{
			StatusEffectHelper.ApplyStatusEffect( ScriptExecutionContext.GetOwner( context ), T"BaseStatusEffect.StrongArmsPhysicalActive", ScriptExecutionContext.GetOwner( context ).GetEntityID() );
		}
		else if( damageType == gamedataDamageType.Thermal )
		{
			StatusEffectHelper.ApplyStatusEffect( ScriptExecutionContext.GetOwner( context ), T"BaseStatusEffect.StrongArmsThermalActive", ScriptExecutionContext.GetOwner( context ).GetEntityID() );
		}
		else if( damageType == gamedataDamageType.Chemical )
		{
			StatusEffectHelper.ApplyStatusEffect( ScriptExecutionContext.GetOwner( context ), T"BaseStatusEffect.StrongArmsChemicalActive", ScriptExecutionContext.GetOwner( context ).GetEntityID() );
		}
		else if( damageType == gamedataDamageType.Electric )
		{
			StatusEffectHelper.ApplyStatusEffect( ScriptExecutionContext.GetOwner( context ), T"BaseStatusEffect.StrongArmsElecricActive", ScriptExecutionContext.GetOwner( context ).GetEntityID() );
		}
	}

}

abstract class AISubActionMountVehicle_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionMountVehicle_Record > ) {}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionMountVehicle_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( MountVehicle( context, record ) )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.FAILURE;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionMountVehicle_Record >, const duration : Float, interrupted : Bool ) {}

	private static function GetAIComponent( context : ScriptExecutionContext ) : AIHumanComponent
	{
		var comp : AIHumanComponent;
		AIHumanComponent.Get( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), comp );
		return comp;
	}

	public static function MountVehicle( context : ScriptExecutionContext, record : weak< AISubActionMountVehicle_Record > ) : Bool
	{
		var vehicle : weak< VehicleObject >;
		var wheeledObject : weak< WheeledObject >;
		var evt : MountAIEvent;
		var mountData : MountEventData;
		var slotName : CName;
		var ownerPuppet : weak< ScriptedPuppet >;
		var aiComponent : AIHumanComponent;
		aiComponent = GetAIComponent( context );
		if( !( AIActionTarget.GetVehicleObject( context, record.Vehicle(), vehicle ) ) )
		{
			return false;
		}
		wheeledObject = ( ( weak< weak< WheeledObject > > )( vehicle ) );
		if( !( wheeledObject ) )
		{
			return false;
		}
		if( !( record.IgnoreFlatTires() ) && ( wheeledObject.GetFlatTireIndex() != -1 ) )
		{
			return false;
		}
		if( vehicle.GetVehicleComponent().IsVehicleInDecay() )
		{
			return false;
		}
		if( ScriptExecutionContext.GetOwner( context ).IsPrevention() )
		{
			if( ( vehicle.ComputeIsVehicleUpsideDown() || VehicleComponent.IsDriverSeatOccupiedByDeadNPC( ScriptExecutionContext.GetOwner( context ).GetGame(), vehicle.GetEntityID() ) ) || aiComponent.IsAssignedVehicleStuck() )
			{
				return false;
			}
		}
		if( vehicle.IsVehicleRemoteControlled() )
		{
			return false;
		}
		if( vehicle.IsDestroyed() )
		{
			return false;
		}
		slotName = record.Slot().SeatName();
		if( slotName == 'first_available' && vehicle.GetAIComponent() )
		{
			slotName = vehicle.GetAIComponent().TryReserveSeatOrFirstAvailable( ScriptExecutionContext.GetOwner( context ).GetEntityID(), slotName );
			if( IsNameValid( slotName ) && aiComponent )
			{
				aiComponent.OnSeatReserved( vehicle.GetEntityID() );
			}
			else
			{
				return false;
			}
		}
		else
		{
			if( IsNameValid( slotName ) )
			{
				if( VehicleComponent.IsSlotAvailable( ScriptExecutionContext.GetOwner( context ).GetGame(), vehicle, slotName ) )
				{
					return false;
				}
			}
			else
			{
				if( !( AIHumanComponent.GetLastUsedVehicleSlot( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), slotName ) ) )
				{
					slotName = '';
				}
				if( !( IsNameValid( slotName ) ) || !( VehicleComponent.IsSlotAvailable( ScriptExecutionContext.GetOwner( context ).GetGame(), vehicle, slotName ) ) )
				{
					if( !( VehicleComponent.GetFirstAvailableSlot( ScriptExecutionContext.GetOwner( context ).GetGame(), vehicle, slotName ) ) )
					{
						return false;
					}
				}
			}
		}
		mountData = new MountEventData;
		mountData.slotName = slotName;
		mountData.mountParentEntityId = vehicle.GetEntityID();
		mountData.isInstant = record.MountInstantly();
		mountData.ignoreHLS = true;
		ownerPuppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		if( ownerPuppet && ownerPuppet.GetHighLevelStateFromBlackboard() == gamedataNPCHighLevelState.Combat )
		{
			mountData.entrySlotName = 'combat';
		}
		evt = new MountAIEvent;
		evt.name = 'Mount';
		evt.data = mountData;
		ScriptExecutionContext.GetOwner( context ).QueueEvent( evt );
		return true;
	}

}

abstract class AISubActionUseSensePreset_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionUseSensePreset_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			SenseComponent.RequestSecondaryPresetChange( ScriptExecutionContext.GetOwner( context ), record.SensePreset().GetID() );
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionUseSensePreset_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			SenseComponent.RequestSecondaryPresetChange( ScriptExecutionContext.GetOwner( context ), record.SensePreset().GetID() );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionUseSensePreset_Record >, const duration : Float, interrupted : Bool )
	{
		SenseComponent.ResetPreset( ScriptExecutionContext.GetOwner( context ) );
	}

}

abstract class AISubActionConditionalFailure_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionConditionalFailure_Record > ) {}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionConditionalFailure_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var i : Int32;
		var count : Int32;
		if( ( record.Delay() > 0.0 ) && ( duration < record.Delay() ) )
		{
			return AIbehaviorUpdateOutcome.IN_PROGRESS;
		}
		count = record.GetConditionCount();
		for( i = 0; i < count; i += 1 )
		{
			if( AICondition.CheckActionCondition( context, record.GetConditionItem( i ) ) )
			{
				break;
			}
		}
		if( ( count == 0 ) || ( i < count ) )
		{
			StartCooldowns( context, record );
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionConditionalFailure_Record >, const duration : Float, interrupted : Bool ) {}

	public static function StartCooldowns( context : ScriptExecutionContext, record : weak< AISubActionConditionalFailure_Record > )
	{
		var i : Int32;
		var count : Int32;
		var puppet : gamePuppet;
		count = record.GetCooldownsCount();
		if( count > 0 )
		{
			puppet = ScriptExecutionContext.GetOwner( context );
			for( i = 0; i < count; i += 1 )
			{
				AIActionHelper.StartCooldown( puppet, record.GetCooldownsItem( i ) );
			}
		}
	}

}

abstract class AISubActionCompleteCommand_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionCompleteCommand_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			CompleteCommand( context );
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionCompleteCommand_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			CompleteCommand( context );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionCompleteCommand_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			CompleteCommand( context );
		}
	}

	public static function CompleteCommand( context : ScriptExecutionContext ) {}
}

abstract class AISubActionLeaveCover_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionLeaveCover_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			LeaveCover( context, record );
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionLeaveCover_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			if( LeaveCover( context, record ) )
			{
				return AIbehaviorUpdateOutcome.SUCCESS;
			}
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionLeaveCover_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			LeaveCover( context, record );
		}
	}

	public static function LeaveCover( context : ScriptExecutionContext, record : weak< AISubActionLeaveCover_Record > ) : Bool
	{
		var puppet : weak< ScriptedPuppet >;
		puppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		if( !( puppet ) )
		{
			return false;
		}
		if( record.CheckExposure() != -1 )
		{
			if( record.CheckExposure() == 0 )
			{
				if( AICoverHelper.GetCoverNPCCurrentlyExposed( puppet ) )
				{
					return false;
				}
			}
			else if( record.CheckExposure() == 1 )
			{
				if( !( AICoverHelper.GetCoverNPCCurrentlyExposed( puppet ) ) )
				{
					return false;
				}
			}
			else if( !( AIActionHelper.IsCurrentlyCrouching( puppet ) ) )
			{
				return false;
			}
		}
		return AICoverHelper.LeaveCoverImmediately( puppet );
	}

}

abstract class AISubActionCustomEffectors_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionCustomEffectors_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			ApplyRemoveEffectors( context, record );
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionCustomEffectors_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			ApplyRemoveEffectors( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionCustomEffectors_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			ApplyRemoveEffectors( context, record );
		}
		else if( record.Remove() )
		{
			RemoveEffectors( context, record );
		}
	}

	public static function ApplyRemoveEffectors( context : ScriptExecutionContext, record : weak< AISubActionCustomEffectors_Record > )
	{
		if( record.Apply() )
		{
			ApplyEffectors( context, record );
		}
		else if( record.Remove() )
		{
			RemoveEffectors( context, record );
		}
	}

	public static function ApplyEffectors( const context : ScriptExecutionContext, record : weak< AISubActionCustomEffectors_Record > )
	{
		var obj : weak< GameObject >;
		var es : EffectorSystem;
		var effector : weak< Effector_Record >;
		var count, i : Int32;
		if( !( record.Target() ) || !( AIActionTarget.GetObject( context, record.Target(), obj ) ) )
		{
			return;
		}
		es = GameInstance.GetEffectorSystem( obj.GetGame() );
		if( !( es ) )
		{
			return;
		}
		count = record.GetEffectorsCount();
		for( i = 0; i < count; i += 1 )
		{
			effector = record.GetEffectorsItem( i );
			es.ApplyEffector( obj.GetEntityID(), ScriptExecutionContext.GetOwner( context ), effector.GetID() );
		}
	}

	public static function RemoveEffectors( const context : ScriptExecutionContext, record : weak< AISubActionCustomEffectors_Record > )
	{
		var obj : weak< GameObject >;
		var es : EffectorSystem;
		var effector : weak< Effector_Record >;
		var count, i : Int32;
		if( !( record.Target() ) || !( AIActionTarget.GetObject( context, record.Target(), obj ) ) )
		{
			return;
		}
		es = GameInstance.GetEffectorSystem( obj.GetGame() );
		if( !( es ) )
		{
			return;
		}
		count = record.GetEffectorsCount();
		for( i = 0; i < count; i += 1 )
		{
			effector = record.GetEffectorsItem( i );
			es.RemoveEffector( obj.GetEntityID(), effector.GetID() );
		}
	}

}

abstract class AISubActionActivateLightPreset_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionActivateLightPreset_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			ActivateLightPreset( context, record );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionActivateLightPreset_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			ActivateLightPreset( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionActivateLightPreset_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			ActivateLightPreset( context, record );
		}
	}

	protected static function ActivateLightPreset( context : ScriptExecutionContext, record : weak< AISubActionActivateLightPreset_Record > )
	{
		var applyPresetEvent : ApplyDiodeLightPresetEvent;
		var recordPreset : weak< LightPreset_Record >;
		var preset : DiodeLightPreset;
		recordPreset = record.LightPreset();
		preset.state = recordPreset.On();
		preset.colorMax = recordPreset.ColorMax();
		preset.colorMin = recordPreset.ColorMin();
		preset.overrideColorMin = recordPreset.OverrideColorMin();
		preset.strength = recordPreset.Strength();
		preset.curve = recordPreset.Curve();
		preset.time = recordPreset.Time();
		preset.loop = recordPreset.Loop();
		preset.duration = recordPreset.Duration();
		preset.force = recordPreset.Force();
		applyPresetEvent = new ApplyDiodeLightPresetEvent;
		applyPresetEvent.preset = preset;
		ScriptExecutionContext.GetOwner( context ).QueueEvent( applyPresetEvent );
	}

}

abstract class AISubActionFailIfFriendlyFire_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionFailIfFriendlyFire_Record > ) {}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionFailIfFriendlyFire_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var BBoard : IBlackboard;
		BBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		if( record.CheckOnlyFirstFrame() && !( BBoard.GetBool( GetAllBlackboardDefs().AIAction.operationHasBeenProcessed ) ) )
		{
			BBoard.SetBool( GetAllBlackboardDefs().AIAction.operationHasBeenProcessed, true );
			if( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().IsFriendlyFiring() )
			{
				return AIbehaviorUpdateOutcome.FAILURE;
			}
		}
		else if( !( record.CheckOnlyFirstFrame() ) && ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().IsFriendlyFiring() )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionFailIfFriendlyFire_Record >, const duration : Float, interrupted : Bool )
	{
		var BBoard : IBlackboard;
		BBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		BBoard.SetBool( GetAllBlackboardDefs().AIAction.operationHasBeenProcessed, false );
	}

}

abstract class AISubActionUpdateFriendlyFireParams_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionUpdateFriendlyFireParams_Record > )
	{
		var aiComponent : AIHumanComponent;
		var weaponItem : ItemObject;
		var equippedItemType : gamedataItemType;
		if( !( record.UpdateOnDeactivate() ) && AIHumanComponent.Get( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), aiComponent ) )
		{
			if( !( GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).IsSlotEmpty( ScriptExecutionContext.GetOwner( context ), T"AttachmentSlots.WeaponRight" ) ) )
			{
				weaponItem = GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetItemInSlot( ScriptExecutionContext.GetOwner( context ), T"AttachmentSlots.WeaponRight" );
				equippedItemType = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( weaponItem.GetItemID() ) ).ItemType().Type();
				SetFriendlyFireGeometry( equippedItemType, aiComponent.GetFriendlyFireSystem() );
			}
		}
	}

	public constexpr export static function Update( context : ScriptExecutionContext, record : weak< AISubActionUpdateFriendlyFireParams_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionUpdateFriendlyFireParams_Record >, const duration : Float, interrupted : Bool )
	{
		var aiComponent : AIHumanComponent;
		var weaponItem : ItemObject;
		var equippedItemType : gamedataItemType;
		if( record.UpdateOnDeactivate() && AIHumanComponent.Get( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), aiComponent ) )
		{
			if( !( GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).IsSlotEmpty( ScriptExecutionContext.GetOwner( context ), T"AttachmentSlots.WeaponRight" ) ) )
			{
				weaponItem = GameInstance.GetTransactionSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetItemInSlot( ScriptExecutionContext.GetOwner( context ), T"AttachmentSlots.WeaponRight" );
				equippedItemType = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( weaponItem.GetItemID() ) ).ItemType().Type();
				SetFriendlyFireGeometry( equippedItemType, aiComponent.GetFriendlyFireSystem() );
			}
		}
	}

	protected static function SetFriendlyFireGeometry( equippedItemType : gamedataItemType, ffs : IFriendlyFireSystem )
	{
		var ffp : FriendlyFireParams;
		ffp = new FriendlyFireParams;
		switch( equippedItemType )
		{
			case gamedataItemType.Wea_Melee:
				ffp.SetGeometry( 180.0, 2.0 );
			break;
			case gamedataItemType.Wea_Axe:
				ffp.SetGeometry( 180.0, 2.0 );
			break;
			case gamedataItemType.Wea_Chainsword:
				ffp.SetGeometry( 180.0, 2.0 );
			break;
			case gamedataItemType.Wea_Fists:
				ffp.SetGeometry( 180.0, 2.0 );
			break;
			case gamedataItemType.Wea_Katana:
				ffp.SetGeometry( 180.0, 2.0 );
			break;
			case gamedataItemType.Wea_Sword:
				ffp.SetGeometry( 180.0, 2.0 );
			break;
			case gamedataItemType.Wea_Knife:
				ffp.SetGeometry( 180.0, 2.0 );
			break;
			case gamedataItemType.Wea_LongBlade:
				ffp.SetGeometry( 180.0, 2.0 );
			break;
			case gamedataItemType.Wea_Machete:
				ffp.SetGeometry( 180.0, 2.0 );
			break;
			case gamedataItemType.Wea_OneHandedClub:
				ffp.SetGeometry( 180.0, 2.0 );
			break;
			case gamedataItemType.Wea_TwoHandedClub:
				ffp.SetGeometry( 180.0, 2.0 );
			break;
			case gamedataItemType.Wea_ShortBlade:
				ffp.SetGeometry( 180.0, 2.0 );
			break;
			case gamedataItemType.Wea_Hammer:
				ffp.SetGeometry( 180.0, 2.0 );
			break;
			case gamedataItemType.Cyb_MantisBlades:
				ffp.SetGeometry( 180.0, 2.0 );
			break;
			case gamedataItemType.Cyb_NanoWires:
				ffp.SetGeometry( 180.0, 2.0 );
			break;
			case gamedataItemType.Cyb_StrongArms:
				ffp.SetGeometry( 180.0, 2.0 );
			break;
			case gamedataItemType.Wea_Rifle:
				ffp.SetGeometry( 0.2, 50.0 );
			break;
			case gamedataItemType.Wea_AssaultRifle:
				ffp.SetGeometry( 0.2, 50.0 );
			break;
			case gamedataItemType.Wea_Handgun:
				ffp.SetGeometry( 0.2, 50.0 );
			break;
			case gamedataItemType.Wea_HeavyMachineGun:
				ffp.SetGeometry( 0.2, 50.0 );
			break;
			case gamedataItemType.Wea_LightMachineGun:
				ffp.SetGeometry( 0.2, 50.0 );
			break;
			case gamedataItemType.Wea_PrecisionRifle:
				ffp.SetGeometry( 0.2, 50.0 );
			break;
			case gamedataItemType.Wea_Revolver:
				ffp.SetGeometry( 0.2, 50.0 );
			break;
			case gamedataItemType.Wea_Shotgun:
				ffp.SetGeometry( 0.2, 50.0 );
			break;
			case gamedataItemType.Wea_ShotgunDual:
				ffp.SetGeometry( 0.2, 50.0 );
			break;
			case gamedataItemType.Wea_SniperRifle:
				ffp.SetGeometry( 0.2, 50.0 );
			break;
			case gamedataItemType.Wea_SubmachineGun:
				ffp.SetGeometry( 0.2, 50.0 );
			break;
			default:
				break;
		}
		ffs.StartChecking( ffp );
	}

}

abstract class AISubActionSendSignal_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionSendSignal_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			ScriptedPuppet.SendActionSignal( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), record.Name(), record.Duration() );
		}
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionSendSignal_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			ScriptedPuppet.SendActionSignal( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), record.Name(), record.Duration() );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionSendSignal_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			ScriptedPuppet.SendActionSignal( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), record.Name(), record.Duration() );
		}
		else if( record.Duration() < 0.0 )
		{
			ScriptedPuppet.ResetActionSignal( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), record.Name() );
		}
	}

}

abstract class AISubActionFastExitWorkspot_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionFastExitWorkspot_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			ExitWorkspot( context, record );
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionFastExitWorkspot_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			ExitWorkspot( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionFastExitWorkspot_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			ExitWorkspot( context, record );
		}
	}

	protected static function ExitWorkspot( context : ScriptExecutionContext, record : weak< AISubActionFastExitWorkspot_Record > )
	{
		var workspotSystem : WorkspotGameSystem;
		var source, destinationObj : weak< GameObject >;
		var sourcePosition, destinationPosition, vecToTarget : Vector4;
		if( !( AIActionTarget.Get( context, record.Target(), false, source, sourcePosition ) ) )
		{
			return;
		}
		if( !( AIActionTarget.Get( context, record.DestinationObj(), false, destinationObj, destinationPosition ) ) )
		{
			return;
		}
		workspotSystem = GameInstance.GetWorkspotSystem( ScriptExecutionContext.GetOwner( context ).GetGame() );
		if( !( workspotSystem ) )
		{
			return;
		}
		vecToTarget = destinationPosition - sourcePosition;
		workspotSystem.SendFastExitSignal( source, Vector4.Vector4To3( vecToTarget ), record.StayInWorkspotIfFailed(), record.PlaySlowExitIfFailed() );
	}

}

abstract class AISubActionMeleeAttackAttemptEvent_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionMeleeAttackAttemptEvent_Record > ) {}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionMeleeAttackAttemptEvent_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var attackAttemptEvent : AIAttackAttemptEvent;
		var target : weak< GameObject >;
		if( AIActionTarget.GetObject( context, record.Target(), target ) )
		{
			attackAttemptEvent = new AIAttackAttemptEvent;
			attackAttemptEvent.instigator = ScriptExecutionContext.GetOwner( context );
			attackAttemptEvent.target = target;
			attackAttemptEvent.isWindUp = record.IsWindUp();
			target.QueueEvent( attackAttemptEvent );
			ScriptExecutionContext.GetOwner( context ).QueueEvent( attackAttemptEvent );
		}
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionMeleeAttackAttemptEvent_Record >, const duration : Float, interrupted : Bool ) {}
}

abstract class AISubActionSetWorldPosition_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionSetWorldPosition_Record > )
	{
		var finalWorldPosition : Vector4;
		if( !( record.CustomPositionTarget() ) || !( record.CustomPositionTarget().IsPosition() ) )
		{
			return;
		}
		finalWorldPosition = CalculateWorldPosition( context, record );
		AIActionTarget.Set( context, record.CustomPositionTarget(), NULL, finalWorldPosition );
	}

	public constexpr static function Update( context : ScriptExecutionContext, record : weak< AISubActionSetWorldPosition_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

	protected static function CalculateWorldPosition( context : ScriptExecutionContext, record : weak< AISubActionSetWorldPosition_Record > ) : Vector4
	{
		var i : Int32;
		var calculatedPosition : Vector4;
		var navmeshPositionValid : Bool;
		if( record.ReferenceTarget() == NULL )
		{
			calculatedPosition = Vector4.Vector3To4( record.MinOffsetFromTarget() );
			return calculatedPosition;
		}
		if( !( record.RandomizePoint() ) )
		{
			calculatedPosition = GetWorldPositionWithOffset( context, record.ReferenceTarget(), record.MinOffsetFromTarget(), record.UseLocalSpace() );
			if( record.CheckForNavmesh() && !( GetNavmeshPosition( context, calculatedPosition ) ) )
			{
				Vector4.Zero( calculatedPosition );
			}
		}
		else
		{
			for( i = 0; i < 10; i += 1 )
			{
				calculatedPosition = GetWorldPositionWithOffset( context, record.ReferenceTarget(), GetRandomOffset( record.MinOffsetFromTarget(), record.MaxOffsetFromTarget() ), record.UseLocalSpace() );
				if( !( record.CheckForNavmesh() ) )
				{
					break;
				}
				else
				{
					navmeshPositionValid = GetNavmeshPosition( context, calculatedPosition );
					if( navmeshPositionValid )
					{
						break;
					}
					else if( ( i == 9 ) && !( navmeshPositionValid ) )
					{
						Vector4.Zero( calculatedPosition );
					}
				}
			}
		}
		return calculatedPosition;
	}

	protected static function GetNavmeshPosition( context : ScriptExecutionContext, out checkPosition : Vector4 ) : Bool
	{
		var closestNavmeshPoint : Vector4;
		if( GameInstance.GetAINavigationSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).IsPointOnNavmesh( ScriptExecutionContext.GetOwner( context ), checkPosition, Vector4( 0.2, 0.2, 1.20000005, 1.0 ), closestNavmeshPoint ) )
		{
			checkPosition = closestNavmeshPoint;
			return true;
		}
		return false;
	}

	protected static function GetWorldPositionWithOffset( context : ScriptExecutionContext, referenceTarget : AIActionTarget_Record, offset : Vector3, useLocalSpace : Bool ) : Vector4
	{
		var referenceTargetObject : weak< GameObject >;
		var referenceTargetPosition : Vector4;
		var positionWithOffset : Vector4;
		AIActionTarget.Get( context, referenceTarget, false, referenceTargetObject, referenceTargetPosition );
		if( referenceTarget.IsPosition() )
		{
			positionWithOffset = referenceTargetPosition + Vector4.Vector3To4( offset );
		}
		else
		{
			if( useLocalSpace )
			{
				positionWithOffset = referenceTargetObject.GetWorldPosition() + Vector4.RotByAngleXY( Vector4.Vector3To4( offset ), -1.0 * Vector4.Heading( referenceTargetObject.GetWorldForward() ) );
			}
			else
			{
				positionWithOffset = referenceTargetObject.GetWorldPosition() + Vector4.Vector3To4( offset );
			}
		}
		return positionWithOffset;
	}

	protected static function GetRandomOffset( minOffset : Vector3, maxOffset : Vector3 ) : Vector3
	{
		var randomOffset : Vector3;
		randomOffset.X = RandRangeF( minOffset.X, maxOffset.X );
		randomOffset.Y = RandRangeF( minOffset.Y, maxOffset.Y );
		randomOffset.Z = RandRangeF( minOffset.Z, maxOffset.Z );
		return randomOffset;
	}

}

abstract class AISubActionCover_Record_Implementation extends IScriptable
{

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionCover_Record > )
	{
		if( record.SetDesiredCover() != -1 )
		{
			AICoverHelper.GetCoverBlackboard( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ) ).SetFloat( GetAllBlackboardDefs().AICover.startCoverEvaluationTimeStamp, EngineTime.ToFloat( ScriptExecutionContext.GetAITime( context ) ) );
		}
		if( record.SetCurrentCover() )
		{
			SetCurrentCover( context );
		}
		if( record.ExposedInCover() == 0 )
		{
			AICoverHelper.SetCoverNPCCurrentlyExposed( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), false );
		}
		else if( record.ExposedInCover() == 1 )
		{
			AICoverHelper.SetCoverNPCCurrentlyExposed( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), true );
		}
		SetCoverData( context, record );
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionCover_Record >, duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.SetDesiredCover() != -1 )
		{
			SetDesiredCover( context, record );
		}
		if( record.SetCurrentCover() )
		{
			SetCurrentCover( context );
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionCover_Record >, const duration : Float, interrupted : Bool )
	{
		var puppet : weak< ScriptedPuppet >;
		var pullSquadSyncRequest : DelaySetCoverNPCCurrentlyExposed;
		puppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		if( !( puppet ) )
		{
			return;
		}
		if( ( record.ExposedInCover() != -1 ) && AICoverHelper.GetCoverNPCCurrentlyExposed( puppet ) )
		{
			AICoverHelper.SetCoverNPCCurrentlyExposed( puppet, false );
			if( interrupted )
			{
				pullSquadSyncRequest = new DelaySetCoverNPCCurrentlyExposed;
				GameInstance.GetDelaySystem( puppet.GetGame() ).DelayEvent( puppet, pullSquadSyncRequest, 0.40000001 );
			}
			else
			{
				AICoverHelper.SetCoverNPCCurrentlyExposed( puppet, false );
			}
		}
	}

	public export static function GetAnimVariation( context : ScriptExecutionContext, record : weak< AISubActionCover_Record > ) : Int32
	{
		var coverExposureMethod : AICoverExposureMethod;
		var puppet : weak< ScriptedPuppet >;
		var animVariation : Int32;
		animVariation = -1;
		puppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		if( !( puppet ) )
		{
			return -1;
		}
		AICoverHelper.GetCoverExposureMethod( puppet, coverExposureMethod );
		if( coverExposureMethod == AICoverExposureMethod.Count )
		{
			if( record.UseLastAvailableExposureMethodsIfNoneAvailable() )
			{
				AICoverHelper.GetFallbackCoverExposureMethod( puppet, coverExposureMethod );
				if( coverExposureMethod != AICoverExposureMethod.Count )
				{
					return ( ( Int32 )( coverExposureMethod ) );
				}
			}
			return -1;
		}
		animVariation = ( ( Int32 )( coverExposureMethod ) );
		return animVariation;
	}

	public constexpr static function GetInvalidCoverID() : Uint64
	{
		return 999999999;
	}

	public static function SetDesiredCover( context : ScriptExecutionContext, record : weak< AISubActionCover_Record > )
	{
		var msc : weak< MultiSelectCovers >;
		var trackedLocation : TrackedLocation;
		var currentRing : gamedataAIRingType;
		var conditionCount : Int32;
		var exposureMethods : array< AICoverExposureMethod >;
		var squadInterface : PuppetSquadInterface;
		var objectSelectionComponent : ObjectSelectionComponent;
		var debugCoverPresetNum : Int32;
		var selectedCoversSize : Int32;
		var targetVisible : Bool;
		var currentCoverValid : Bool;
		var target : weak< GameObject >;
		var puppet : weak< ScriptedPuppet >;
		var checkedCoverID : Uint64;
		var setCoverID : Uint64;
		var cm : CoverManager;
		var i : Int32;
		var tmpID : Uint64;
		var ringName : CName;
		debugCoverPresetNum = -1;
		puppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		if( !( puppet ) )
		{
			return;
		}
		objectSelectionComponent = puppet.GetObjectSelectionComponent();
		if( objectSelectionComponent && objectSelectionComponent.IsCoversProcessingPaused() )
		{
			return;
		}
		cm = GameInstance.GetCoverManager( puppet.GetGame() );
		setCoverID = GetInvalidCoverID();
		checkedCoverID = ScriptExecutionContext.GetArgumentUint64( context, 'CommandCoverID' );
		if( checkedCoverID > ( ( Uint64 )( 0 ) ) )
		{
			conditionCount = record.GetCommandCoverConditionsCount();
			if( conditionCount > 0 )
			{
				for( i = 0; i < conditionCount; i += 1 )
				{
					if( AICondition.CheckActionCondition( context, record.GetCommandCoverConditionsItem( i ) ) )
					{
						AIActionHelper.StartCooldown( puppet, record.InsideCoverReselectionCooldown() );
						tmpID = ScriptExecutionContext.GetArgumentUint64( context, 'DesiredCoverID' );
						if( tmpID != checkedCoverID )
						{
							ScriptExecutionContext.SetArgumentUint64( context, 'DesiredCoverID', checkedCoverID );
						}
						if( !( IsFinal() ) && objectSelectionComponent )
						{
							objectSelectionComponent.SetCurrentCoverDebugPresetNumber( -1 );
							AICoverHelper.GetCoverBlackboard( puppet ).SetInt( GetAllBlackboardDefs().AICover.lastDebugCoverPreset, -1 );
						}
						AICoverHelper.GetCoverBlackboard( puppet ).SetBool( GetAllBlackboardDefs().AICover.firstCoverEvaluationDone, true );
						return;
					}
				}
			}
			else
			{
				AIActionHelper.StartCooldown( puppet, record.InsideCoverReselectionCooldown() );
				tmpID = ScriptExecutionContext.GetArgumentUint64( context, 'DesiredCoverID' );
				if( tmpID != checkedCoverID )
				{
					ScriptExecutionContext.SetArgumentUint64( context, 'DesiredCoverID', checkedCoverID );
				}
				if( !( IsFinal() ) && objectSelectionComponent )
				{
					objectSelectionComponent.SetCurrentCoverDebugPresetNumber( -1 );
					AICoverHelper.GetCoverBlackboard( puppet ).SetInt( GetAllBlackboardDefs().AICover.lastDebugCoverPreset, -1 );
				}
				AICoverHelper.GetCoverBlackboard( puppet ).SetBool( GetAllBlackboardDefs().AICover.firstCoverEvaluationDone, true );
				return;
			}
		}
		if( cm )
		{
			checkedCoverID = cm.GetCurrentCover( puppet );
		}
		currentRing = AISquadHelper.GetCurrentSquadRing( puppet );
		currentCoverValid = objectSelectionComponent.IsCoverPositiveScored( checkedCoverID, currentRing );
		if( checkedCoverID > ( ( Uint64 )( 0 ) ) )
		{
			if( cm.IsShootingSpot( checkedCoverID ) && !( GameObject.IsCooldownActive( puppet, 'ShootingSpotSelection' ) ) )
			{
				AIActionHelper.StartCooldown( puppet, 'ShootingSpotSelection', 600.0 );
			}
			if( currentCoverValid && GameObject.IsCooldownActive( puppet, record.InsideCoverReselectionCooldown().Name() ) )
			{
				return;
			}
		}
		msc = ( ( weak< weak< MultiSelectCovers > > )( ScriptExecutionContext.GetArgumentScriptable( context, 'MultiCoverID' ) ) );
		if( !( msc ) )
		{
			return;
		}
		AIActionTarget.GetObject( context, record.Target(), target );
		selectedCoversSize = msc.selectedCovers.Size();
		if( ( ( checkedCoverID > ( ( Uint64 )( 0 ) ) ) && target ) && AISquadHelper.GetSquadBaseInterface( puppet, squadInterface ) )
		{
			exposureMethods = AICoverHelper.GetAvailableExposureSpots( puppet, checkedCoverID, target, exposureMethods, record.ClearLOSDistanceTolerance() );
			if( ( ( record.SetDesiredCover() == 1 ) || ( record.SetDesiredCover() == 3 ) ) || ( record.SetDesiredCover() == 5 ) )
			{
				if( exposureMethods.Size() == 0 )
				{
					for( i = 0; i < selectedCoversSize; i += 1 )
					{
						if( !( msc.coversUseLOS[ i ] ) )
						{
							continue;
						}
						if( cm.IsShootingSpot( msc.selectedCovers[ i ] ) && !( EvaluateShootingSpot( puppet, target, cm, msc.selectedCovers[ i ] ) ) )
						{
							continue;
						}
						if( !( squadInterface.CheckTicketConditions( AISquadHelper.SquadRingTypeToTicketName( msc.coverRingTypes[ i ] ), puppet ) ) )
						{
							continue;
						}
						ringName = StringToName( AISquadHelper.SquadRingTypeToTicketString( msc.coverRingTypes[ i ] ) + ( ( msc.coverRingTypes[ i ] == gamedataAIRingType.Default ) ? ( "" ) : ( "2ndFilter" ) ) );
						if( !( squadInterface.CheckTicketConditions( ringName, puppet ) ) )
						{
							continue;
						}
						if( SelectCover( context, record.InsideCoverReselectionCooldown(), msc.selectedCovers[ i ], msc.coverRingTypes[ i ], currentRing, false ) )
						{
							setCoverID = msc.selectedCovers[ i ];
							debugCoverPresetNum = i;
							break;
						}
					}
				}
			}
		}
		else if( checkedCoverID == ( ( Uint64 )( 0 ) ) )
		{
			if( target )
			{
				if( TargetTrackingExtension.GetTrackedLocation( context, target, trackedLocation ) )
				{
					targetVisible = trackedLocation.accuracy > 0.89999998;
					if( !( targetVisible ) && ScriptedPuppet.IsPlayerCompanion( puppet ) )
					{
						targetVisible = trackedLocation.sharedAccuracy > 0.89999998;
					}
				}
			}
			if( ( ( record.SetDesiredCover() == 1 ) || ( record.SetDesiredCover() == 3 ) ) || ( record.SetDesiredCover() == 5 ) )
			{
				for( i = 0; i < selectedCoversSize; i += 1 )
				{
					if( record.SetDesiredCover() == 5 )
					{
						if( !( msc.coversUseLOS[ i ] ) )
						{
							continue;
						}
					}
					else if( ( ( ( ( record.SetDesiredCover() == 3 ) && ( selectedCoversSize > 1 ) ) && target ) && targetVisible ) && !( msc.coversUseLOS[ i ] ) )
					{
						continue;
					}
					if( cm.IsShootingSpot( msc.selectedCovers[ i ] ) && !( EvaluateShootingSpot( puppet, target, cm, msc.selectedCovers[ i ] ) ) )
					{
						continue;
					}
					if( SelectCover( context, record.InsideCoverReselectionCooldown(), msc.selectedCovers[ i ], msc.coverRingTypes[ i ], currentRing, selectedCoversSize > 1 ) )
					{
						setCoverID = msc.selectedCovers[ i ];
						debugCoverPresetNum = i;
						break;
					}
				}
			}
			else
			{
				for( i = selectedCoversSize - 1; i >= 0; i -= 1 )
				{
					if( record.SetDesiredCover() == 4 )
					{
						if( msc.coversUseLOS[ i ] )
						{
							continue;
						}
					}
					if( ( ( ( ( record.SetDesiredCover() == 2 ) && ( selectedCoversSize > 1 ) ) && target ) && !( targetVisible ) ) && msc.coversUseLOS[ i ] )
					{
						continue;
					}
					if( cm.IsShootingSpot( msc.selectedCovers[ i ] ) && !( EvaluateShootingSpot( puppet, target, cm, msc.selectedCovers[ i ] ) ) )
					{
						continue;
					}
					if( SelectCover( context, record.InsideCoverReselectionCooldown(), msc.selectedCovers[ i ], msc.coverRingTypes[ i ], currentRing, selectedCoversSize > 1 ) )
					{
						setCoverID = msc.selectedCovers[ i ];
						debugCoverPresetNum = i;
						break;
					}
				}
			}
		}
		if( setCoverID == GetInvalidCoverID() )
		{
			if( !( AICoverHelper.GetCoverBlackboard( puppet ).GetBool( GetAllBlackboardDefs().AICover.firstCoverEvaluationDone ) ) )
			{
				if( EngineTime.ToFloat( ScriptExecutionContext.GetAITime( context ) ) > ( AICoverHelper.GetCoverBlackboard( puppet ).GetFloat( GetAllBlackboardDefs().AICover.startCoverEvaluationTimeStamp ) + 1.0 ) )
				{
					AICoverHelper.GetCoverBlackboard( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ) ).SetBool( GetAllBlackboardDefs().AICover.firstCoverEvaluationDone, true );
				}
			}
			if( currentCoverValid )
			{
				tmpID = ScriptExecutionContext.GetArgumentUint64( context, 'DesiredCoverID' );
				if( tmpID != checkedCoverID )
				{
					ScriptExecutionContext.SetArgumentUint64( context, 'DesiredCoverID', checkedCoverID );
				}
				AIActionHelper.StartCooldown( ScriptExecutionContext.GetOwner( context ), record.InsideCoverReselectionCooldown() );
				if( !( IsFinal() ) && ( objectSelectionComponent.GetCurrentCoverDebugPresetNumber() < 0 ) )
				{
					debugCoverPresetNum = AICoverHelper.GetCoverBlackboard( puppet ).GetInt( GetAllBlackboardDefs().AICover.lastDebugCoverPreset );
					objectSelectionComponent.SetCurrentCoverDebugPresetNumber( debugCoverPresetNum );
				}
			}
			else
			{
				tmpID = ScriptExecutionContext.GetArgumentUint64( context, 'DesiredCoverID' );
				if( tmpID != ( ( Uint64 )( 0 ) ) )
				{
					ScriptExecutionContext.SetArgumentUint64( context, 'DesiredCoverID', ( ( Uint64 )( 0 ) ) );
				}
				if( !( IsFinal() ) && objectSelectionComponent )
				{
					objectSelectionComponent.SetCurrentCoverDebugPresetNumber( debugCoverPresetNum );
					AICoverHelper.GetCoverBlackboard( puppet ).SetInt( GetAllBlackboardDefs().AICover.lastDebugCoverPreset, debugCoverPresetNum );
				}
			}
		}
		else if( !( IsFinal() ) && objectSelectionComponent )
		{
			objectSelectionComponent.SetCurrentCoverDebugPresetNumber( debugCoverPresetNum );
			AICoverHelper.GetCoverBlackboard( puppet ).SetInt( GetAllBlackboardDefs().AICover.lastDebugCoverPreset, debugCoverPresetNum );
		}
	}

	public static function SelectCover( context : ScriptExecutionContext, cooldown : AIActionCooldown_Record, consideredCoverID : Uint64, consideredRing, currentRing : gamedataAIRingType, compareRings : Bool ) : Bool
	{
		var tmpID : Uint64;
		if( compareRings )
		{
			if( currentRing == gamedataAIRingType.Invalid )
			{
				if( consideredRing != gamedataAIRingType.Undefined && consideredRing != gamedataAIRingType.Default )
				{
					return false;
				}
			}
			else if( currentRing != consideredRing )
			{
				return false;
			}
		}
		AICoverHelper.GetCoverBlackboard( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ) ).SetBool( GetAllBlackboardDefs().AICover.firstCoverEvaluationDone, true );
		if( consideredCoverID > ( ( Uint64 )( 0 ) ) )
		{
			tmpID = ScriptExecutionContext.GetArgumentUint64( context, 'DesiredCoverID' );
			if( tmpID != consideredCoverID )
			{
				ScriptExecutionContext.SetArgumentUint64( context, 'DesiredCoverID', consideredCoverID );
			}
			AIActionHelper.StartCooldown( ScriptExecutionContext.GetOwner( context ), cooldown );
			AICoverHelper.GetCoverBlackboard( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ) ).SetVariant( GetAllBlackboardDefs().AICover.lastCoverRing, consideredRing );
			return true;
		}
		return false;
	}

	public static function EvaluateShootingSpot( puppet : weak< ScriptedPuppet >, target : weak< GameObject >, cm : weak< CoverManager >, consideredCoverID : Uint64 ) : Bool
	{
		var shootingSpotPosition : Vector4;
		var targetPosition : Vector4;
		shootingSpotPosition = cm.GetCoverPosition( consideredCoverID );
		targetPosition = target.GetWorldPosition();
		if( ( ( shootingSpotPosition.Z - targetPosition.Z ) < 1.5 ) && GameObject.IsCooldownActive( puppet, 'ShootingSpotSelection' ) )
		{
			return false;
		}
		return true;
	}

	public static function SetCurrentCover( context : ScriptExecutionContext )
	{
		var coverID : Uint64;
		var tmpID : Uint64;
		coverID = ScriptExecutionContext.GetArgumentUint64( context, 'DesiredCoverID' );
		tmpID = ScriptExecutionContext.GetArgumentUint64( context, 'CoverID' );
		if( tmpID != coverID )
		{
			ScriptExecutionContext.SetArgumentUint64( context, 'CoverID', coverID );
			AICoverHelper.SetCoverLastAvailableExposureMethod( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ) );
		}
	}

	public static function SetCoverData( context : ScriptExecutionContext, record : weak< AISubActionCover_Record > )
	{
		var coverID : Uint64;
		var puppet : weak< ScriptedPuppet >;
		var target : weak< GameObject >;
		puppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		if( !( puppet ) )
		{
			return;
		}
		if( record.SetInitialCoverData() )
		{
			coverID = GameInstance.GetCoverManager( puppet.GetGame() ).GetCurrentCover( puppet );
			if( coverID == ( ( Uint64 )( 0 ) ) )
			{
				coverID = ScriptExecutionContext.GetArgumentUint64( context, 'CoverID' );
				if( coverID == ( ( Uint64 )( 0 ) ) )
				{
					return;
				}
			}
			SetInitialCoverData( puppet, coverID );
		}
		if( record.SetCoverExposureAnim() )
		{
			coverID = GameInstance.GetCoverManager( puppet.GetGame() ).GetCurrentCover( puppet );
			if( coverID == ( ( Uint64 )( 0 ) ) )
			{
				return;
			}
			AIActionTarget.GetObject( context, record.Target(), target );
			SetCoverExposureAnim( context, puppet, coverID, record, target, record.ClearLOSDistanceTolerance() );
		}
	}

	public static function SetInitialCoverData( puppet : weak< ScriptedPuppet >, const coverID : Uint64 )
	{
		var coverStance : gameCoverHeight;
		var coverFeature : AnimFeature_NPCCoverStanceState;
		var shootingSpot : Bool;
		coverStance = AICoverHelper.GetCoverType( puppet, coverID, shootingSpot );
		AICoverHelper.SetCurrentCoverStance( puppet, coverStance );
		coverFeature = new AnimFeature_NPCCoverStanceState;
		if( shootingSpot )
		{
			coverFeature.state = 3;
		}
		else
		{
			coverFeature.state = ( ( Int32 )( coverStance ) );
		}
		AnimationControllerComponent.ApplyFeatureToReplicate( puppet, 'CoverStance', coverFeature );
		AnimationControllerComponent.ApplyFeatureToReplicateOnHeldItems( puppet, 'CoverStance', coverFeature );
	}

	public static function SetCoverExposureAnim( context : ScriptExecutionContext, puppet : weak< ScriptedPuppet >, const coverID : Uint64, record : weak< AISubActionCover_Record >, target : weak< GameObject >, lineOfSightTolerance : Float )
	{
		var exposureMethods : array< AICoverExposureMethod >;
		var coverExposureMethod : AICoverExposureMethod;
		var coverStance : gameCoverHeight;
		var trackedLocation : TrackedLocation;
		TargetTrackingExtension.GetTrackedLocation( context, target, trackedLocation );
		coverExposureMethod = CalculateCoverExposureMethod( puppet, coverID, record, target, lineOfSightTolerance, trackedLocation, exposureMethods );
		coverStance = AICoverHelper.GetCoverStanceFromExposureSpot( puppet, coverExposureMethod );
		AICoverHelper.SetCoverExposureMethod( puppet, coverExposureMethod );
		AICoverHelper.SetDesiredCoverStance( puppet, coverStance );
		if( exposureMethods.Size() > 0 )
		{
			AICoverHelper.SetCoverLastAvailableExposureMethod( puppet, exposureMethods );
		}
		AICoverHelper.GetRandomCoverLastAvailableExposureMethod( puppet, coverExposureMethod );
		AICoverHelper.SetFallbackCoverExposureMethod( puppet, coverExposureMethod );
	}

	public static function CalculateCoverExposureMethod( puppet : weak< ScriptedPuppet >, const coverID : Uint64, record : weak< AISubActionCover_Record >, const target : weak< GameObject >, lineOfSightTolerance : Float, const trackedLocation : ref< TrackedLocation >, exposureMethods : ref< array< AICoverExposureMethod > > ) : AICoverExposureMethod
	{
		var coverExposureMethod : AICoverExposureMethod;
		coverExposureMethod = AICoverHelper.CalculateCoverExposureMethod( puppet, target, coverID, record, lineOfSightTolerance, trackedLocation, exposureMethods );
		return coverExposureMethod;
	}

}

abstract class AISubActionHitData_Record_Implementation extends IScriptable
{

	public export static function GetAnimVariation( context : ScriptExecutionContext, record : weak< AISubActionHitData_Record > ) : Int32
	{
		var hitData : AnimFeature_HitReactionsData;
		var animVariation : Int32;
		var object : weak< GameObject >;
		var newDirection : Int32;
		var backDirection : Int32;
		animVariation = -1;
		hitData = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetHitReactionComponent().GetLastHitReactionData();
		if( !( hitData ) )
		{
			return -1;
		}
		if( record.OverrideHitDirection() )
		{
			if( AIActionTarget.GetObject( context, record.DirectionObj(), object ) )
			{
				newDirection = GameObject.GetTargetAngleInInt( object, ScriptExecutionContext.GetOwner( context ), backDirection );
			}
			switch( hitData.hitBodyPart )
			{
				case 1:
					switch( hitData.hitDirection )
					{
						case 1:
							if( newDirection == 1 )
							{
								animVariation = 24;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 1;
								}
								else
								{
									animVariation = 0;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 26;
							}
							else
							{
								animVariation = 3;
							}
						break;
						case 2:
							if( newDirection == 1 )
							{
								animVariation = 24;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 1;
								}
								else
								{
									animVariation = 0;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 26;
							}
							else
							{
								animVariation = 3;
							}
						break;
						case 3:
							if( newDirection == 1 )
							{
								animVariation = 24;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 1;
								}
								else
								{
									animVariation = 0;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 26;
							}
							else
							{
								animVariation = 3;
							}
						break;
						case 4:
							if( newDirection == 1 )
							{
								animVariation = 24;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 1;
								}
								else
								{
									animVariation = 0;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 26;
							}
							else
							{
								animVariation = 3;
							}
						break;
						default:
							return -1;
					}
				break;
				case 2:
					switch( hitData.hitDirection )
					{
						case 1:
							if( newDirection == 1 )
							{
								animVariation = 28;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 17;
								}
								else
								{
									animVariation = 16;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 9;
							}
							else
							{
								animVariation = 8;
							}
						break;
						case 2:
							if( newDirection == 1 )
							{
								animVariation = 24;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 1;
								}
								else
								{
									animVariation = 0;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 26;
							}
							else
							{
								animVariation = 3;
							}
						break;
						case 3:
							if( newDirection == 1 )
							{
								animVariation = 28;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 17;
								}
								else
								{
									animVariation = 16;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 9;
							}
							else
							{
								animVariation = 8;
							}
						break;
						case 4:
							if( newDirection == 1 )
							{
								animVariation = 24;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 1;
								}
								else
								{
									animVariation = 0;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 26;
							}
							else
							{
								animVariation = 3;
							}
						break;
						default:
							return -1;
					}
				break;
				case 3:
					switch( hitData.hitDirection )
					{
						case 1:
							if( newDirection == 1 )
							{
								animVariation = 28;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 17;
								}
								else
								{
									animVariation = 16;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 9;
							}
							else
							{
								animVariation = 8;
							}
						break;
						case 2:
							if( newDirection == 1 )
							{
								animVariation = 28;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 17;
								}
								else
								{
									animVariation = 16;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 9;
							}
							else
							{
								animVariation = 8;
							}
						break;
						case 3:
							if( newDirection == 1 )
							{
								animVariation = 28;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 17;
								}
								else
								{
									animVariation = 16;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 9;
							}
							else
							{
								animVariation = 8;
							}
						break;
						case 4:
							if( newDirection == 1 )
							{
								animVariation = 28;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 17;
								}
								else
								{
									animVariation = 16;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 9;
							}
							else
							{
								animVariation = 8;
							}
						break;
						default:
							return -1;
					}
				break;
				case 4:
					switch( hitData.hitDirection )
					{
						case 1:
							if( newDirection == 1 )
							{
								animVariation = 28;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 17;
								}
								else
								{
									animVariation = 16;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 9;
							}
							else
							{
								animVariation = 8;
							}
						break;
						case 2:
							if( newDirection == 1 )
							{
								animVariation = 24;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 1;
								}
								else
								{
									animVariation = 0;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 26;
							}
							else
							{
								animVariation = 3;
							}
						break;
						case 3:
							if( newDirection == 1 )
							{
								animVariation = 28;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 17;
								}
								else
								{
									animVariation = 16;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 9;
							}
							else
							{
								animVariation = 8;
							}
						break;
						case 4:
							if( newDirection == 1 )
							{
								animVariation = 28;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 17;
								}
								else
								{
									animVariation = 16;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 9;
							}
							else
							{
								animVariation = 8;
							}
						break;
						default:
							return -1;
					}
				break;
				case 5:
					switch( hitData.hitDirection )
					{
						case 1:
							if( newDirection == 1 )
							{
								animVariation = 28;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 17;
								}
								else
								{
									animVariation = 16;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 9;
							}
							else
							{
								animVariation = 8;
							}
						break;
						case 2:
							if( newDirection == 1 )
							{
								animVariation = 28;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 17;
								}
								else
								{
									animVariation = 16;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 9;
							}
							else
							{
								animVariation = 8;
							}
						break;
						case 3:
							if( newDirection == 1 )
							{
								animVariation = 28;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 17;
								}
								else
								{
									animVariation = 16;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 9;
							}
							else
							{
								animVariation = 8;
							}
						break;
						case 4:
							if( newDirection == 1 )
							{
								animVariation = 24;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 1;
								}
								else
								{
									animVariation = 0;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 26;
							}
							else
							{
								animVariation = 3;
							}
						break;
						default:
							return -1;
					}
				break;
				case 6:
					switch( hitData.hitDirection )
					{
						case 1:
							if( newDirection == 1 )
							{
								animVariation = 28;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 17;
								}
								else
								{
									animVariation = 16;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 9;
							}
							else
							{
								animVariation = 8;
							}
						break;
						case 2:
							if( newDirection == 1 )
							{
								animVariation = 28;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 17;
								}
								else
								{
									animVariation = 16;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 9;
							}
							else
							{
								animVariation = 8;
							}
						break;
						case 3:
							if( newDirection == 1 )
							{
								animVariation = 28;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 17;
								}
								else
								{
									animVariation = 16;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 9;
							}
							else
							{
								animVariation = 8;
							}
						break;
						case 4:
							if( newDirection == 1 )
							{
								animVariation = 24;
							}
							else if( newDirection == 2 )
							{
								if( backDirection == 1 )
								{
									animVariation = 1;
								}
								else
								{
									animVariation = 0;
								}
							}
							else if( newDirection == 3 )
							{
								animVariation = 26;
							}
							else
							{
								animVariation = 3;
							}
						break;
						default:
							return -1;
					}
				break;
				default:
					return -1;
			}
		}
		else if( hitData.stance == 0 )
		{
			switch( hitData.hitBodyPart )
			{
				case 1:
					switch( hitData.hitDirection )
					{
						case 1:
							animVariation = 0;
						break;
						case 2:
							animVariation = 1;
						break;
						case 3:
							animVariation = 2;
						break;
						case 4:
							animVariation = 3;
						break;
						default:
							return -1;
					}
				break;
				case 2:
					switch( hitData.hitDirection )
					{
						case 1:
							animVariation = 4;
						break;
						case 2:
							animVariation = 5;
						break;
						case 3:
							animVariation = 6;
						break;
						case 4:
							animVariation = 7;
						break;
						default:
							return -1;
					}
				break;
				case 3:
					switch( hitData.hitDirection )
					{
						case 1:
							animVariation = 8;
						break;
						case 2:
							animVariation = 9;
						break;
						case 3:
							animVariation = 10;
						break;
						case 4:
							animVariation = 11;
						break;
						default:
							return -1;
					}
				break;
				case 4:
					switch( hitData.hitDirection )
					{
						case 1:
							animVariation = 12;
						break;
						case 2:
							animVariation = 13;
						break;
						case 3:
							animVariation = 14;
						break;
						case 4:
							animVariation = 15;
						break;
						default:
							return -1;
					}
				break;
				case 5:
					switch( hitData.hitDirection )
					{
						case 1:
							animVariation = 16;
						break;
						case 2:
							animVariation = 17;
						break;
						case 3:
							animVariation = 18;
						break;
						case 4:
							animVariation = 19;
						break;
						default:
							return -1;
					}
				break;
				case 6:
					switch( hitData.hitDirection )
					{
						case 1:
							animVariation = 20;
						break;
						case 2:
							animVariation = 21;
						break;
						case 3:
							animVariation = 22;
						break;
						case 4:
							animVariation = 23;
						break;
						default:
							return -1;
					}
				break;
				default:
					return -1;
			}
		}
		else
		{
			switch( hitData.hitBodyPart )
			{
				case 1:
					switch( hitData.hitDirection )
					{
						case 1:
							animVariation = 24;
						break;
						case 2:
							animVariation = 25;
						break;
						case 3:
							animVariation = 26;
						break;
						case 4:
							animVariation = 27;
						break;
						default:
							return -1;
					}
				break;
				case 2:
					switch( hitData.hitDirection )
					{
						case 1:
							animVariation = 28;
						break;
						case 2:
							animVariation = 29;
						break;
						case 3:
							animVariation = 30;
						break;
						case 4:
							animVariation = 31;
						break;
						default:
							return -1;
					}
				break;
				case 3:
					switch( hitData.hitDirection )
					{
						case 1:
							animVariation = 32;
						break;
						case 2:
							animVariation = 33;
						break;
						case 3:
							animVariation = 34;
						break;
						case 4:
							animVariation = 35;
						break;
						default:
							return -1;
					}
				break;
				case 4:
					switch( hitData.hitDirection )
					{
						case 1:
							animVariation = 36;
						break;
						case 2:
							animVariation = 37;
						break;
						case 3:
							animVariation = 38;
						break;
						case 4:
							animVariation = 39;
						break;
						default:
							return -1;
					}
				break;
				case 5:
					switch( hitData.hitDirection )
					{
						case 1:
							animVariation = 40;
						break;
						case 2:
							animVariation = 41;
						break;
						case 3:
							animVariation = 42;
						break;
						case 4:
							animVariation = 43;
						break;
						default:
							return -1;
					}
				break;
				case 6:
					switch( hitData.hitDirection )
					{
						case 1:
							animVariation = 44;
						break;
						case 2:
							animVariation = 45;
						break;
						case 3:
							animVariation = 46;
						break;
						case 4:
							animVariation = 47;
						break;
						default:
							return -1;
					}
				break;
				default:
					return -1;
			}
		}
		return animVariation;
	}

}

abstract class AISubActionBlockData_Record_Implementation extends IScriptable
{

	public static function GetAnimVariation( context : ScriptExecutionContext, record : weak< AISubActionBlockData_Record > ) : Int32
	{
		var ownerPuppet : weak< ScriptedPuppet >;
		var attackDirection : Int32;
		var animVariation : Int32;
		animVariation = -1;
		ownerPuppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		attackDirection = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetHitReactionComponent().GetAttackDirection();
		switch( attackDirection )
		{
			case 0:
				animVariation = SetAnimVariation( ownerPuppet, EAIBlockDirection.Center );
			break;
			case 1:
				animVariation = SetAnimVariation( ownerPuppet, EAIBlockDirection.Center );
			break;
			case 2:
				animVariation = SetAnimVariation( ownerPuppet, EAIBlockDirection.Left );
			break;
			case 3:
				animVariation = SetAnimVariation( ownerPuppet, EAIBlockDirection.Left );
			break;
			case 4:
				animVariation = SetAnimVariation( ownerPuppet, EAIBlockDirection.Left );
			break;
			case 5:
				animVariation = SetAnimVariation( ownerPuppet, EAIBlockDirection.Right );
			break;
			case 6:
				animVariation = SetAnimVariation( ownerPuppet, EAIBlockDirection.Right );
			break;
			case 7:
				animVariation = SetAnimVariation( ownerPuppet, EAIBlockDirection.Right );
			break;
			case 8:
				animVariation = SetAnimVariation( ownerPuppet, EAIBlockDirection.Center );
			break;
			default:
				return -1;
		}
		return animVariation;
	}

	public static function SetAnimVariation( owner : weak< ScriptedPuppet >, direction : EAIBlockDirection ) : Int32
	{
		var animVariationList : array< Int32 >;
		var previousAnimVariation : Int32;
		var animVariation : Int32;
		var blackBoard : IBlackboard;
		animVariation = -1;
		blackBoard = owner.GetAIControllerComponent().GetActionBlackboard();
		if( !( blackBoard.GetBool( GetAllBlackboardDefs().AIAction.ownerCurrentAnimVariationSet ) ) )
		{
			switch( direction )
			{
				case EAIBlockDirection.Center:
					animVariationList.Resize( 3 );
				animVariationList[ 0 ] = 0;
				animVariationList[ 1 ] = 1;
				animVariationList[ 2 ] = 2;
				break;
				case EAIBlockDirection.Left:
					animVariationList.Resize( 2 );
				animVariationList[ 0 ] = 0;
				animVariationList[ 1 ] = 1;
				break;
				case EAIBlockDirection.Right:
					animVariationList.Resize( 2 );
				animVariationList[ 0 ] = 0;
				animVariationList[ 1 ] = 2;
				break;
			}
			if( animVariationList.Size() > 1 )
			{
				previousAnimVariation = GetAnimVariationInBlackBoard( blackBoard, owner );
				if( ( previousAnimVariation == 1 ) && animVariationList.Contains( 2 ) )
				{
					animVariation = 2;
				}
				else if( ( previousAnimVariation == 2 ) && animVariationList.Contains( 1 ) )
				{
					animVariation = 1;
				}
				else
				{
					if( animVariationList.Contains( previousAnimVariation ) )
					{
						animVariationList.Remove( previousAnimVariation );
					}
					animVariation = RandRange( 0, animVariationList.Size() );
					animVariation = animVariationList[ animVariation ];
				}
			}
			else
			{
				animVariation = animVariationList[ 0 ];
			}
			SetAnimVariationInBlackBoard( blackBoard, owner, animVariation );
		}
		else
		{
			return GetAnimVariationInBlackBoard( blackBoard, owner );
		}
		return animVariation;
	}

	public static function SetAnimVariationInBlackBoard( blackBoard : IBlackboard, owner : weak< ScriptedPuppet >, animVariation : Int32 )
	{
		blackBoard.SetInt( GetAllBlackboardDefs().AIAction.ownerLastBlockAnimVariation, animVariation );
		blackBoard.SetBool( GetAllBlackboardDefs().AIAction.ownerCurrentAnimVariationSet, true );
	}

	public static function GetAnimVariationInBlackBoard( blackBoard : IBlackboard, owner : weak< ScriptedPuppet > ) : Int32
	{
		return blackBoard.GetInt( GetAllBlackboardDefs().AIAction.ownerLastBlockAnimVariation );
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionBlockData_Record >, const duration : Float, interrupted : Bool )
	{
		var blackBoard : IBlackboard;
		blackBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		blackBoard.SetBool( GetAllBlackboardDefs().AIAction.ownerCurrentAnimVariationSet, false );
	}

}

abstract class AISubActionFail_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionFail_Record > ) {}

	public constexpr static function Update( context : ScriptExecutionContext, record : weak< AISubActionFail_Record >, duration : Float ) : AIbehaviorUpdateOutcome
	{
		return AIbehaviorUpdateOutcome.FAILURE;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionFail_Record >, const duration : Float, interrupted : Bool ) {}
}

abstract class AISubActionInitialReactionParams_Record_Implementation extends IScriptable
{

	public constexpr static function Update( context : ScriptExecutionContext, record : weak< AISubActionInitialReaction_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

	public static function GetAnimVariation( context : ScriptExecutionContext, record : weak< AISubActionInitialReaction_Record > ) : Int32
	{
		var direction : Float;
		if( record.DirectionObj() )
		{
			direction = GetAnimDirection( context, record );
		}
		if( MathHelper.IsFloatInRange( direction, -45.0, 45.0, true, true ) )
		{
			return 0;
		}
		else if( MathHelper.IsFloatInRange( direction, 45.0, 135.0, true, true ) )
		{
			return 1;
		}
		else if( MathHelper.IsFloatInRange( direction, 135.0, 180.0, true, true ) )
		{
			return 2;
		}
		else if( MathHelper.IsFloatInRange( direction, -180.0, -135.0, true, true ) )
		{
			return 3;
		}
		else if( MathHelper.IsFloatInRange( direction, -135.0, -45.0, true, true ) )
		{
			return 4;
		}
		return -1;
	}

	public static function GetAnimDirection( const context : ScriptExecutionContext, record : weak< AISubActionInitialReaction_Record > ) : Float
	{
		var vecToTarget : Vector4;
		var targetPos : Vector4;
		if( AIActionTarget.GetPosition( context, record.DirectionObj(), targetPos, false ) )
		{
			vecToTarget = targetPos - ScriptExecutionContext.GetOwner( context ).GetWorldPosition();
			return AngleNormalize180( Vector4.GetAngleDegAroundAxis( ScriptExecutionContext.GetOwner( context ).GetWorldForward(), vecToTarget, ScriptExecutionContext.GetOwner( context ).GetWorldUp() ) );
		}
		return 0.0;
	}

}

abstract class AISubActionRandomize_Record_Implementation extends IScriptable
{

	public constexpr static function Update( context : ScriptExecutionContext, record : weak< AISubActionRandomize_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

	public export static function GetAnimVariation( context : ScriptExecutionContext, record : weak< AISubActionRandomize_Record > ) : Int32
	{
		var animVariationList : array< Int32 >;
		var previousAnimVariation : Int32;
		var animVariation : Int32;
		var blackBoard : IBlackboard;
		animVariation = -1;
		blackBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		if( !( blackBoard.GetBool( GetAllBlackboardDefs().AIAction.ownerCurrentAnimVariationSet ) ) )
		{
			animVariationList = record.AnimVariationRandomize();
			if( animVariationList.Size() > 1 )
			{
				if( ( ( TweakDBID )( blackBoard.GetVariant( GetAllBlackboardDefs().AIAction.ownerLastAnimVariationAction ) ) ) != TDBID.None() )
				{
					previousAnimVariation = blackBoard.GetInt( GetAllBlackboardDefs().AIAction.ownerLastAnimVariation );
					if( animVariationList.Contains( previousAnimVariation ) )
					{
						animVariationList.Remove( previousAnimVariation );
					}
				}
				animVariation = RandRange( 0, animVariationList.Size() );
				animVariation = animVariationList[ animVariation ];
			}
			else
			{
				animVariation = animVariationList[ 0 ];
			}
			blackBoard.SetBool( GetAllBlackboardDefs().AIAction.ownerCurrentAnimVariationSet, true );
			blackBoard.SetInt( GetAllBlackboardDefs().AIAction.ownerLastAnimVariation, animVariation );
		}
		else
		{
			return blackBoard.GetInt( GetAllBlackboardDefs().AIAction.ownerLastAnimVariation );
		}
		return animVariation;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionRandomize_Record >, const duration : Float, interrupted : Bool )
	{
		var blackBoard : IBlackboard;
		blackBoard = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetAIControllerComponent().GetActionBlackboard();
		blackBoard.SetBool( GetAllBlackboardDefs().AIAction.ownerCurrentAnimVariationSet, false );
	}

}

abstract class AISubActionCallReinforcements_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionCallReinforcements_Record > )
	{
		if( record.Delay() == 0.0 )
		{
			StartCallReinforcement( context, record );
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionCallReinforcements_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			StartCallReinforcement( context, record );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionCallReinforcements_Record >, const duration : Float, interrupted : Bool )
	{
		if( record.Delay() < 0.0 )
		{
			StartCallReinforcement( context, record );
		}
	}

	public static function StartCallReinforcement( context : ScriptExecutionContext, record : weak< AISubActionCallReinforcements_Record > )
	{
		var m_puppet : weak< ScriptedPuppet >;
		var m_statPoolsSystem : StatPoolsSystem;
		var m_startPhoneCallEvent : StartEndPhoneCallEvent;
		var m_pauseResumePhoneCallEvent : PauseResumePhoneCallEvent;
		var m_statPoolType : gamedataStatPoolType;
		m_statPoolType = gamedataStatPoolType.CallReinforcementProgress;
		m_puppet = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		m_statPoolsSystem = GameInstance.GetStatPoolsSystem( ScriptExecutionContext.GetOwner( context ).GetGame() );
		if( !( m_statPoolsSystem.IsStatPoolAdded( m_puppet.GetEntityID(), m_statPoolType ) ) )
		{
			m_startPhoneCallEvent = new StartEndPhoneCallEvent;
			m_startPhoneCallEvent.callDuration = record.Duration();
			m_startPhoneCallEvent.startCall = true;
			m_startPhoneCallEvent.statType = gamedataStatType.CallReinforcement;
			m_startPhoneCallEvent.statPoolType = gamedataStatPoolType.CallReinforcementProgress;
			m_startPhoneCallEvent.statPoolName = "BaseStatPools.CallReinforcementProgress";
			m_puppet.QueueEvent( m_startPhoneCallEvent );
		}
		else
		{
			m_pauseResumePhoneCallEvent = new PauseResumePhoneCallEvent;
			m_pauseResumePhoneCallEvent.callDuration = record.Duration();
			m_pauseResumePhoneCallEvent.pauseCall = false;
			m_pauseResumePhoneCallEvent.statPoolType = m_statPoolType;
			m_puppet.QueueEvent( m_pauseResumePhoneCallEvent );
		}
	}

}

abstract class AISubActionGeneratePointOfInterestTarget_Record_Implementation extends IScriptable
{

	private static function SetPointOfInterest( context : ScriptExecutionContext, record : weak< AISubActionGeneratePointOfInterestTarget_Record > )
	{
		var direction : Vector4;
		var angleRange : Vector2;
		direction = ScriptExecutionContext.GetOwner( context ).GetWorldForward();
		angleRange = record.RandomPointZRotationAngleRange();
		angleRange.X = Deg2Rad( angleRange.X );
		angleRange.Y = Deg2Rad( angleRange.Y );
		direction = Vector4.RotateAxis( direction, Vector4( 0.0, 0.0, 1.0, 0.0 ), RandRangeF( angleRange.X, angleRange.Y ) );
		angleRange = record.RandomPointYRotationAngleRange();
		angleRange.X = Deg2Rad( angleRange.X );
		angleRange.Y = Deg2Rad( angleRange.Y );
		direction = Vector4.RotateAxis( direction, Vector4( 0.0, 1.0, 0.0, 0.0 ), RandRangeF( angleRange.X, angleRange.Y ) );
		direction = Vector4.Normalize( direction );
		direction *= 100.0;
		direction.Z += 2.0;
		ScriptExecutionContext.SetArgumentVector( context, 'PointOfInterest', ScriptExecutionContext.GetOwner( context ).GetWorldPosition() + direction );
	}

	private static function GetSquadMate( context : ScriptExecutionContext, record : weak< AISubActionGeneratePointOfInterestTarget_Record > ) : GameObject
	{
		var squadMembers : array< weak< Entity > >;
		var chosenObjectOfInterest : GameObject;
		var prevObjectOfInterest : GameObject;
		var tmpDot : Float;
		if( AISquadHelper.GetSquadmates( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), squadMembers ) )
		{
			squadMembers.Remove( ScriptExecutionContext.GetArgumentObject( context, 'FriendlyTarget' ) );
			if( squadMembers.Size() > 0 )
			{
				chosenObjectOfInterest = ( ( GameObject )( squadMembers[ RandRange( 0, squadMembers.Size() ) ] ) );
				prevObjectOfInterest = ScriptExecutionContext.GetArgumentObject( context, 'ObjectOfInterest' );
				while( squadMembers.Size() > 0 )
				{
					chosenObjectOfInterest = ( ( GameObject )( squadMembers[ RandRange( 0, squadMembers.Size() ) ] ) );
					if( chosenObjectOfInterest != prevObjectOfInterest )
					{
						tmpDot = Vector4.Dot( ScriptExecutionContext.GetOwner( context ).GetWorldForward(), Vector4.Normalize( chosenObjectOfInterest.GetWorldPosition() - ScriptExecutionContext.GetOwner( context ).GetWorldPosition() ) );
						if( tmpDot > CosF( Deg2Rad( record.SquadMateWatchingMaxAngle() ) ) )
						{
							return chosenObjectOfInterest;
						}
					}
					squadMembers.Remove( chosenObjectOfInterest );
				}
			}
		}
		return NULL;
	}

	private static function GetFriendlyTarget( context : ScriptExecutionContext, record : weak< AISubActionGeneratePointOfInterestTarget_Record > ) : GameObject
	{
		var friendlyTarget : GameObject;
		var tmpDot : Float;
		friendlyTarget = ScriptExecutionContext.GetArgumentObject( context, 'FriendlyTarget' );
		if( friendlyTarget && ( friendlyTarget != ScriptExecutionContext.GetArgumentObject( context, 'ObjectOfInterest' ) ) )
		{
			tmpDot = Vector4.Dot( ScriptExecutionContext.GetOwner( context ).GetWorldForward(), Vector4.Normalize( friendlyTarget.GetWorldPosition() - ScriptExecutionContext.GetOwner( context ).GetWorldPosition() ) );
			if( tmpDot > CosF( Deg2Rad( record.FriendlyTargetWatchingMaxAngle() ) ) )
			{
				return friendlyTarget;
			}
		}
		return NULL;
	}

	private static function GetClosestThreat( context : ScriptExecutionContext, record : weak< AISubActionGeneratePointOfInterestTarget_Record > ) : GameObject
	{
		var i : Int32;
		var tmpDot : Float;
		var threats : array< TrackedLocation >;
		var target : Entity;
		var minSqrDist : Float;
		var tmpSqrDist : Float;
		var ownerPos : Vector4;
		threats = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetTargetTrackerComponent().GetThreats( true );
		ownerPos = ScriptExecutionContext.GetOwner( context ).GetWorldPosition();
		if( threats.Size() > 0 )
		{
			minSqrDist = Vector4.DistanceSquared( ownerPos, threats[ 0 ].entity.GetWorldPosition() );
			target = threats[ 0 ].entity;
		}
		for( i = 1; i < threats.Size(); i += 1 )
		{
			tmpSqrDist = Vector4.DistanceSquared( ownerPos, threats[ i ].entity.GetWorldPosition() );
			if( tmpSqrDist < minSqrDist )
			{
				target = threats[ i ].entity;
				minSqrDist = tmpSqrDist;
			}
		}
		if( target && ( target != ScriptExecutionContext.GetArgumentObject( context, 'ObjectOfInterest' ) ) )
		{
			tmpDot = Vector4.Dot( ScriptExecutionContext.GetOwner( context ).GetWorldForward(), Vector4.Normalize( target.GetWorldPosition() - ScriptExecutionContext.GetOwner( context ).GetWorldPosition() ) );
			if( tmpDot > CosF( Deg2Rad( record.ClosestThreatWatchingMaxAngle() ) ) )
			{
				return ( ( GameObject )( target ) );
			}
		}
		return NULL;
	}

	public export static function Activate( context : ScriptExecutionContext, record : weak< AISubActionGeneratePointOfInterestTarget_Record > )
	{
		var prevObjectOfInterest : GameObject;
		var randomVal : Float;
		var weightsSum : Float;
		var chosenObjectOfInterest : GameObject;
		var triedOptions : Bool[ 3 ];
		prevObjectOfInterest = ScriptExecutionContext.GetArgumentObject( context, 'ObjectOfInterest' );
		weightsSum = ( ( record.ChoosingRandomPointChanceWeight() + record.ChoosingSquadMateChanceWeight() ) + record.ChoosingFriendlyTargetChanceWeight() ) + record.ChoosingClosestThreatChanceWeight();
		SetPointOfInterest( context, record );
		if( prevObjectOfInterest == NULL )
		{
			weightsSum -= record.ChoosingRandomPointChanceWeight();
		}
		while( chosenObjectOfInterest == NULL )
		{
			randomVal = RandRangeF( 0.0, weightsSum );
			if( !( triedOptions[ 0 ] ) )
			{
				if( randomVal < record.ChoosingSquadMateChanceWeight() )
				{
					chosenObjectOfInterest = GetSquadMate( context, record );
					if( chosenObjectOfInterest == NULL )
					{
						weightsSum -= record.ChoosingSquadMateChanceWeight();
						triedOptions[ 0 ] = true;
						continue;
					}
					break;
				}
				randomVal -= record.ChoosingSquadMateChanceWeight();
			}
			if( !( triedOptions[ 1 ] ) )
			{
				if( randomVal < record.ChoosingFriendlyTargetChanceWeight() )
				{
					chosenObjectOfInterest = GetFriendlyTarget( context, record );
					if( chosenObjectOfInterest == NULL )
					{
						weightsSum -= record.ChoosingFriendlyTargetChanceWeight();
						triedOptions[ 1 ] = true;
						continue;
					}
					break;
				}
				randomVal -= record.ChoosingFriendlyTargetChanceWeight();
			}
			if( !( triedOptions[ 2 ] ) )
			{
				if( randomVal < record.ChoosingClosestThreatChanceWeight() )
				{
					chosenObjectOfInterest = GetClosestThreat( context, record );
					if( chosenObjectOfInterest == NULL )
					{
						weightsSum -= record.ChoosingClosestThreatChanceWeight();
						triedOptions[ 2 ] = true;
						continue;
					}
					break;
				}
			}
			break;
		}
		ScriptExecutionContext.SetArgumentObject( context, 'ObjectOfInterest', chosenObjectOfInterest );
	}

	public export static function Update( context : ScriptExecutionContext, record : weak< AISubActionGeneratePointOfInterestTarget_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		var randomDuration : Float;
		var currentObjectOfInterest : GameObject;
		var currentPointOfInterest : Vector4;
		var durationRange : Vector2;
		var seed : Int32;
		var tmpDot : Float;
		currentObjectOfInterest = ScriptExecutionContext.GetArgumentObject( context, 'ObjectOfInterest' );
		currentPointOfInterest = ScriptExecutionContext.GetArgumentVector( context, 'PointOfInterest' );
		if( currentObjectOfInterest == NULL )
		{
			durationRange = record.RandomPointDurationRange();
		}
		else
		{
			tmpDot = Vector4.Dot( ScriptExecutionContext.GetOwner( context ).GetWorldForward(), Vector4.Normalize( currentObjectOfInterest.GetWorldPosition() - ScriptExecutionContext.GetOwner( context ).GetWorldPosition() ) );
			if( currentObjectOfInterest == ScriptExecutionContext.GetArgumentObject( context, 'FriendlyTarget' ) )
			{
				if( tmpDot < CosF( Deg2Rad( record.FriendlyTargetWatchingMaxAngle() ) ) )
				{
					return AIbehaviorUpdateOutcome.SUCCESS;
				}
				durationRange = record.FriendlyTargetDurationRange();
			}
			else if( TargetTrackingExtension.IsThreatInThreatList( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), currentObjectOfInterest, true, true ) )
			{
				if( tmpDot < CosF( Deg2Rad( record.ClosestThreatWatchingMaxAngle() ) ) )
				{
					return AIbehaviorUpdateOutcome.SUCCESS;
				}
				durationRange = record.SquadMateDurationRange();
			}
			else
			{
				if( tmpDot < CosF( Deg2Rad( record.SquadMateWatchingMaxAngle() ) ) )
				{
					return AIbehaviorUpdateOutcome.SUCCESS;
				}
				durationRange = record.ClosestThreatDurationRange();
			}
		}
		seed = ( ( Int32 )( 100.0 * ( currentPointOfInterest.Y + currentPointOfInterest.Z ) ) );
		randomDuration = RandNoiseF( seed, durationRange.Y, durationRange.X );
		if( duration > randomDuration )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public export static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionGeneratePointOfInterestTarget_Record >, const duration : Float, interrupted : Bool ) {}
}

abstract class AISubActionDroneModifyAltitude_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionDroneModifyAltitude_Record > )
	{
		if( record.Delay() <= 0.0 )
		{
			SetDesiredAltitudeOffset( context, record.AltitudeOffset() );
		}
	}

	public static function Update( context : ScriptExecutionContext, record : weak< AISubActionDroneModifyAltitude_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		if( record.Delay() <= 0.0 )
		{
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		if( ( record.Delay() > 0.0 ) && ( duration >= record.Delay() ) )
		{
			SetDesiredAltitudeOffset( context, record.AltitudeOffset() );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionDroneModifyAltitude_Record >, const duration : Float, interrupted : Bool )
	{
		SetDesiredAltitudeOffset( context, 0.0 );
	}

	public static function SetDesiredAltitudeOffset( context : ScriptExecutionContext, desiredOffset : Float )
	{
		var altitudeOffsetAnimFeature : AnimFeature_DroneActionAltitudeOffset;
		altitudeOffsetAnimFeature = new AnimFeature_DroneActionAltitudeOffset;
		altitudeOffsetAnimFeature.desiredOffset = desiredOffset;
		AnimationControllerComponent.ApplyFeatureToReplicate( ScriptExecutionContext.GetOwner( context ), 'ActionAltitudeOffset', altitudeOffsetAnimFeature );
	}

}

abstract class AISubActionSetTopThreatPersistance_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionSetTopThreatPersistance_Record > )
	{
		SetTopThreatPersistance( context, record, true );
	}

	public constexpr static function Update( context : ScriptExecutionContext, record : weak< AISubActionSetTopThreatPersistance_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionSetTopThreatPersistance_Record >, const duration : Float, interrupted : Bool )
	{
		ResetAllThreatsPersistenceForSource( context, record );
	}

	public static function SetTopThreatPersistance( context : ScriptExecutionContext, record : weak< AISubActionSetTopThreatPersistance_Record >, set : Bool )
	{
		var combatTarget : weak< GameObject >;
		combatTarget = ScriptExecutionContext.GetArgumentObject( context, 'CombatTarget' );
		if( combatTarget )
		{
			TargetTrackingExtension.SetThreatPersistence( ( ( weak< weak< ScriptedPuppet > > )( ScriptExecutionContext.GetOwner( context ) ) ), combatTarget, set, ( ( Uint32 )( record.Source().EnumValue() ) ) );
		}
	}

	public static function ResetAllThreatsPersistenceForSource( context : ScriptExecutionContext, record : weak< AISubActionSetTopThreatPersistance_Record > )
	{
		TargetTrackingExtension.SetCurrentThreatsPersistence( ( ( weak< weak< ScriptedPuppet > > )( ScriptExecutionContext.GetOwner( context ) ) ), false, ( ( Uint32 )( record.Source().EnumValue() ) ) );
	}

}

abstract class AISubActionScaleDurationWithDistance_Record_Implementation extends IScriptable
{

	public static function Activate( context : ScriptExecutionContext, record : weak< AISubActionScaleDurationWithDistance_Record > ) {}

	public constexpr static function Update( context : ScriptExecutionContext, record : weak< AISubActionScaleDurationWithDistance_Record >, const duration : Float ) : AIbehaviorUpdateOutcome
	{
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

	public static function Deactivate( context : ScriptExecutionContext, record : weak< AISubActionScaleDurationWithDistance_Record >, const duration : Float, interrupted : Bool ) {}

	public static function GetPhaseDuration( context : ScriptExecutionContext, record : weak< AISubActionScaleDurationWithDistance_Record >, actionPhase : Int32, baseDuration : Float ) : Float
	{
		var source, target : weak< GameObject >;
		var sourcePosition, targetPosition : Vector4;
		var distanceRange, timeRange : Vector2;
		var distance : Float;
		if( !( AIActionTarget.Get( context, record.Source(), false, source, sourcePosition ) ) )
		{
			return -1.0;
		}
		if( !( AIActionTarget.Get( context, record.Target(), false, target, targetPosition ) ) )
		{
			return -1.0;
		}
		distance = Vector4.Distance( targetPosition, sourcePosition );
		distanceRange = record.DistanceRange();
		distanceRange.X = MaxF( 0.0, distanceRange.X );
		distanceRange.Y = MaxF( 0.0, distanceRange.Y );
		if( distanceRange.Y < distanceRange.X )
		{
			distanceRange.Y = distanceRange.X;
		}
		timeRange = record.ScaleDistanceToTime();
		timeRange.X = MaxF( 0.0, timeRange.X );
		timeRange.Y = MaxF( 0.0, timeRange.Y );
		if( timeRange.Y < timeRange.X )
		{
			timeRange.Y = timeRange.X;
		}
		if( ( distanceRange.Y >= 0.0 ) && ( distance > distanceRange.Y ) )
		{
			distance = distanceRange.Y;
		}
		if( ( distanceRange.X >= 0.0 ) && ( distance < distanceRange.X ) )
		{
			distance = distanceRange.X;
		}
		return ProportionalClampF( distanceRange.X, distanceRange.Y, distance, timeRange.X, timeRange.Y );
	}

}

