class ExplosiveDeviceController extends BasicDistractionDeviceController
{

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

}

class ExplosiveDeviceControllerPS extends BasicDistractionDeviceControllerPS
{
	default m_deviceName = "LocKey#42163";
	default m_tweakDBRecord = T"Devices.ExplosiveDevice";
	default m_tweakDBDescriptionRecord = T"device_descriptions.ExplosiveDevice";
	default m_shouldScannerShowNetwork = false;
	default m_shouldScannerShowStatus = false;
	default m_shouldScannerShowHealth = true;
	protected instanceeditable inlined var m_explosiveSkillChecks : EngDemoContainer;
	[ category = "Explosive properties" ][ tooltip = "The FIRST element in the vfxResourceOnFirstHit array will be used for normal first hit effects, the SECOND element will only be used if the device has a distraction collider and that is what is hit by the player." ]
	protected const editable var m_explosionDefinition : array< ExplosiveDeviceResourceDefinition >;
	[ category = "Explosive properties" ]
	protected editable var m_explosiveWithQhacks : Bool;
	[ category = "Explosive properties" ]
	protected instanceeditable var m_HealthDecay : Float;
	default m_HealthDecay = 0f;
	[ category = "Explosive properties" ]
	protected instanceeditable var m_timeToMeshSwap : Float;
	default m_timeToMeshSwap = 0.1f;
	[ category = "Explosive properties" ]
	protected editable var m_shouldDistractionHitVFXIgnoreHitPosition : Bool;
	[ category = "Explosive properties" ]
	protected editable var m_canBeDisabledWithQhacks : Bool;
	protected var m_disarmed : Bool;
	private persistent var m_exploded : Bool;
	[ category = "Tech design" ]
	protected editable var m_provideExplodeAction : Bool;
	default m_provideExplodeAction = true;
	[ category = "Tech design" ]
	protected editable var m_doExplosiveEngineerLogic : Bool;
	default m_doExplosiveEngineerLogic = true;

	protected event OnInstantiated()
	{
		super.OnInstantiated();
		if( !( IsStringValid( m_deviceName ) ) )
		{
			m_deviceName = "LocKey#42163";
		}
	}

	protected override function GetSkillCheckContainerForSetup() : BaseSkillCheckContainer
	{
		return m_explosiveSkillChecks;
	}

	protected override function GameAttached() {}

	public function PushPersistentData() {}

	public function GetExplosionDefinition( index : Int32 ) : ExplosiveDeviceResourceDefinition
	{
		return m_explosionDefinition[ index ];
	}

	public function GetExplosionDefinitionArray() : array< ExplosiveDeviceResourceDefinition >
	{
		return m_explosionDefinition;
	}

	public const function IsExplosiveWithQhacks() : Bool
	{
		return m_explosiveWithQhacks;
	}

	public function GetHealthDecay() : Float
	{
		return m_HealthDecay;
	}

	public function GetTimeToMeshSwap() : Float
	{
		return m_timeToMeshSwap;
	}

	public function GetDistractionHitVFXIgnoreHitPosition() : Bool
	{
		return m_shouldDistractionHitVFXIgnoreHitPosition;
	}

	public const function IsDisabledWithQhacks() : Bool
	{
		return m_canBeDisabledWithQhacks;
	}

	public quest const function IsExploded() : Bool
	{
		return m_exploded;
	}

	public function DoExplosiveResolveGameplayLogic() : Bool
	{
		if( !( m_doExplosiveEngineerLogic ) || !( m_provideExplodeAction ) )
		{
			return false;
		}
		return true;
	}

