class ActionDisposal extends ActionBool
{

	public override function CompleteAction( gameInstance : GameInstance )
	{
		var i : Int32;
		var rewards : array< weak< RewardBase_Record > >;
		var actionEffects : array< weak< ObjectActionEffect_Record > >;
		var mountingInfo : MountingInfo;
		GameInstance.GetPersistencySystem( gameInstance ).QueuePSDeviceEvent( this );
		mountingInfo = GameInstance.GetMountingFacility( gameInstance ).GetMountingInfoSingleWithObjects( , GetExecutor() );
		GetObjectActionRecord().Rewards( rewards );
		for( i = 0; i < rewards.Size(); i += 1 )
		{
			RPGManager.GiveReward( gameInstance, rewards[ i ].GetID(), mountingInfo.childId );
		}
		GetObjectActionRecord().CompletionEffects( actionEffects );
		ProcessStatusEffects( actionEffects, gameInstance );
	}

}

class DisposeBody extends ActionDisposal
{

	public function SetProperties()
	{
		actionName = 'Dispose';
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'Dispose', true, 'Dispose', 'Dispose' );
	}

	public constexpr static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		return true;
	}

}

class TakedownAndDisposeBody extends ActionDisposal
{

	public function SetProperties()
	{
		actionName = 'TakedownAndDispose';
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'TakedownAndDispose', true, 'TakedownAndDispose', 'TakedownAndDispose' );
	}

	public constexpr static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		return true;
	}

}

class NonlethalTakedownAndDisposeBody extends ActionDisposal
{

	public function SetProperties()
	{
		actionName = 'NonlethalTakedownAndDispose';
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'NonlethalTakedownAndDispose', true, 'NonlethalTakedownAndDispose', 'NonlethalTakedownAndDispose' );
	}

	public constexpr static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		return true;
	}

}

class SpiderbotDistractionPerformed extends ActionBool
{

	public function SetProperties( action_name : CName )
	{
		actionName = action_name;
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( action_name, true, action_name, action_name );
	}

	public constexpr static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		return true;
	}

}

class OverchargeDevice extends ActionBool
{

	public function SetProperties( action_name : CName )
	{
		actionName = action_name;
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( action_name, true, action_name, action_name );
	}

	public constexpr static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		return true;
	}

	public override function GetTweakDBChoiceRecord() : String
	{
		if( TDBID.IsValid( m_objectActionID ) )
		{
			return super.GetTweakDBChoiceRecord();
		}
		else
		{
			return "Overcharge";
		}
	}

}

struct DisposalDeviceSetup
{
	instanceeditable persistent var m_numberOfUses : Int32;
	default m_numberOfUses = 1;
	instanceeditable var m_isBodyRequired : Bool;
	default m_isBodyRequired = true;
	[ category = "InteractionNamesSetup" ][ customEditor = "TweakDBGroupInheritance;Interactions.InteractionChoice;Interactions.MountChoice" ]
	instanceeditable var m_actionName : TweakDBID;
	[ category = "InteractionNamesSetup" ][ customEditor = "TweakDBGroupInheritance;Interactions.InteractionChoice;Interactions.MountChoice" ]
	instanceeditable var m_takedownActionName : TweakDBID;
	[ category = "InteractionNamesSetup" ][ customEditor = "TweakDBGroupInheritance;Interactions.InteractionChoice;Interactions.MountChoice" ]
	instanceeditable var m_nonlethalTakedownActionName : TweakDBID;
}

struct DistractionSetup
{
	instanceeditable var m_StimuliRange : Float;
	default m_StimuliRange = 10.f;
	instanceeditable var m_disableOnActivation : Bool;
	[ category = "AvailableInteractions" ]
	instanceeditable var m_hasSimpleInteraction : Bool;
	default m_hasSimpleInteraction = false;
	[ category = "AvailableInteractions" ]
	instanceeditable var m_hasSpiderbotInteraction : Bool;
	default m_hasSpiderbotInteraction = false;
	[ category = "AvailableInteractions" ]
	instanceeditable var m_hasQuickHack : Bool;
	default m_hasQuickHack = false;
	[ category = "AvailableInteractions" ]
	instanceeditable var m_hasComputerInteraction : Bool;
	default m_hasComputerInteraction = false;
	[ category = "InteractionNamesSetup" ][ customEditor = "TweakDBGroupInheritance;Interactions.InteractionChoice;Interactions.MountChoice" ]
	instanceeditable var m_alternativeInteractionName : TweakDBID;
	[ category = "InteractionNamesSetup" ][ customEditor = "TweakDBGroupInheritance;Interactions.InteractionChoice;Interactions.MountChoice" ]
	instanceeditable var m_alternativeSpiderbotInteractionName : TweakDBID;
	[ category = "InteractionNamesSetup" ][ customEditor = "TweakDBGroupInheritance;Interactions.InteractionChoice;Interactions.MountChoice" ]
	instanceeditable var m_alternativeQuickHackName : TweakDBID;
	instanceeditable inlined var m_skillChecks : EngDemoContainer;
	const instanceeditable inlined var explosionDefinition : array< ExplosiveDeviceResourceDefinition >;
}

class DisposalDeviceController extends ScriptableDeviceComponent
{

	public const override function GetPS() : DisposalDeviceControllerPS
	{
		return ( ( DisposalDeviceControllerPS )( GetBasePS() ) );
	}

}

class DisposalDeviceControllerPS extends ScriptableDeviceComponentPS
{
	default m_deviceName = "LocKey#102";
	default m_tweakDBRecord = T"Devices.DisposalDevice";
	default m_tweakDBDescriptionRecord = T"device_descriptions.DisposalDevice";
	default m_shouldScannerShowStatus = false;
	default m_shouldScannerShowNetwork = false;
	default m_shouldScannerShowRole = true;
	private instanceeditable persistent var m_DisposalDeviceSetup : DisposalDeviceSetup;
	private instanceeditable persistent var m_distractionSetup : DistractionSetup;
	private instanceeditable persistent var m_explosionSetup : DistractionSetup;
	private persistent var m_isDistractionDisabled : Bool;
	private persistent var m_wasActivated : Bool;
	private persistent var m_wasLethalTakedownPerformed : Bool;
	private var m_isPlayerCurrentlyPerformingDisposal : Bool;

	public function GetInteractionName() : TweakDBID
	{
		return m_distractionSetup.m_alternativeInteractionName;
	}

	public function WasActivated() : Bool
	{
		return m_wasActivated;
	}

	public function SetIsPlayerCurrentlyPerformingDisposal( value : Bool )
	{
		m_isPlayerCurrentlyPerformingDisposal = value;
	}

	public const function WasLethalTakedownPerformed() : Bool
	{
		return m_wasLethalTakedownPerformed;
	}

	public function SetWasLethalTakedownPerformed( value : Bool )
	{
		m_wasLethalTakedownPerformed = value;
	}

	public function GetQuickHackName() : TweakDBID
	{
		return m_distractionSetup.m_alternativeQuickHackName;
	}

	public function GetActionName() : TweakDBID
	{
		return m_DisposalDeviceSetup.m_actionName;
	}

	public function GetTakedownActionName() : TweakDBID
	{
		return m_DisposalDeviceSetup.m_takedownActionName;
	}

	public function GetNonlethalTakedownActionName() : TweakDBID
	{
		return m_DisposalDeviceSetup.m_nonlethalTakedownActionName;
	}

	public function GetStimuliRange() : Float
	{
		return m_distractionSetup.m_StimuliRange;
	}

	public const function HasQuickHackDistraction() : Bool
	{
		return m_distractionSetup.m_hasQuickHack;
	}

	public function HasSpiderbotInteraction() : Bool
	{
		return m_distractionSetup.m_hasSpiderbotInteraction;
	}

	public function HasSpiderbotExplosionInteraction() : Bool
	{
		return m_explosionSetup.m_hasSpiderbotInteraction;
	}

	public function HasComputerInteraction() : Bool
	{
		return m_explosionSetup.m_hasComputerInteraction;
	}

	public function GetExplosionDeinitionArray() : array< ExplosiveDeviceResourceDefinition >
	{
		return m_explosionSetup.explosionDefinition;
	}

	public function GetNumberOfUses() : Int32
	{
		return m_DisposalDeviceSetup.m_numberOfUses;
	}