	public function SetExplodedState( state : Bool )
	{
		m_exploded = state;
		SendPSChangedEvent();
	}

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

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

	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;
	}

	public constexpr function OnSpiderbotExplodeExplosiveDevicePerformed( evt : SpiderbotExplodeExplosiveDevicePerformed ) : EntityNotificationType
	{
		return EntityNotificationType.SendThisEventToEntity;
	}

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

	public function OnSpiderbotDistractExplosiveDevice( evt : SpiderbotDistractExplosiveDevice ) : EntityNotificationType
	{
		m_distractExecuted = true;
		SendSpiderbotToPerformAction( ActionSpiderbotDistractExplosiveDevicePerformed(), evt.GetExecutor() );
		UseNotifier( evt );
		return EntityNotificationType.SendThisEventToEntity;
	}

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

	public function OnSpiderbotDistractExplosiveDevicePerformed( evt : SpiderbotDistractExplosiveDevicePerformed ) : EntityNotificationType
	{
		UseNotifier( evt );
		return EntityNotificationType.SendThisEventToEntity;
	}

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

	public constexpr function OnQuestForceDetonate( evt : QuestForceDetonate ) : EntityNotificationType
	{
		return EntityNotificationType.SendThisEventToEntity;
	}

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

	public function OnForceDetonate( evt : ForceDetonate ) : EntityNotificationType
	{
		UseNotifier( evt );
		return EntityNotificationType.SendThisEventToEntity;
	}

	protected function ActionQuickHackExplodeExplosive() : QuickHackExplodeExplosive
	{
		var action : QuickHackExplodeExplosive;
		action = new QuickHackExplodeExplosive;
		action.clearanceLevel = DefaultActionsParametersHolder.GetTakeOverControl();
		action.SetUp( this );
		action.SetProperties();
		action.AddDeviceName( m_deviceName );
		action.CreateInteraction();
		return action;
	}

	public function OnQuickHackExplodeExplosive( evt : QuickHackExplodeExplosive ) : EntityNotificationType
	{
		ForceDisableDevice();
		UseNotifier( evt );
		return EntityNotificationType.SendThisEventToEntity;
	}

	protected function ActionQuickHackDistractExplosive() : QuickHackDistractExplosive
	{
		var action : QuickHackDistractExplosive;
		action = new QuickHackDistractExplosive;
		action.clearanceLevel = DefaultActionsParametersHolder.GetTakeOverControl();
		action.SetUp( this );
		action.SetProperties();
		action.AddDeviceName( m_deviceName );
		action.CreateInteraction();
		return action;
	}

	protected override function ActionQuickHackToggleON() : QuickHackToggleON
	{
		var action : QuickHackToggleON;
		action = super.ActionQuickHackToggleON();
		if( IsON() )
		{
			action.CreateInteraction( , , T"Interactions.Disarm" );
		}
		else
		{
			action.CreateInteraction( , , T"Interactions.Arm" );
		}
		return action;
	}

	public override function GetActions( out actions : array< DeviceAction >, context : GetActionsContext ) : Bool
	{
		if( !( super.GetActions( actions, context ) ) )
		{
			return false;
		}
		if( m_provideExplodeAction )
		{
			actions.PushBack( ActionForceDetonate() );
			SetActionIllegality( actions, m_illegalActions.regularActions );
		}
		return true;
	}

	public override function GetQuestActionByName( actionName : CName ) : DeviceAction
	{
		var action : DeviceAction;
		action = super.GetQuestActionByName( actionName );
		if( action == NULL )
		{
			switch( actionName )
			{
				case 'ForceDetonate':
					action = ActionQuestForceDetonate();
				break;
			}
		}
		return action;
	}

	public override function GetQuestActions( out actions : array< DeviceAction >, const context : ref< GetActionsContext > )
	{
		super.GetQuestActions( actions, context );
		actions.PushBack( ActionQuestForceDetonate() );
	}

	protected const override function CanCreateAnyQuickHackActions() : Bool
	{
		if( IsExplosiveWithQhacks() )
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	protected override function GetQuickHackActions( out actions : array< DeviceAction >, const context : ref< GetActionsContext > )
	{
		var currentAction : ScriptableDeviceAction;
		var target : weak< GameObject >;
		target = ( ( GameObject )( GetOwnerEntityWeak() ) );
		super.GetQuickHackActions( actions, context );
		if( !( IsExplosiveWithQhacks() ) )
		{
			return;
		}
		if( ( ( target && !( target.IsTurret() ) ) && IsON() ) && IsDisabledWithQhacks() )
		{
			currentAction = ActionQuickHackToggleON();
			currentAction.SetObjectActionID( T"DeviceAction.ToggleStateClassHack" );
			actions.PushBack( currentAction );
		}
		if( HasNPCWorkspotKillInteraction() && IsSomeoneUsingNPCWorkspot() )
		{
			currentAction = ActionOverloadDevice();
			if( target && !( target.IsTurret() ) )
			{
				currentAction.SetObjectActionID( T"DeviceAction.OverloadClassHack" );
			}
			else
			{
				currentAction.SetObjectActionID( T"DeviceAction.TurretOverloadClassHack" );
			}
			currentAction.SetInactiveWithReason( !( m_wasQuickHacked ) && IsSomeoneUsingNPCWorkspot(), "LocKey#7011" );
			actions.PushBack( currentAction );
		}
		else
		{
			currentAction = ActionQuickHackExplodeExplosive();
			if( target && !( target.IsTurret() ) )
			{
				currentAction.SetObjectActionID( T"DeviceAction.OverloadClassHack" );
			}
			else
			{
				currentAction.SetObjectActionID( T"DeviceAction.TurretOverloadClassHack" );
			}
			actions.PushBack( currentAction );
		}
		FinalizeGetQuickHackActions( actions, context );
	}

	protected override function GetDeviceIconTweakDBID() : TweakDBID
	{
		return T"DeviceIcons.ExplosionDeviceIcon";
	}

	protected override function GetBackgroundTextureTweakDBID() : TweakDBID
	{
		return T"DeviceIcons.ExplosionDeviceBackground";
	}

	public override function OnActionEngineering( evt : ActionEngineering ) : EntityNotificationType
	{
		if( !( evt.WasPassed() ) )
		{
			return EntityNotificationType.DoNotNotifyEntity;
		}
		super.OnActionEngineering( evt );
		if( evt.IsCompleted() )
		{
			if( IsON() && m_doExplosiveEngineerLogic )
			{
				Disarm( evt );
				RPGManager.GiveReward( evt.GetExecutor().GetGame(), T"RPGActionRewards.ExtractPartsSecurityTurret" );
				return EntityNotificationType.SendThisEventToEntity;
			}
		}
		return EntityNotificationType.SendThisEventToEntity;
	}

	protected virtual function Disarm( action : ScriptableDeviceAction )
	{
		var actionToSend : ScriptableDeviceAction;
		actionToSend = ( ( ScriptableDeviceAction )( ActionToggleON() ) );
		actionToSend.RegisterAsRequester( PersistentID.ExtractEntityID( GetID() ) );
		actionToSend.SetExecutor( action.GetExecutor() );
		GetPersistencySystem().QueuePSDeviceEvent( actionToSend );
		SetBlockSecurityWakeUp( true );
		m_disarmed = true;
	}

}