	protected override function GetSkillCheckContainerForSetup() : BaseSkillCheckContainer
	{
		return m_distractionSetup.m_skillChecks;
	}

	private function ActionDisposeBody( interactionTweak : TweakDBID ) : DisposeBody
	{
		var action : DisposeBody;
		action = new DisposeBody;
		action.clearanceLevel = 2;
		action.SetUp( this );
		action.SetProperties();
		action.AddDeviceName( m_deviceName );
		action.CreateInteraction( , , interactionTweak );
		return action;
	}

	private function ActionTakedownAndDisposeBody( interactionTweak : TweakDBID ) : TakedownAndDisposeBody
	{
		var action : TakedownAndDisposeBody;
		action = new TakedownAndDisposeBody;
		action.clearanceLevel = 2;
		action.SetUp( this );
		action.SetProperties();
		action.AddDeviceName( m_deviceName );
		action.CreateInteraction( , , interactionTweak );
		return action;
	}

	private function ActionNonlethalTakedownAndDisposeBody( interactionTweak : TweakDBID ) : NonlethalTakedownAndDisposeBody
	{
		var action : NonlethalTakedownAndDisposeBody;
		action = new NonlethalTakedownAndDisposeBody;
		action.clearanceLevel = 2;
		action.SetUp( this );
		action.SetProperties();
		action.AddDeviceName( m_deviceName );
		action.CreateInteraction( , , interactionTweak );
		return action;
	}

	protected function ActionQuickHackDistraction( interactionTweak : TweakDBID ) : QuickHackDistraction
	{
		var action : QuickHackDistraction;
		action = new QuickHackDistraction;
		action = super.ActionQuickHackDistraction();
		action.CreateInteraction( , , interactionTweak );
		action.CreateInteraction();
		action.SetDurationValue( GetDistractionDuration( action ) );
		return action;
	}

	protected function ActionSpiderbotDistraction( const interactionName : ref< String > ) : SpiderbotDistraction
	{
		var action : SpiderbotDistraction;
		action = new SpiderbotDistraction;
		action.clearanceLevel = 2;
		action.SetUp( this );
		action.SetProperties();
		action.AddDeviceName( m_deviceName );
		action.CreateInteraction( , interactionName );
		return action;
	}

	protected function ActionSpiderbotExplosion( const interactionName : ref< String > ) : SpiderbotExplodeExplosiveDevice
	{
		var action : SpiderbotExplodeExplosiveDevice;
		action = new SpiderbotExplodeExplosiveDevice;
		action.clearanceLevel = 2;
		action.SetUp( this );
		action.SetProperties();
		action.AddDeviceName( m_deviceName );
		action.CreateInteraction( , interactionName );
		return action;
	}

	protected function ActionSpiderbotExplodeExplosiveDevicePerformed() : SpiderbotExplodeExplosiveDevicePerformed
	{
		var action : SpiderbotExplodeExplosiveDevicePerformed;
		action = new SpiderbotExplodeExplosiveDevicePerformed;
		action.clearanceLevel = DefaultActionsParametersHolder.GetSpiderbotClearance();
		action.SetUp( this );
		action.SetProperties();
		action.AddDeviceName( m_deviceName );
		return action;
	}

	protected function ActionSpiderbotDistractionPerformed() : SpiderbotDistractionPerformed
	{
		var action : SpiderbotDistractionPerformed;
		action = new SpiderbotDistractionPerformed;
		action.clearanceLevel = 2;
		action.SetUp( this );
		action.SetProperties( 'Distract' );
		action.AddDeviceName( m_deviceName );
		return action;
	}

	protected function ActionOverchargeDevice() : OverchargeDevice
	{
		var action : OverchargeDevice;
		action = new OverchargeDevice;
		action.clearanceLevel = DefaultActionsParametersHolder.GetInteractiveClearance();
		action.SetUp( this );
		action.SetProperties( 'Overcharge' );
		action.AddDeviceName( m_deviceName );
		action.CreateActionWidgetPackage();
		return action;
	}

	protected function ActionToggleActivation( interactionTweak : TweakDBID ) : ToggleActivation
	{
		var action : ToggleActivation;
		action = new ToggleActivation;
		action.SetUp( this );
		action.SetProperties( m_deviceState );
		action.AddDeviceName( m_deviceName );
		action.CreateInteraction( , , interactionTweak );
		return action;
	}