struct ExplosiveDeviceResourceDefinition
{
	[ customEditor = "TweakDBGroupInheritance;Attacks.DeviceAttack" ]
	editable var damageType : TweakDBID;
	var vfxResource : FxResource;
	const editable var vfxEventNamesOnExplosion : array< CName >;
	const editable var vfxResourceOnFirstHit : array< FxResource >;
	editable var executionDelay : Float;
	editable var additionalGameEffectType : EExplosiveAdditionalGameEffectType;
	editable var dontHighlightOnLookat : Bool;
}

class SpiderbotExplodeExplosiveDevice extends ActionBool
{

	public function SetProperties()
	{
		actionName = 'SpiderbotExplodeExplosiveDevice';
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( actionName, true, 'LocKey#389', 'LocKey#389' );
	}

	public override function GetTweakDBChoiceRecord() : String
	{
		return "SpiderbotExplodeExplosiveDevice";
	}

	public constexpr static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		return true;
	}

	public static function IsClearanceValid( clearance : Clearance ) : Bool
	{
		if( Clearance.IsInRange( clearance, DefaultActionsParametersHolder.GetInteractiveClearance() ) )
		{
			return true;
		}
		return false;
	}

	public static function IsContextValid( const context : ref< GetActionsContext > ) : Bool
	{
		if( context.requestType == gamedeviceRequestType.Remote )
		{
			return true;
		}
		return false;
	}

}

class SpiderbotExplodeExplosiveDevicePerformed extends ActionBool
{

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

	public constexpr static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		return true;
	}

	public constexpr static function IsClearanceValid( clearance : Clearance ) : Bool
	{
		return true;
	}

	public constexpr static function IsContextValid( const context : ref< GetActionsContext > ) : Bool
	{
		return true;
	}

}

class SpiderbotDistractExplosiveDevice extends ActionBool
{

	public function SetProperties()
	{
		actionName = 'SpiderbotDistractExplosiveDevice';
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( actionName, true, 'LocKey#390', 'LocKey#390' );
	}

	public override function GetTweakDBChoiceRecord() : String
	{
		return "SpiderbotDistractExplosiveDevice";
	}

	public constexpr static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		return true;
	}

	public static function IsClearanceValid( clearance : Clearance ) : Bool
	{
		if( Clearance.IsInRange( clearance, DefaultActionsParametersHolder.GetInteractiveClearance() ) )
		{
			return true;
		}
		return false;
	}

	public static function IsContextValid( const context : ref< GetActionsContext > ) : Bool
	{
		if( context.requestType == gamedeviceRequestType.Remote )
		{
			return true;
		}
		return false;
	}

}

class SpiderbotDistractExplosiveDevicePerformed extends ActionBool
{

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

	public constexpr static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		return true;
	}

	public constexpr static function IsClearanceValid( clearance : Clearance ) : Bool
	{
		return true;
	}

	public constexpr static function IsContextValid( const context : ref< GetActionsContext > ) : Bool
	{
		return true;
	}

}

class QuestForceDetonate extends ActionBool
{

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

}

class ForceDetonate extends ActionBool
{

	public function SetProperties()
	{
		actionName = 'ForceDetonate';
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'ForceDetonate', true, 'LocKey#17832', 'LocKey#17832' );
	}

}

class QuickHackExplodeExplosive extends ActionBool
{

	public override function GetBaseCost() : Int32
	{
		if( m_isQuickHack )
		{
			return super.GetBaseCost();
		}
		return 0;
	}

	public function SetProperties()
	{
		actionName = 'QuickHackExplodeExplosive';
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'QuickHackExplodeExplosive', true, 'LocKey#1607', 'LocKey#1607' );
	}

}

class QuickHackDistractExplosive extends ActionBool
{

	public override function GetBaseCost() : Int32
	{
		if( m_isQuickHack )
		{
			return super.GetBaseCost();
		}
		return 0;
	}

	public function SetProperties()
	{
		actionName = 'QuickHackDistractExplosive';
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'QuickHackDistractExplosive', true, 'LocKey#375', 'LocKey#375' );
	}

}

enum EExplosiveAdditionalGameEffectType
{
	none = 0,
	EMP = 1,
}