	private const function GetPlayerSMBlackboard() : IBlackboard
	{
		var psmBlackboard : IBlackboard;
		var playerPuppet : PlayerPuppet;
		playerPuppet = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( GetGameInstance() ).GetLocalPlayerControlledGameObject() ) );
		psmBlackboard = GameInstance.GetBlackboardSystem( GetGameInstance() ).GetLocalInstanced( playerPuppet.GetEntityID(), GetAllBlackboardDefs().PlayerStateMachine );
		return psmBlackboard;
	}

	public override function GetActions( out actions : array< DeviceAction >, context : GetActionsContext ) : Bool
	{
		var action : ScriptableDeviceAction;
		if( IsDisabled() || m_isPlayerCurrentlyPerformingDisposal )
		{
			return false;
		}
		if( HasComputerInteraction() )
		{
			actions.PushBack( ActionOverchargeDevice() );
		}
		if( m_distractionSetup.m_hasSimpleInteraction && !( m_wasActivated ) )
		{
			actions.PushBack( ActionToggleActivation( GetInteractionName() ) );
		}
		if( !( IsPlayerCarrying() || IsEnemyGrappled() ) )
		{
			super.GetActions( actions, context );
		}
		if( IsNPCDisposalBlockedStatusEffect() )
		{
			return false;
		}
		if( IsPlayerDroppingBody() )
		{
			return false;
		}
		if( StatusEffectSystem.ObjectHasStatusEffectWithTag( context.processInitiatorObject, 'NoWorldInteractions' ) )
		{
			return false;
		}
		if( IsEnemyGrappled() )
		{
			action = ActionTakedownAndDisposeBody( GetTakedownActionName() );
			action.SetInactiveWithReason( GetNumberOfUses() > 0, "LocKey#2115" );
			actions.PushBack( action );
		}
		if( IsPlayerCarrying() )
		{
			action = ActionDisposeBody( GetActionName() );
			action.SetInactiveWithReason( GetNumberOfUses() > 0, "LocKey#2115" );
			actions.PushBack( action );
		}
		SetActionIllegality( actions, m_illegalActions.regularActions );
		return true;
	}

	protected function IsNPCDisposalBlockedStatusEffect() : Bool
	{
		var mountingInfo : MountingInfo;
		var npc : weak< NPCPuppet >;
		var playerPuppet : PlayerPuppet;
		playerPuppet = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( GetGameInstance() ).GetLocalPlayerControlledGameObject() ) );
		mountingInfo = GameInstance.GetMountingFacility( GetGameInstance() ).GetMountingInfoSingleWithObjects( , playerPuppet );
		npc = ( ( NPCPuppet )( GameInstance.FindEntityByID( GetGameInstance(), mountingInfo.childId ) ) );
		return StatusEffectSystem.ObjectHasStatusEffect( npc, T"BaseStatusEffect.BlockBodyDisposal" );
	}

	public const function IsPlayerCarrying() : Bool
	{
		return GetPlayerSMBlackboard().GetBool( GetAllBlackboardDefs().PlayerStateMachine.Carrying );
	}

	public const function IsEnemyGrappled() : Bool
	{
		return GetPlayerSMBlackboard().GetInt( GetAllBlackboardDefs().PlayerStateMachine.Takedown ) == ( ( Int32 )( gamePSMTakedown.Grapple ) );
	}

	protected function IsPlayerDroppingBody() : Bool
	{
		return GetPlayerSMBlackboard().GetInt( GetAllBlackboardDefs().PlayerStateMachine.BodyCarrying ) == ( ( Int32 )( gamePSMBodyCarrying.Drop ) );
	}

	protected const override function CanCreateAnyQuickHackActions() : Bool
	{
		if( IsDisabled() || IsDistracting() )
		{
			return false;
		}
		else if( HasQuickHackDistraction() )
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	protected override function GetQuickHackActions( out actions : array< DeviceAction >, const context : ref< GetActionsContext > )
	{
		var currentAction : ScriptableDeviceAction;
		if( IsDisabled() || IsDistracting() )
		{
			return;
		}
		if( HasQuickHackDistraction() )
		{
			currentAction = ActionQuickHackDistraction();
			currentAction.SetObjectActionID( T"DeviceAction.MalfunctionClassHack" );
			currentAction.SetDurationValue( GetDistractionDuration( currentAction ) );
			actions.PushBack( currentAction );
		}
		FinalizeGetQuickHackActions( actions, context );
	}

	protected override function CanCreateAnySpiderbotActions() : Bool
	{
		return false;
	}

	protected override function GetSpiderbotActions( actions : ref< array< DeviceAction > >, const context : ref< GetActionsContext > ) {}

	public function OnDistraction( evt : Distraction ) : EntityNotificationType
	{
		if( m_distractionSetup.m_disableOnActivation )
		{
			m_isDistractionDisabled = true;
		}
		UseNotifier( evt );
		return EntityNotificationType.SendThisEventToEntity;
	}

	public override function OnToggleActivation( evt : ToggleActivation ) : EntityNotificationType
	{
		UseNotifier( evt );
		m_wasActivated = true;
		return EntityNotificationType.SendThisEventToEntity;
	}

	public function OnSpiderbotDistraction( evt : SpiderbotDistraction ) : EntityNotificationType
	{
		SendSpiderbotToPerformAction( ActionSpiderbotDistractionPerformed(), evt.GetExecutor() );
		UseNotifier( evt );
		return EntityNotificationType.SendThisEventToEntity;
	}

	public function OnSpiderbotExplosion( evt : SpiderbotExplodeExplosiveDevice ) : EntityNotificationType
	{
		SendSpiderbotToPerformAction( ActionSpiderbotExplodeExplosiveDevicePerformed(), evt.GetExecutor() );
		UseNotifier( evt );
		return EntityNotificationType.SendThisEventToEntity;
	}

	public function OnSpiderbotExplosionPerformed( evt : SpiderbotExplodeExplosiveDevicePerformed ) : EntityNotificationType
	{
		if( m_explosionSetup.m_disableOnActivation )
		{
			DisableDevice();
		}
		UseNotifier( evt );
		return EntityNotificationType.SendThisEventToEntity;
	}

	public function OnSpiderbotDistractionPerformed( evt : SpiderbotDistractionPerformed ) : EntityNotificationType
	{
		if( m_distractionSetup.m_disableOnActivation )
		{
			m_isDistractionDisabled = true;
		}
		UseNotifier( evt );
		return EntityNotificationType.SendThisEventToEntity;
	}

	public function OnDisposeBody( evt : DisposeBody ) : EntityNotificationType
	{
		var notifier : ActionNotifier;
		notifier = new ActionNotifier;
		notifier.SetNone();
		m_DisposalDeviceSetup.m_numberOfUses = m_DisposalDeviceSetup.m_numberOfUses - 1;
		m_isPlayerCurrentlyPerformingDisposal = true;
		Notify( notifier, evt );
		return EntityNotificationType.SendThisEventToEntity;
	}

	public function OnTakedownAndDisposeBody( evt : TakedownAndDisposeBody ) : EntityNotificationType
	{
		var notifier : ActionNotifier;
		notifier = new ActionNotifier;
		notifier.SetNone();
		m_DisposalDeviceSetup.m_numberOfUses = m_DisposalDeviceSetup.m_numberOfUses - 1;
		m_isPlayerCurrentlyPerformingDisposal = true;
		Notify( notifier, evt );
		return EntityNotificationType.SendThisEventToEntity;
	}

	public function OnNonlethalTakedownAndDisposeBody( evt : NonlethalTakedownAndDisposeBody ) : EntityNotificationType
	{
		var notifier : ActionNotifier;
		notifier = new ActionNotifier;
		notifier.SetNone();
		m_DisposalDeviceSetup.m_numberOfUses = m_DisposalDeviceSetup.m_numberOfUses - 1;
		m_isPlayerCurrentlyPerformingDisposal = true;
		Notify( notifier, evt );
		return EntityNotificationType.SendThisEventToEntity;
	}

	public function OnOverchargeDevice( evt : OverchargeDevice ) : EntityNotificationType
	{
		UseNotifier( evt );
		DisableDevice();
		return EntityNotificationType.SendThisEventToEntity;
	}

}

