importonly class PSChangedEvent extends Event
{
}

importonly class PSDeviceChangedEvent extends Event
{
	import var persistentID : PersistentID;
	import var className : CName;
}

import enum gamedeviceRequestType
{
	None,
	External,
	Remote,
	Direct,
	Internal,
}

importonly class DeviceStartPlayerCameraControlEvent extends Event
{
	import var playerController : weak< GameObject >;
	import var initialRotation : Vector4;
	import var minYaw : Float;
	import var maxYaw : Float;
	import var minPitch : Float;
	import var maxPitch : Float;
}

importonly class DeviceEndPlayerCameraControlEvent extends Event
{
}

importonly struct ActionPrereqs
{
	import var actionName : CName;
	import var prereqs : array< IPrereq >;
}

importonly struct GetActionsContext
{
	import var clearance : Clearance;
	import var requestorID : EntityID;
	import var requestType : gamedeviceRequestType;
	import var actionPrereqs : array< ActionPrereqs >;
	import var interactionLayerTag : CName;
	import var processInitiatorObject : weak< GameObject >;
	import var ignoresAuthorization : Bool;
	import var allowsRemoteAuthorization : Bool;
	import var ignoresRPG : Bool;
}

importonly class Clearance extends IScriptable
{
	public import static function IsInRange( clearance : Clearance, clearanceLevel : Int32 ) : Bool;
	public import static function CreateClearance( optional min : Int32, optional max : Int32 ) : Clearance;
	public import static function ReadValues( clearance : Clearance, out min : Int32, out max : Int32 );
	public import static function GetMaxClearanceLevel() : Int32;
	public import static function GetMinClearanceLevel() : Int32;

	import editable var min : Int32;
	import editable var max : Int32;
}

struct ActionInteractivityInfo
{
	var isExternal : Bool;
	var isRemote : Bool;
	var isDirect : Bool;
}

class ResolveActionData
{
	var m_password : String;
}

importonly class DeviceAction extends Event
{
	public import function SetUp( const ps : PersistentState );
	public import export virtual function GetProperties() : array< DeviceActionProperty >;
	public import function GetPersistentID() : PersistentID;
	public import function GetDeviceClassName() : CName;
	public import const virtual function GetCurrentDisplayString() : String;

	import var actionName : CName;
	import var clearanceLevel : Int32;
	import var localizedObjectName : String;
	import var paymentQuantity : Int32;
}

class PerformedAction extends Event
{
	var m_action : DeviceAction;
}

abstract class BaseScriptableAction extends DeviceAction
{
	protected var m_requesterID : EntityID;
	protected var m_executor : weak< GameObject >;
	protected var m_proxyExecutor : weak< GameObject >;
	protected var m_costComponents : array< weak< ObjectActionCost_Record > >;
	protected var m_objectActionID : TweakDBID;
	protected var m_objectActionRecord : weak< ObjectAction_Record >;
	protected var m_inkWidgetID : TweakDBID;
	protected var interactionChoice : InteractionChoice;
	protected var m_interactionLayer : CName;
	protected var m_isActionRPGCheckDissabled : Bool;
	protected var m_canSkipPayCost : Bool;
	protected var m_calculatedBaseCost : Int32;
	var m_deviceActionQueue : DeviceActionQueue;
	var m_isActionQueueingUsed : Bool;
	var m_isQueuedAction : Bool;
	var m_isInactive : Bool;
	var m_isTargetDead : Bool;
	var m_activationTimeReduction : Float;
	var m_IsAppliedByMonowire : Bool;

	protected virtual function GetOwnerPS( game : GameInstance ) : PersistentState
	{
		var psID : PersistentID;
		psID = GetPersistentID();
		if( PersistentID.IsDefined( psID ) )
		{
			return GameInstance.GetPersistencySystem( game ).GetConstAccessToPSObject( psID, GetDeviceClassName() );
		}
		else
		{
			return NULL;
		}
	}

	public function RegisterAsRequester( id : EntityID )
	{
		m_requesterID = id;
	}

	public function GetRequesterID() : EntityID
	{
		return m_requesterID;
	}

	public function SetExecutor( executor : weak< GameObject > )
	{
		m_executor = executor;
	}

	public const function GetExecutor() : weak< GameObject >
	{
		return m_executor;
	}

	public function SetProxyExecutor( proxy : weak< GameObject > )
	{
		m_proxyExecutor = proxy;
	}

	public const function GetProxyExecutor() : weak< GameObject >
	{
		return m_proxyExecutor;
	}

	public const function GetDeviceActionQueue() : weak< DeviceActionQueue >
	{
		return m_deviceActionQueue;
	}

	public const function GetDeviceActionQueueSize() : Int32
	{
		if( m_deviceActionQueue )
		{
			return m_deviceActionQueue.GetQueueSize();
		}
		else
		{
			return 0;
		}
	}

	public const function GetDeviceActionMaxQueueSize() : Int32
	{
		if( m_deviceActionQueue )
		{
			return m_deviceActionQueue.GetMaxQueueSize();
		}
		else
		{
			return 1;
		}
	}

	public const function GetDeviceActionQueueNames() : array< CName >
	{
		var actionNames : array< CName >;
		m_deviceActionQueue.GetAllQueuedActionNames( actionNames );
		return actionNames;
	}

	public const function IsFirstUniqueCategoryInQueue( targetID : EntityID, category : gamedataHackCategory ) : Bool
	{
		var targetPuppet : ScriptedPuppet;
		var currentlyUploadingAction : weak< ScriptableDeviceAction >;
		var objectActionRecords : array< ObjectAction_Record >;
		var deviceActionQueue : weak< DeviceActionQueue >;
		var hackCategory : gamedataHackCategory;
		var isNewCategory : Bool;
		var i : Int32;
		targetPuppet = ( ( ScriptedPuppet )( GameInstance.FindEntityByID( GetExecutor().GetGame(), targetID ) ) );
		isNewCategory = true;
		if( !( targetPuppet ) )
		{
			return false;
		}
		currentlyUploadingAction = targetPuppet.GetCurrentlyUploadingAction();
		if( ( currentlyUploadingAction == NULL ) || currentlyUploadingAction.m_isInactive )
		{
			return false;
		}
		hackCategory = currentlyUploadingAction.GetObjectActionRecord().HackCategory().Type();
		if( hackCategory == category )
		{
			return false;
		}
		deviceActionQueue = currentlyUploadingAction.GetDeviceActionQueue();
		if( deviceActionQueue )
		{
			deviceActionQueue.GetAllQueuedActionObjectRecords( objectActionRecords );
			for( i = 0; i < objectActionRecords.Size(); i += 1 )
			{
				hackCategory = objectActionRecords[ i ].HackCategory().Type();
				if( hackCategory == category )
				{
					isNewCategory = false;
					break;
				}
			}
		}
		return isNewCategory;
	}

	public const function GetActionID() : CName
	{
		var id : CName;
		if( TDBID.IsValid( GetObjectActionID() ) )
		{
			id = GetObjectActionRecord().ActionName();
		}
		else if( GetClassName() != actionName )
		{
			id = actionName;
		}
		else
		{
			id = GetClassName();
		}
		return id;
	}

	public const virtual function GetObjectActionRecord() : weak< ObjectAction_Record >
	{
		if( m_objectActionRecord )
		{
			return m_objectActionRecord;
		}
		return TweakDBInterface.GetObjectActionRecord( m_objectActionID );
	}

	public const virtual function GetObjectActionID() : TweakDBID
	{
		var record : weak< ObjectAction_Record >;
		var tweakDBID : TweakDBID;
		record = GetObjectActionRecord();
		if( record )
		{
			tweakDBID = record.GetID();
		}
		return tweakDBID;
	}

	public const function GetGameplayCategoryID() : TweakDBID
	{
		var record : weak< ObjectAction_Record >;
		var returnValue : TweakDBID;
		record = GetObjectActionRecord();
		if( record && GetObjectActionRecord().GameplayCategory() )
		{
			returnValue = GetObjectActionRecord().GameplayCategory().GetID();
		}
		return returnValue;
	}

	public const function GetGameplayCategoryRecord() : weak< ObjectActionGameplayCategory_Record >
	{
		var record : weak< ObjectAction_Record >;
		var returnValue : weak< ObjectActionGameplayCategory_Record >;
		record = GetObjectActionRecord();
		if( record )
		{
			returnValue = GetObjectActionRecord().GameplayCategory();
		}
		return returnValue;
	}

	public virtual function SetObjectActionID( id : TweakDBID )
	{
		m_objectActionID = id;
		m_objectActionRecord = NULL;
		m_objectActionRecord = GetObjectActionRecord();
		m_costComponents.Clear();
		if( m_objectActionRecord )
		{
			actionName = m_objectActionRecord.ActionName();
		}
		ProduceInteractionPart();
	}

	public virtual function GetTweakDBChoiceRecord() : String
	{
		var recordName : String;
		if( ( GetObjectActionRecord() && GetObjectActionRecord().ObjectActionUI() ) && TDBID.IsValid( m_objectActionID ) )
		{
			recordName = GetObjectActionRecord().ObjectActionUI().Name();
		}
		if( IsStringValid( recordName ) )
		{
			return recordName;
		}
		else
		{
			return NameToString( actionName );
		}
	}

	public virtual function GetTweakDBChoiceID() : TweakDBID
	{
		var id : TweakDBID;
		return id;
	}

	public function SetIsActionRPGCheckDissabled( value : Bool )
	{
		if( value && IsInactive() )
		{
			SetActive();
		}
		m_isActionRPGCheckDissabled = value;
	}

	public const function GetIsActionRPGCheckDissabled() : Bool
	{
		return m_isActionRPGCheckDissabled;
	}

	public function SetInactive()
	{
		if( !( GetIsActionRPGCheckDissabled() ) )
		{
			ChoiceTypeWrapper.SetType( interactionChoice.choiceMetaData.type, gameinteractionsChoiceType.Inactive );
		}
	}

	public function SetActive()
	{
		ChoiceTypeWrapper.ClearType( interactionChoice.choiceMetaData.type, gameinteractionsChoiceType.Inactive );
	}

	public const function IsInactive() : Bool
	{
		return ChoiceTypeWrapper.IsType( interactionChoice.choiceMetaData.type, gameinteractionsChoiceType.Inactive );
	}

	public const function IsInteractionChoiceValid() : Bool
	{
		if( !( IsStringValid( interactionChoice.choiceMetaData.tweakDBName ) ) && !( TDBID.IsValid( interactionChoice.choiceMetaData.tweakDBID ) ) )
		{
			return false;
		}
		else
		{
			return true;
		}
	}

	protected function ProduceInteractionPart()
	{
		var costPart : InteractionChoiceCaptionQuickhackCostPart;
		var cost : Int32;
		interactionChoice.choiceMetaData.tweakDBName = GetTweakDBChoiceRecord();
		if( !( IsInteractionChoiceValid() ) )
		{
			return;
		}
		InteractionChoiceCaption.Clear( interactionChoice.captionParts );
		if( GetObjectActionRecord() && GetObjectActionRecord().ObjectActionUI() )
		{
			InteractionChoiceCaption.AddPartFromRecord( interactionChoice.captionParts, GetObjectActionRecord().ObjectActionUI().CaptionIcon() );
		}
		cost = GetCost();
		if( cost > 0 )
		{
			costPart = new InteractionChoiceCaptionQuickhackCostPart;
			costPart.cost = cost;
			InteractionChoiceCaption.AddScriptPart( interactionChoice.captionParts, costPart );
		}
		ChoiceTypeWrapper.SetType( interactionChoice.choiceMetaData.type, gameinteractionsChoiceType.CheckSuccess );
	}

	public virtual function IsPossible( target : weak< GameObject >, optional actionRecord : weak< ObjectAction_Record >, optional objectActionsCallbackController : weak< gameObjectActionsCallbackController > ) : Bool
	{
		var targetPrereqs : array< weak< IPrereq_Record > >;
		if( !( actionRecord ) )
		{
			actionRecord = GetObjectActionRecord();
		}
		if( objectActionsCallbackController && objectActionsCallbackController.HasObjectAction( actionRecord ) )
		{
			return objectActionsCallbackController.IsObjectActionTargetPrereqFulfilled( actionRecord );
		}
		else
		{
			actionRecord.TargetPrereqs( targetPrereqs );
			return RPGManager.CheckPrereqs( targetPrereqs, target );
		}
	}

	public virtual function CanInterrupt( target : weak< GameObject >, optional actionRecord : weak< ObjectAction_Record > ) : Bool
	{
		var interruptionPrereqs : array< weak< IPrereq_Record > >;
		if( !( actionRecord ) )
		{
			actionRecord = GetObjectActionRecord();
		}
		actionRecord.InterruptionPrereqs( interruptionPrereqs );
		return RPGManager.CheckPrereqs( interruptionPrereqs, target );
	}

	public virtual function IsVisible( const context : ref< GetActionsContext >, optional objectActionsCallbackController : weak< gameObjectActionsCallbackController > ) : Bool
	{
		var actionRecord : weak< ObjectAction_Record >;
		var instigatorPrereqs : array< weak< IPrereq_Record > >;
		if( !( IsNameValid( context.interactionLayerTag ) ) )
		{
			return false;
		}
		actionRecord = GetObjectActionRecord();
		if( actionRecord.InteractionLayer() == 'any' || context.interactionLayerTag == actionRecord.InteractionLayer() )
		{
			if( objectActionsCallbackController && objectActionsCallbackController.HasObjectAction( actionRecord ) )
			{
				return objectActionsCallbackController.IsObjectActionInstigatorPrereqFulfilled( actionRecord );
			}
			else
			{
				actionRecord.InstigatorPrereqs( instigatorPrereqs );
				return RPGManager.CheckPrereqs( instigatorPrereqs, context.processInitiatorObject );
			}
		}
		else
		{
			return false;
		}
	}

	public virtual function IsVisible( player : weak< GameObject >, optional objectActionsCallbackController : weak< gameObjectActionsCallbackController > ) : Bool
	{
		var actionRecord : weak< ObjectAction_Record >;
		var instigatorPrereqs : array< weak< IPrereq_Record > >;
		actionRecord = GetObjectActionRecord();
		if( objectActionsCallbackController && objectActionsCallbackController.HasObjectAction( actionRecord ) )
		{
			return objectActionsCallbackController.IsObjectActionInstigatorPrereqFulfilled( actionRecord );
		}
		else
		{
			actionRecord.InstigatorPrereqs( instigatorPrereqs );
			return RPGManager.CheckPrereqs( instigatorPrereqs, player );
		}
		return false;
	}

	public virtual function ProcessRPGAction( gameInstance : GameInstance, optional gameplayRoleComponent : GameplayRoleComponent )
	{
		SetProxyExecutor( GetExecutor().TryGetControlledProxy() );
		if( GetActivationTime() > 0.0 )
		{
			if( PutActionInQuickhackQueue( gameInstance, gameplayRoleComponent ) )
			{
				return;
			}
		}
		if( CanSkipPayCost( false ) || PayCost( true ) )
		{
			StartAction( gameInstance );
			if( GetActivationTime() > 0.0 )
			{
				StartUpload( gameInstance );
			}
			else
			{
				CompleteAction( gameInstance );
			}
			m_calculatedBaseCost = GetBaseCost();
		}
	}

	public virtual function StartAction( gameInstance : GameInstance )
	{
		var actionEffects : array< weak< ObjectActionEffect_Record > >;
		var player : PlayerPuppet;
		var objectActionRecord : ObjectAction_Record;
		objectActionRecord = GetObjectActionRecord();
		if( objectActionRecord )
		{
			objectActionRecord.StartEffects( actionEffects );
		}
		ProcessStatusEffects( actionEffects, gameInstance );
		ProcessEffectors( actionEffects, gameInstance );
		if( ( objectActionRecord && objectActionRecord.Cooldown() ) && GetExecutor() )
		{
			if( TDBID.IsValid( objectActionRecord.Cooldown().GetID() ) && GetExecutor().IsPlayer() )
			{
				player = ( ( PlayerPuppet )( GetExecutor() ) );
				if( player )
				{
					player.GetCooldownStorage().StartSimpleCooldown( this );
				}
			}
		}
	}

	public virtual function CompleteAction( gameInstance : GameInstance )
	{
		var i : Int32;
		var rewards : array< weak< RewardBase_Record > >;
		var actionEffects : array< weak< ObjectActionEffect_Record > >;
		var actionRecord : ObjectAction_Record;
		actionRecord = GetObjectActionRecord();
		if( actionRecord )
		{
			actionRecord.Rewards( rewards );
		}
		for( i = 0; i < rewards.Size(); i += 1 )
		{
			RPGManager.GiveReward( gameInstance, rewards[ i ].GetID(), GetRequesterID() );
		}
		if( actionRecord )
		{
			actionRecord.CompletionEffects( actionEffects );
			if( actionRecord.HackCategory().Type() != gamedataHackCategory.NotAHack )
			{
				RPGManager.AwardExperienceFromQuickhack( ( ( PlayerPuppet )( GetExecutor() ) ), ( ( Float )( m_calculatedBaseCost ) ), m_requesterID, actionRecord.HackCategory().Type() );
			}
		}
		ProcessStatusEffects( actionEffects, gameInstance );
		ProcessEffectors( actionEffects, gameInstance );
	}

	private virtual function StartUpload( gameInstance : GameInstance )
	{
		return;
	}

	private function PutActionInQuickhackQueue( gameInstance : GameInstance, gameplayRoleComponent : GameplayRoleComponent ) : Bool
	{
		var isActionQueued : Bool;
		var sAction : ScriptableDeviceAction;
		var requesterObject : GameObject;
		var slotName : CName;
		isActionQueued = false;
		sAction = ( ( ScriptableDeviceAction )( this ) );
		if( sAction && sAction.IsQuickHack() )
		{
			requesterObject = ( ( GameObject )( GameInstance.FindEntityByID( gameInstance, m_requesterID ) ) );
			if( requesterObject )
			{
				slotName = GetExecutor().GetQuickHackIndicatorSlotName();
				isActionQueued = QuickHackableQueueHelper.PutActionInQuickhackQueue( sAction, gameplayRoleComponent, gameInstance, slotName, requesterObject );
			}
			if( !( sAction.m_isQueuedAction ) && sAction.GetExecutor().IsPlayer() )
			{
				RPGManager.IncrementQuickHackBlackboard( gameInstance, sAction.GetObjectActionID() );
			}
		}
		return isActionQueued;
	}

	protected virtual function ProcessStatusEffects( const actionEffects : ref< array< weak< ObjectActionEffect_Record > > >, gameInstance : GameInstance )
	{
		var i : Int32;
		var instigator : GameObject;
		var proxy : GameObject;
		var proxyId : EntityID;
		instigator = GetExecutor();
		proxy = GetProxyExecutor();
		if( proxy )
		{
			proxyId = proxy.GetEntityID();
		}
		for( i = 0; i < actionEffects.Size(); i += 1 )
		{
			switch( actionEffects[ i ].Recipient().Type() )
			{
				case gamedataObjectActionReference.Instigator:
					ResetStatusEffectIfActionIsQueued( instigator.GetEntityID(), actionEffects[ i ].StatusEffect(), gameInstance );
				StatusEffectHelper.ApplyStatusEffect( instigator, actionEffects[ i ].StatusEffect().GetID(), instigator.GetEntityID(), proxyId );
				break;
				case gamedataObjectActionReference.Target:
					ResetStatusEffectIfActionIsQueued( m_requesterID, actionEffects[ i ].StatusEffect(), gameInstance );
				GameInstance.GetStatusEffectSystem( gameInstance ).ApplyStatusEffect( m_requesterID, actionEffects[ i ].StatusEffect().GetID(), GameObject.GetTDBID( instigator ), instigator.GetEntityID(), 1, Vector4( 0.0, 0.0, 0.0, 0.0 ), true, proxyId );
				break;
				case gamedataObjectActionReference.Source:
					break;
			}
		}
	}

	protected function ProcessEffectors( const actionEffects : ref< array< weak< ObjectActionEffect_Record > > >, gameInstance : GameInstance )
	{
		var i : Int32;
		var instigator : GameObject;
		var proxy : GameObject;
		var proxyId : EntityID;
		instigator = GetExecutor();
		proxy = GetProxyExecutor();
		if( proxy )
		{
			proxyId = proxy.GetEntityID();
		}
		for( i = 0; i < actionEffects.Size(); i += 1 )
		{
			switch( actionEffects[ i ].Recipient().Type() )
			{
				case gamedataObjectActionReference.Instigator:
					GameInstance.GetEffectorSystem( gameInstance ).ApplyEffector( GetExecutor().GetEntityID(), instigator, actionEffects[ i ].EffectorToTrigger().GetID(), TDBID.None(), proxyId );
				break;
				case gamedataObjectActionReference.Target:
					GameInstance.GetEffectorSystem( gameInstance ).ApplyEffector( m_requesterID, instigator, actionEffects[ i ].EffectorToTrigger().GetID(), TDBID.None(), proxyId );
				break;
				case gamedataObjectActionReference.Source:
					break;
			}
		}
	}

	protected function ResetStatusEffectIfActionIsQueued( entityID : EntityID, statusEffectRecord : StatusEffect_Record, gameInstance : GameInstance )
	{
		if( m_isActionQueueingUsed && !( QuickHackableQueueHelper.IsStatusEffectStackable( statusEffectRecord ) ) )
		{
			GameInstance.GetStatusEffectSystem( gameInstance ).RemoveStatusEffect( entityID, statusEffectRecord.GetID() );
		}
	}

	public virtual function GetActivationTime() : Float
	{
		var timeMods : array< weak< StatModifier_Record > >;
		var uploadTime : Float;
		var executor : GameObject;
		if( GetObjectActionRecord() )
		{
			GetObjectActionRecord().ActivationTime( timeMods );
		}
		executor = GetExecutor();
		if( executor && ( timeMods.Size() > 0 ) )
		{
			if( executor.IsPlayer() && ( timeMods.Size() > 1 ) )
			{
				uploadTime = RPGManager.CalculateStatModifiers( GameInstance.GetStatsDataSystem( GetExecutor().GetGame() ).GetValueFromCurve( 'puppet_dynamic_scaling', GetPowerLevelDiff(), 'pl_diff_to_upload_time_modifier' ), 1.0, 0.0, timeMods, executor.GetGame(), executor, GetRequesterID(), executor.GetEntityID() );
			}
			else
			{
				uploadTime = RPGManager.CalculateStatModifiers( timeMods, executor.GetGame(), executor, GetRequesterID(), executor.GetEntityID() );
			}
		}
		if( ( m_activationTimeReduction > 0.0 ) && ( m_activationTimeReduction < 1.0 ) )
		{
			uploadTime -= ( uploadTime * m_activationTimeReduction );
		}
		return uploadTime;
	}

	public function GetCooldownDuration() : Float
	{
		if( GetObjectActionRecord() )
		{
			return GetObjectActionRecord().Cooldown().Duration();
		}
		return 0.0;
	}

	public function IsEyesInTheSkyPerk() : Bool
	{
		var hackCategory : gamedataHackCategory;
		var playerPuppet : PlayerPuppet;
		var playerBlackboard : IBlackboard;
		var isControlling : Bool;
		var isCategory : Bool;
		var isPerk : Bool;
		isControlling = false;
		isCategory = false;
		isPerk = false;
		playerPuppet = ( ( PlayerPuppet )( GetPlayer( GetExecutor().GetGame() ) ) );
		if( !( playerPuppet ) )
		{
			return false;
		}
		hackCategory = GetObjectActionRecord().HackCategory().Type();
		playerBlackboard = GameInstance.GetBlackboardSystem( GetExecutor().GetGame() ).GetLocalInstanced( playerPuppet.GetEntityID(), GetAllBlackboardDefs().PlayerStateMachine );
		isCategory = ( hackCategory == gamedataHackCategory.CovertHack || hackCategory == gamedataHackCategory.ControlHack ) || hackCategory == gamedataHackCategory.DeviceHack;
		isControlling = playerBlackboard.GetBool( GetAllBlackboardDefs().PlayerStateMachine.IsControllingDevice );
		isPerk = PlayerDevelopmentSystem.GetData( GetExecutor() ).IsNewPerkBought( gamedataNewPerkType.Intelligence_Left_Milestone_1 );
		return ( isCategory && isControlling ) && isPerk;
	}

	public function GetModifiedDurationTime( baseValue : Float ) : Float
	{
		if( IsEyesInTheSkyPerk() )
		{
			return baseValue + ( baseValue * TDB.GetFloat( T"NewPerks.Intelligence_Left_Milestone_1.durationIncease", 0.0 ) );
		}
		return baseValue;
	}

	public virtual function GetDurationTime() : Float
	{
		var timeMods : array< weak< StatModifier_Record > >;
		var durationTime : Float;
		var executor : GameObject;
		if( GetObjectActionRecord() )
		{
			GetObjectActionRecord().DurationTime( timeMods );
		}
		executor = GetExecutor();
		if( executor && ( timeMods.Size() > 0 ) )
		{
			durationTime = RPGManager.CalculateStatModifiers( timeMods, executor.GetGame(), executor, GetRequesterID(), executor.GetEntityID() );
		}
		return GetModifiedDurationTime( durationTime );
	}

	public function CanPayCost( optional user : GameObject, optional checkForOverclockedState : Bool ) : Bool
	{
		var statPoolSys : StatPoolsSystem;
		var transactionSys : TransactionSystem;
		var i : Int32;
		var statPoolCost : weak< StatPoolCost_Record >;
		var itemCost : weak< ItemCost_Record >;
		var quantity : Int32;
		var statPoolType : gamedataStatPoolType;
		var executorQuantity : Int32;
		var executor : GameObject;
		var overclockIsActivated : Bool;
		if( user )
		{
			executor = user;
		}
		else
		{
			executor = GetExecutor();
		}
		if( m_costComponents.Size() == 0 )
		{
			GetObjectActionRecord().Costs( m_costComponents );
		}
		for( i = 0; i < m_costComponents.Size(); i += 1 )
		{
			quantity = GetCost();
			itemCost = ( ( ItemCost_Record )( m_costComponents[ i ] ) );
			statPoolCost = ( ( StatPoolCost_Record )( m_costComponents[ i ] ) );
			if( itemCost )
			{
				transactionSys = GameInstance.GetTransactionSystem( executor.GetGame() );
				executorQuantity = transactionSys.GetItemQuantity( executor, ItemID.CreateQuery( itemCost.Item().GetID() ) );
			}
			else if( statPoolCost )
			{
				statPoolSys = GameInstance.GetStatPoolsSystem( executor.GetGame() );
				statPoolType = statPoolCost.StatPool().StatPoolType();
				executorQuantity = FloorF( statPoolSys.GetStatPoolValue( executor.GetEntityID(), statPoolType, false ) );
			}
			if( executorQuantity < quantity )
			{
				overclockIsActivated = QuickHackableHelper.IsOverclockedStateActive( GetExecutor() );
				if( checkForOverclockedState && overclockIsActivated )
				{
					if( !( QuickHackableHelper.CanPayWithHealthInOverclockedState( GetExecutor(), quantity, 0.0 ) ) )
					{
						return false;
					}
				}
				else
				{
					return false;
				}
			}
		}
		return true;
	}

	public function CanSkipPayCost( isJustConsulting : Bool ) : Bool
	{
		var playerPuppet : PlayerPuppet;
		var playerBlackboard : IBlackboard;
		var playerFreeCostActionIDName : TweakDBID;
		var amountOfFreeSimultaneousActions : Int32;
		if( m_canSkipPayCost )
		{
			return true;
		}
		playerPuppet = ( ( PlayerPuppet )( GetExecutor() ) );
		if( !( playerPuppet ) )
		{
			return false;
		}
		playerBlackboard = GameInstance.GetBlackboardSystem( playerPuppet.GetGame() ).GetLocalInstanced( playerPuppet.GetEntityID(), GetAllBlackboardDefs().PlayerStateMachine );
		playerFreeCostActionIDName = ( ( TweakDBID )( playerBlackboard.GetVariant( GetAllBlackboardDefs().PlayerStateMachine.CostFreeActionID ) ) );
		amountOfFreeSimultaneousActions = playerBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.AmountOfCostFreeActions );
		if( GetObjectActionID() == playerFreeCostActionIDName )
		{
			if( amountOfFreeSimultaneousActions > 0 )
			{
				amountOfFreeSimultaneousActions -= 1;
				playerBlackboard.SetInt( GetAllBlackboardDefs().PlayerStateMachine.AmountOfCostFreeActions, amountOfFreeSimultaneousActions );
				if( amountOfFreeSimultaneousActions > 0 )
				{
					return true;
				}
			}
			if( !( isJustConsulting ) )
			{
				playerBlackboard.SetVariant( GetAllBlackboardDefs().PlayerStateMachine.CostFreeActionID, TDBID.None() );
			}
			return true;
		}
		return false;
	}

	public virtual function PayCost( optional checkForOverclockedState : Bool ) : Bool
	{
		var statPoolSys : StatPoolsSystem;
		var transactionSys : TransactionSystem;
		var currValue : Float;
		var newValue : Float;
		var statPoolCost : weak< StatPoolCost_Record >;
		var itemCost : weak< ItemCost_Record >;
		var quantity : Int32;
		var statPoolType : gamedataStatPoolType;
		var executorQuantity : Int32;
		var overclockIsActivated : Bool;
		if( GetObjectActionRecord() )
		{
			if( m_costComponents.Size() == 0 )
			{
				GetObjectActionRecord().Costs( m_costComponents );
			}
		}
		if( m_costComponents[ 0 ] )
		{
			quantity = GetCost();
			this.paymentQuantity = quantity;
			itemCost = ( ( ItemCost_Record )( m_costComponents[ 0 ] ) );
			statPoolCost = ( ( StatPoolCost_Record )( m_costComponents[ 0 ] ) );
			overclockIsActivated = QuickHackableHelper.IsOverclockedStateActive( GetExecutor() );
			if( itemCost )
			{
				transactionSys = GameInstance.GetTransactionSystem( GetExecutor().GetGame() );
				executorQuantity = transactionSys.GetItemQuantity( GetExecutor(), ItemID.CreateQuery( itemCost.Item().GetID() ) );
				if( executorQuantity < quantity )
				{
					if( checkForOverclockedState && overclockIsActivated )
					{
						return QuickHackableHelper.PayWithHealthInOverclockedState( GetExecutor(), quantity );
					}
					else
					{
						return false;
					}
				}
				transactionSys.RemoveItem( GetExecutor(), ItemID.CreateQuery( itemCost.Item().GetID() ), quantity );
			}
			else if( statPoolCost )
			{
				statPoolSys = GameInstance.GetStatPoolsSystem( GetExecutor().GetGame() );
				statPoolType = statPoolCost.StatPool().StatPoolType();
				currValue = statPoolSys.GetStatPoolValue( GetExecutor().GetEntityID(), statPoolType, false );
				newValue = currValue - ( ( Float )( quantity ) );
				if( newValue < 0.0 )
				{
					if( checkForOverclockedState && overclockIsActivated )
					{
						return QuickHackableHelper.PayWithHealthInOverclockedState( GetExecutor(), quantity );
					}
					else
					{
						return false;
					}
				}
				statPoolSys.RequestSettingStatPoolValue( GetExecutor().GetEntityID(), statPoolType, newValue, GetExecutor(), false );
			}
			GameObject.PlaySoundEvent( GetExecutor(), 'ui_focus_mode_quickhack' );
			return true;
		}
		return true;
	}

	public virtual function GetCost() : Int32
	{
		var costMods : array< weak< StatModifier_Record > >;
		var targetID : EntityID;
		var targetPuppet : ScriptedPuppet;
		var statPoolCost : StatPoolCost_Record;
		var cost, extraCost : Float;
		var availableMemory : Float;
		var stacks : Uint32;
		var device : ScriptableDeviceComponentPS;
		var hackCategory : gamedataHackCategory;
		var statsDataSystem : StatsDataSystem;
		var currentlyUploadingAction : weak< ScriptableDeviceAction >;
		var deviceActionQueue : weak< DeviceActionQueue >;
		var objectActionRecords : array< ObjectAction_Record >;
		var targetPos : Vector4;
		var instigatorPos : Vector4;
		var distance : Float;
		var hackID : TweakDBID;
		var shouldReduceCost : Bool;
		var i : Int32;
		hackID = GetObjectActionRecord().GetID();
		if( GetExecutor() && ( GetObjectActionRecord().GetCostsCount() > 0 ) )
		{
			device = ( ( ScriptableDeviceComponentPS )( GetOwnerPS( GetExecutor().GetGame() ) ) );
			if( ( device && ( GetObjectActionID() == T"DeviceAction.TakeControlCameraClassHack" ) ) && device.WasActionPerformed( GetActionID(), EActionContext.QHack ) )
			{
				return 0;
			}
			else
			{
				if( m_costComponents.Size() == 0 )
				{
					GetObjectActionRecord().Costs( m_costComponents );
				}
				if( m_costComponents[ 0 ] )
				{
					GetCostMods( m_costComponents, costMods );
					if( EntityID.IsDefined( GetRequesterID() ) )
					{
						targetID = GetRequesterID();
					}
					else
					{
						targetID = PersistentID.ExtractEntityID( GetPersistentID() );
					}
					cost = RPGManager.CalculateStatModifiers( costMods, GetExecutor().GetGame(), GetExecutor(), targetID, GetExecutor().GetEntityID() );
					statPoolCost = ( ( StatPoolCost_Record )( m_costComponents[ 0 ] ) );
					if( statPoolCost.StatPool().StatPoolType() == gamedataStatPoolType.Memory )
					{
						hackCategory = GetObjectActionRecord().HackCategory().Type();
						if( hackCategory == gamedataHackCategory.VehicleHack )
						{
							if( GetObjectActionID() == T"DeviceAction.TakeControlVehicleClassHack" )
							{
								cost *= GameInstance.GetStatsDataSystem( GetExecutor().GetGame() ).GetValueFromCurve( 'puppet_dynamic_scaling', GetExecutorLevel(), 'vehicle_quickhack_remotecontrol_memory_cost_multiplier' );
							}
							else if( GetObjectActionID() == T"DeviceAction.VehicleForceBrakesClassHack" )
							{
								cost *= GameInstance.GetStatsDataSystem( GetExecutor().GetGame() ).GetValueFromCurve( 'puppet_dynamic_scaling', GetExecutorLevel(), 'vehicle_quickhack_forcebrakes_memory_cost_multiplier' );
							}
							else if( GetObjectActionID() == T"DeviceAction.VehicleExplodeClassHack" )
							{
								cost *= GameInstance.GetStatsDataSystem( GetExecutor().GetGame() ).GetValueFromCurve( 'puppet_dynamic_scaling', GetExecutorLevel(), 'vehicle_quickhack_explode_memory_cost_multiplier' );
							}
							else if( GetObjectActionID() == T"DeviceAction.VehicleAccelerateClassHack" )
							{
								cost *= GameInstance.GetStatsDataSystem( GetExecutor().GetGame() ).GetValueFromCurve( 'puppet_dynamic_scaling', GetExecutorLevel(), 'vehicle_quickhack_accelerate_memory_cost_multiplier' );
							}
						}
						else
						{
							extraCost = GameInstance.GetStatsDataSystem( GetExecutor().GetGame() ).GetValueFromCurve( 'puppet_dynamic_scaling', GetPowerLevelDiff(), 'pl_diff_to_memory_cost_modifier' );
							cost += extraCost;
							if( hackCategory == gamedataHackCategory.UltimateHack )
							{
								cost += extraCost;
							}
						}
						if( PlayerDevelopmentSystem.GetData( GetExecutor() ).IsNewPerkBought( gamedataNewPerkType.Intelligence_Left_Perk_3_1 ) && IsFirstUniqueCategoryInQueue( targetID, hackCategory ) )
						{
							cost -= GameInstance.GetStatsSystem( GetExecutor().GetGame() ).GetStatValue( GetExecutor().GetEntityID(), gamedataStatType.FirstHackOfTypeInQueueRAMDecrease );
						}
						if( hackCategory == gamedataHackCategory.DamageHack && PlayerDevelopmentSystem.GetData( GetExecutor() ).IsNewPerkBought( gamedataNewPerkType.Intelligence_Central_Perk_2_2 ) )
						{
							shouldReduceCost = false;
							if( ( GameInstance.GetStatusEffectSystem( GetExecutor().GetGame() ).HasStatusEffectWithTag( targetID, 'CovertQuickhacked' ) || GameInstance.GetStatusEffectSystem( GetExecutor().GetGame() ).HasStatusEffectWithTag( targetID, 'ControlQuickhacked' ) ) || GameInstance.GetStatusEffectSystem( GetExecutor().GetGame() ).HasStatusEffect( targetID, T"BaseStatusEffect.DistractionDuration" ) )
							{
								shouldReduceCost = true;
							}
							if( !( shouldReduceCost ) )
							{
								targetPuppet = ( ( ScriptedPuppet )( GameInstance.FindEntityByID( GetExecutor().GetGame(), targetID ) ) );
								if( targetPuppet )
								{
									currentlyUploadingAction = targetPuppet.GetCurrentlyUploadingAction();
									if( currentlyUploadingAction.GetObjectActionRecord().HackCategory().Type() == gamedataHackCategory.CovertHack || currentlyUploadingAction.GetObjectActionRecord().HackCategory().Type() == gamedataHackCategory.ControlHack )
									{
										shouldReduceCost = true;
									}
									deviceActionQueue = currentlyUploadingAction.GetDeviceActionQueue();
									deviceActionQueue.GetAllQueuedActionObjectRecords( objectActionRecords );
									for( i = 0; i < objectActionRecords.Size(); i += 1 )
									{
										if( objectActionRecords[ i ].HackCategory().Type() == gamedataHackCategory.CovertHack || objectActionRecords[ i ].HackCategory().Type() == gamedataHackCategory.ControlHack )
										{
											shouldReduceCost = true;
											break;
										}
									}
								}
							}
							if( shouldReduceCost )
							{
								cost -= TDB.GetFloat( T"NewPerks.Intelligence_Central_Perk_2_2.memoryCostReduction", 0.0 );
							}
						}
						if( IsEyesInTheSkyPerk() )
						{
							cost -= TDB.GetFloat( T"NewPerks.Intelligence_Left_Milestone_1.memoryCostReduction", 0.0 );
						}
						if( PlayerDevelopmentSystem.GetData( GetExecutor() ).IsNewPerkBought( gamedataNewPerkType.Intelligence_Master_Perk_1 ) )
						{
							targetPuppet = ( ( ScriptedPuppet )( GameInstance.FindEntityByID( GetExecutor().GetGame(), targetID ) ) );
							if( ( targetPuppet && targetPuppet.CanNewActionBeQueued() ) && ( targetPuppet.GetDeviceActionQueueSize() >= ( targetPuppet.GetDeviceActionMaxQueueSize() - 1 ) ) )
							{
								cost *= ( 1.0 - TDB.GetFloat( T"NewPerks.Intelligence_Master_Perk_1.memoryCostReduction", 0.0 ) );
							}
						}
						if( ( GameInstance.GetStatPoolsSystem( GetExecutor().GetGame() ).GetStatPoolValue( GetExecutor().GetEntityID(), gamedataStatPoolType.QuickHackUpload, true ) > 0.0 ) && ( GameInstance.GetStatsSystem( GetExecutor().GetGame() ).GetStatValue( targetID, gamedataStatType.IsNetrunnerArchetype ) > 0.0 ) )
						{
							if( GameInstance.GetStatsSystem( GetExecutor().GetGame() ).GetStatValue( targetID, gamedataStatType.RevealNetrunnerWhenHacked ) > 0.0 )
							{
								if( PlayerDevelopmentSystem.GetData( GetExecutor() ).IsNewPerkBought( gamedataNewPerkType.Intelligence_Left_Perk_2_1 ) )
								{
									cost -= TDB.GetFloat( T"NewPerks.Intelligence_Left_Perk_2_1.memoryCostReduction", 0.0 );
								}
							}
						}
						if( ( ( ( hackID == T"QuickHack.MadnessLvl3Hack" ) || ( hackID == T"QuickHack.MadnessLvl4Hack" ) ) || ( hackID == T"QuickHack.MadnessLvl4PlusPlusHack" ) ) || ( hackID == T"QuickHack.MadnessSetFriendlyHack" ) )
						{
							cost -= GetMadnessLvl3ProgramCostReduction( targetID );
						}
						if( ( hackID == T"QuickHack.BrainMeltLvl3Hack" ) || ( hackID == T"QuickHack.BrainMeltLvl4Hack" ) )
						{
							stacks = StatusEffectHelper.GetStatusEffectByID( GetPlayer( GetExecutor().GetGame() ), T"BaseStatusEffect.BrainMeltCostReductionSE" ).GetStackCount();
							cost -= ( ( ( Float )( stacks ) ) * TDB.GetFloat( T"EquipmentGLP.BrainMeltProgramLvl3Passive.memoryCostReductionPerStack", 0.0 ) );
						}
						if( ( hackID == T"QuickHack.SystemCollapseLvl3Hack" ) || ( hackID == T"QuickHack.SystemCollapseLvl4Hack" ) )
						{
							stacks = StatusEffectHelper.GetStatusEffectByID( GetPlayer( GetExecutor().GetGame() ), T"BaseStatusEffect.SystemCollapseMemoryCostReduction" ).GetStackCount();
							cost -= ( ( ( Float )( stacks ) ) * TDB.GetFloat( T"EquipmentGLP.SystemCollapseLvl3Program.memoryCostReductionPerStack", 0.0 ) );
						}
						if( ( GetObjectActionRecord().GetID() == T"QuickHack.GrenadeLvl3Hack" ) || ( GetObjectActionRecord().GetID() == T"QuickHack.GrenadeLvl4Hack" ) )
						{
							cost -= GetDetonateGranadeCostReduction( false );
						}
						else if( GetObjectActionRecord().GetID() == T"QuickHack.GrenadeLvl4PlusPlusHack" )
						{
							cost -= GetDetonateGranadeCostReduction( true );
						}
						if( actionName == 'Suicide' )
						{
							cost -= GameInstance.GetStatsSystem( GetExecutor().GetGame() ).GetStatValue( GetExecutor().GetEntityID(), gamedataStatType.SuicideHackMemoryCostReduction );
						}
						if( PlayerDevelopmentSystem.GetData( GetExecutor() ).IsNewPerkBought( gamedataNewPerkType.Intelligence_Central_Perk_1_2 ) )
						{
							targetPos = GameInstance.FindEntityByID( GetExecutor().GetGame(), targetID ).GetWorldPosition();
							instigatorPos = GetExecutor().GetWorldPosition();
							distance = Vector4.Distance( targetPos, instigatorPos );
							statsDataSystem = GameInstance.GetStatsDataSystem( GetExecutor().GetGame() );
							cost *= ( 1.0 - statsDataSystem.GetValueFromCurve( 'hacking_passives', distance, 'distance_to_hacking_cost_reduction' ) );
						}
						if( QuickHackableHelper.IsOverclockedStateActive( GetExecutor() ) )
						{
							if( StrEndsWith( NameToString( actionName ), "BlackWall" ) )
							{
								availableMemory = GameInstance.GetStatPoolsSystem( GetExecutor().GetGame() ).GetStatPoolValue( GetExecutor().GetEntityID(), gamedataStatPoolType.Memory, false );
								availableMemory = MinF( cost, ( ( Float )( FloorF( availableMemory ) ) ) );
								cost = availableMemory + ( ( cost - availableMemory ) * TDB.GetFloat( T"QuickHack.BaseBlackWallHack.memoryCostReductionInOverclock", 1.0 ) );
							}
						}
					}
					if( costMods.Size() > 0 )
					{
						return Max( 2, CeilF( cost ) );
					}
					return Max( 0, CeilF( cost ) );
				}
			}
		}
		return 0;
	}

	public virtual function GetBaseCost() : Int32
	{
		var costMods : array< weak< StatModifier_Record > >;
		var targetID : EntityID;
		var statPoolCost : weak< StatPoolCost_Record >;
		var cost, extraCost : Float;
		var constantCostMods : array< weak< StatModifier_Record > >;
		var i : Int32;
		if( GetExecutor() && ( GetObjectActionRecord().GetCostsCount() > 0 ) )
		{
			if( m_costComponents.Size() == 0 )
			{
				GetObjectActionRecord().Costs( m_costComponents );
			}
			GetCostMods( m_costComponents, costMods );
			if( m_costComponents[ 0 ] )
			{
				if( EntityID.IsDefined( GetRequesterID() ) )
				{
					targetID = GetRequesterID();
				}
				else
				{
					targetID = PersistentID.ExtractEntityID( GetPersistentID() );
				}
				for( i = 0; i < costMods.Size(); i += 1 )
				{
					if( ( ( ConstantStatModifier_Record )( costMods[ i ] ) ) )
					{
						constantCostMods.PushBack( costMods[ i ] );
					}
				}
				cost = RPGManager.CalculateStatModifiers( constantCostMods, GetExecutor().GetGame(), GetExecutor(), targetID, GetExecutor().GetEntityID() );
				statPoolCost = ( ( StatPoolCost_Record )( m_costComponents[ 0 ] ) );
				if( statPoolCost.StatPool().StatPoolType() == gamedataStatPoolType.Memory )
				{
					extraCost = GameInstance.GetStatsDataSystem( GetExecutor().GetGame() ).GetValueFromCurve( 'puppet_dynamic_scaling', GetPowerLevelDiff(), 'pl_diff_to_memory_cost_modifier' );
					cost += extraCost;
					if( GetObjectActionRecord().HackCategory().Type() == gamedataHackCategory.UltimateHack )
					{
						cost += extraCost;
					}
				}
				if( costMods.Size() > 0 )
				{
					return Max( 1, CeilF( cost ) );
				}
				return Max( 0, CeilF( cost ) );
			}
		}
		return 0;
	}

	public static function GetBaseCostStatic( executor : weak< GameObject >, actionRecord : weak< ObjectAction_Record > ) : Int32
	{
		var costComponents : array< weak< ObjectActionCost_Record > >;
		var costMods : array< weak< StatModifier_Record > >;
		var targetID : EntityID;
		var cost : Float;
		var constantCostMods : array< weak< StatModifier_Record > >;
		var i : Int32;
		if( executor && ( actionRecord.GetCostsCount() > 0 ) )
		{
			actionRecord.Costs( costComponents );
			GetCostMods( costComponents, costMods );
			if( costComponents[ 0 ] )
			{
				for( i = 0; i < costMods.Size(); i += 1 )
				{
					if( ( ( ConstantStatModifier_Record )( costMods[ i ] ) ) )
					{
						constantCostMods.PushBack( costMods[ i ] );
					}
				}
				cost += RPGManager.CalculateStatModifiers( constantCostMods, executor.GetGame(), executor, targetID, executor.GetEntityID() );
				if( costMods.Size() > 0 )
				{
					return Max( 1, CeilF( cost ) );
				}
				return Max( 0, CeilF( cost ) );
			}
		}
		return 0;
	}

	public static function GetCostMods( costComponents : ref< array< weak< ObjectActionCost_Record > > >, out costMods : array< weak< StatModifier_Record > > )
	{
		var i : Int32;
		for( i = 0; i < costComponents.Size(); i += 1 )
		{
			costComponents[ i ].CostMods( costMods );
		}
	}

	private function GetPowerLevelDiff() : Float
	{
		var statsSystem : StatsSystem;
		var powerLevelDiff : Float;
		var executorLevel : Float;
		var targetLevel : Float;
		var targetID : EntityID;
		if( !( GetExecutor() ) )
		{
			return 0.0;
		}
		targetID = GetRequesterID();
		if( !( EntityID.IsDefined( targetID ) ) )
		{
			targetID = PersistentID.ExtractEntityID( GetPersistentID() );
		}
		if( !( EntityID.IsDefined( targetID ) ) )
		{
			return 0.0;
		}
		statsSystem = GameInstance.GetStatsSystem( GetExecutor().GetGame() );
		executorLevel = statsSystem.GetStatValue( GetExecutor().GetEntityID(), gamedataStatType.PowerLevel );
		targetLevel = statsSystem.GetStatValue( targetID, gamedataStatType.PowerLevel );
		powerLevelDiff = ( ( Float )( RoundMath( executorLevel ) - RoundF( targetLevel ) ) );
		return powerLevelDiff;
	}

	private function GetExecutorLevel() : Float
	{
		var statsSystem : StatsSystem;
		var executorLevel : Float;
		if( !( GetExecutor() ) )
		{
			return 0.0;
		}
		statsSystem = GameInstance.GetStatsSystem( GetExecutor().GetGame() );
		executorLevel = statsSystem.GetStatValue( GetExecutor().GetEntityID(), gamedataStatType.PowerLevel );
		return executorLevel;
	}

	private function GetMadnessLvl3ProgramCostReduction( targetID : EntityID ) : Float
	{
		var maxReduction : Float;
		var stackReduction : Float;
		var costReductors : array< TweakDBID >;
		var costReductor : gamedataStatusEffectType;
		var appliedStatusEffects : array< StatusEffect >;
		var stacks : Uint32;
		var i, j : Int32;
		maxReduction = TweakDBInterface.GetFloat( T"Items.MadnessLvl3Program.maxCostReduction", 0.0 );
		stackReduction = TweakDBInterface.GetFloat( T"Items.MadnessLvl3Program.costReductionPerReductorStack", 0.0 );
		costReductors = TweakDBInterface.GetForeignKeyArray( T"Items.MadnessLvl3Program.statusEffectsTypeCostReductors" );
		stacks = 0;
		for( i = 0; i < costReductors.Size(); i += 1 )
		{
			appliedStatusEffects.Clear();
			costReductor = TweakDBInterface.GetStatusEffectTypeRecord( costReductors[ i ] ).Type();
			GameInstance.GetStatusEffectSystem( GetExecutor().GetGame() ).GetAppliedEffectsOfType( targetID, costReductor, appliedStatusEffects );
			for( j = 0; j < appliedStatusEffects.Size(); j += 1 )
			{
				stacks += appliedStatusEffects[ j ].GetStackCount();
			}
		}
		return MinF( maxReduction, ( ( Float )( stacks ) ) * stackReduction );
	}

	private function GetDetonateGranadeCostReduction( legendaryPlusPlus : Bool ) : Float
	{
		var stackSE : TweakDBID;
		var stackReduction : Float;
		var stacks : Uint32;
		stackSE = ( ( legendaryPlusPlus ) ? ( T"BaseStatusEffect.ReduceUltimateSuicideWithGrenadeCostPlusPlus" ) : ( T"BaseStatusEffect.ReduceUltimateSuicideWithGrenadeCost" ) );
		stackReduction = TweakDBInterface.GetFloat( ( ( legendaryPlusPlus ) ? ( T"BaseStatusEffect.ReduceUltimateSuicideWithGrenadeCostPlusPlus.costReductionPerStack" ) : ( T"BaseStatusEffect.ReduceUltimateSuicideWithGrenadeCost.costReductionPerStack" ) ), 0.0 );
		stacks = StatusEffectHelper.GetStatusEffectByID( GetPlayer( GetExecutor().GetGame() ), stackSE ).GetStackCount();
		return ( ( Float )( stacks ) ) * stackReduction;
	}

}

abstract class ScriptableDeviceAction extends BaseScriptableAction
{
	var prop : DeviceActionProperty;
	protected var m_actionWidgetPackage : SActionWidgetPackage;
	protected var m_spiderbotActionLocationOverride : NodeRef;
	protected var m_duration : Float;
	private var m_canTriggerStim : Bool;
	default m_canTriggerStim = true;
	private var m_wasPerformedOnOwner : Bool;
	private var m_shouldActivateDevice : Bool;
	private var m_disableSpread : Bool;
	protected var m_isQuickHack : Bool;
	protected var m_isSpiderbotAction : Bool;
	protected var m_attachedProgram : TweakDBID;
	protected var m_activeStatusEffect : TweakDBID;
	protected var m_interactionIconType : TweakDBID;
	protected var m_hasInteraction : Bool;
	protected var m_inactiveReason : String;
	protected var m_widgetStyle : gamedataComputerUIStyle;

	protected override function GetOwnerPS( game : GameInstance ) : ScriptableDeviceComponentPS
	{
		var psID : PersistentID;
		psID = GetPersistentID();
		if( PersistentID.IsDefined( psID ) )
		{
			return ( ( ScriptableDeviceComponentPS )( GameInstance.GetPersistencySystem( game ).GetConstAccessToPSObject( psID, GetDeviceClassName() ) ) );
		}
		else
		{
			return NULL;
		}
	}

	public virtual function ResolveAction( data : ResolveActionData ) : Bool
	{
		return true;
	}

	public const function ShouldActivateDevice() : Bool
	{
		return m_shouldActivateDevice;
	}

	public function SetShouldActivateDevice( value : Bool )
	{
		m_shouldActivateDevice = value;
	}

	public function SetDisableSpread( value : Bool )
	{
		m_disableSpread = value;
	}

	public function SetCanSkipPayCost( value : Bool )
	{
		m_canSkipPayCost = value;
	}

	public const function IsSpreadDisabled() : Bool
	{
		return m_disableSpread;
	}

	public const function CanTriggerStim() : Bool
	{
		return m_canTriggerStim;
	}

	public function SetCanTriggerStim( canTrigger : Bool )
	{
		m_canTriggerStim = canTrigger;
	}

	public const function GetDurationValue() : Float
	{
		return m_duration;
	}

	public function SetCompleted()
	{
		m_duration = 0.0;
	}

	public const function IsCompleted() : Bool
	{
		return m_duration <= 0.0;
	}

	public const function IsStarted() : Bool
	{
		return m_duration > 0.0;
	}

	public function SetDurationValue( duration : Float )
	{
		m_duration = duration;
	}

	public function GetActionName() : CName
	{
		if( IsNameValid( actionName ) )
		{
			return actionName;
		}
		return GetDefaultActionName();
	}

	protected virtual function GetDefaultActionName() : CName
	{
		return 'ScriptableDeviceAction';
	}

	public const override function GetObjectActionRecord() : weak< ObjectAction_Record >
	{
		if( m_objectActionRecord )
		{
			return m_objectActionRecord;
		}
		else if( TDBID.IsValid( m_objectActionID ) )
		{
			return super.GetObjectActionRecord();
		}
		else
		{
			return TweakDBInterface.GetObjectActionRecord( TDBID.Create( "DeviceAction." + NameToString( GetClassName() ) ) );
		}
	}

	public const virtual function CanSpiderbotCompleteThisAction( const device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.IsDisabled() )
		{
			return false;
		}
		return true;
	}

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( IsAvailable( device ) && IsClearanceValid( context.clearance ) )
		{
			return true;
		}
		return false;
	}

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

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

	public function AddDeviceName( const deviceName : ref< String > )
	{
		localizedObjectName = deviceName;
	}

	public function GetDeviceName() : String
	{
		return localizedObjectName;
	}

	public virtual function GetInkWidgetLibraryPath() : ResRef
	{
		return R"";
	}

	public virtual function GetInkWidgetLibraryID() : CName
	{
		return '';
	}

	public virtual function SetInkWidgetTweakDBID( id : TweakDBID )
	{
		m_inkWidgetID = id;
	}

	public function SetWidgetStyle( style : gamedataComputerUIStyle )
	{
		m_widgetStyle = style;
	}

	public virtual function GetInkWidgetTweakDBID() : TweakDBID
	{
		if( TDBID.IsValid( m_inkWidgetID ) )
		{
			return m_inkWidgetID;
		}
		else
		{
			switch( m_widgetStyle )
			{
				case gamedataComputerUIStyle.Orange:
					return T"DevicesUIDefinitions.GenericDeviceActionWidgetOA";
				default:
					return T"DevicesUIDefinitions.GenericDeviceActionWidget";
			}
		}
	}

	public virtual function SetActiveStatusEffectTweakDBID( effectID : TweakDBID )
	{
		m_activeStatusEffect = effectID;
	}

	public virtual function GetActiveStatusEffectTweakDBID() : TweakDBID
	{
		return m_activeStatusEffect;
	}

	public virtual function SetAttachedProgramTweakDBID( programID : TweakDBID )
	{
		m_attachedProgram = programID;
	}

	public virtual function GetAttachedProgramTweakDBID() : TweakDBID
	{
		return m_attachedProgram;
	}

	public function SetIllegal( isIllegal : Bool )
	{
		if( isIllegal )
		{
			ChoiceTypeWrapper.SetType( interactionChoice.choiceMetaData.type, gameinteractionsChoiceType.Illegal );
		}
	}

	public function ClearIllegal()
	{
		ChoiceTypeWrapper.ClearType( interactionChoice.choiceMetaData.type, gameinteractionsChoiceType.Illegal );
	}

	public function IsIllegal() : Bool
	{
		return ChoiceTypeWrapper.IsType( interactionChoice.choiceMetaData.type, gameinteractionsChoiceType.Illegal );
	}

	public function GetInteractionLayer() : CName
	{
		return m_interactionLayer;
	}

	public function SetInteractionLayer( layer : CName )
	{
		m_interactionLayer = layer;
	}

	public function GetRequestType() : gamedeviceRequestType
	{
		if( m_interactionLayer == 'direct' )
		{
			return gamedeviceRequestType.Direct;
		}
		else if( m_interactionLayer == 'remote' )
		{
			return gamedeviceRequestType.Remote;
		}
		return gamedeviceRequestType.None;
	}

	public override function SetObjectActionID( id : TweakDBID )
	{
		m_objectActionID = id;
		m_objectActionRecord = TweakDBInterface.GetObjectActionRecord( id );
		m_costComponents.Clear();
		if( m_objectActionRecord )
		{
			actionName = m_objectActionRecord.ActionName();
		}
		ProduceInteractionPart();
	}

	public function SetAsQuickHack( optional wasExecutedAtLeastOnce : Bool )
	{
		m_isQuickHack = true;
		m_wasPerformedOnOwner = wasExecutedAtLeastOnce;
		ProduceInteractionParts();
	}

	public function GetAwarenessCost( gameInstance : GameInstance ) : Float
	{
		var awarenessCost : Float;
		var hackStatRecord : weak< StatModifierGroup_Record >;
		var hackActionRecord : weak< ObjectAction_Record >;
		var incrementModifiers : array< weak< StatModifier_Record > >;
		awarenessCost = 0.0;
		hackActionRecord = GetObjectActionRecord();
		hackStatRecord = TweakDBInterface.GetStatModifierGroupRecord( TDB.GetForeignKey( hackActionRecord.GetID() + T".awarenessCost" ) );
		if( TDBID.IsValid( hackStatRecord.GetID() ) )
		{
			hackStatRecord.StatModifiers( incrementModifiers );
			awarenessCost = RPGManager.CalculateStatModifiers( incrementModifiers, gameInstance, GetExecutor(), GetRequesterID(), GetExecutor().GetEntityID() );
		}
		return awarenessCost;
	}

	private function ProduceInteractionParts()
	{
		var costPart : InteractionChoiceCaptionQuickhackCostPart;
		var iconRecord : weak< ChoiceCaptionIconPart_Record >;
		if( !( IsInteractionChoiceValid() ) )
		{
			return;
		}
		InteractionChoiceCaption.Clear( interactionChoice.captionParts );
		iconRecord = GetInteractionIcon();
		if( iconRecord )
		{
			InteractionChoiceCaption.AddPartFromRecord( interactionChoice.captionParts, iconRecord );
		}
		if( ( m_isQuickHack && ( GetCost() >= 0 ) ) || ( GetCost() > 0 ) )
		{
			costPart = new InteractionChoiceCaptionQuickhackCostPart;
			costPart.cost = GetCost();
			InteractionChoiceCaption.AddScriptPart( interactionChoice.captionParts, costPart );
		}
		InteractionChoiceCaption.AddTextPart( interactionChoice.captionParts, LocKeyToString( TweakDBInterface.GetInteractionBaseRecord( TDBID.Create( "Interactions." + interactionChoice.choiceMetaData.tweakDBName ) ).Caption() ) );
	}

	private override function StartUpload( gameInstance : GameInstance )
	{
		var statPoolSys : StatPoolsSystem;
		var actionUploadListener : QuickHackUploadListener;
		var statMod : gameStatModifierData;
		var setQuickHackAttempt : SetQuickHackAttemptEvent;
		var progressBarBB : weak< IBlackboard >;
		var hackingMinigameBB : IBlackboard;
		progressBarBB = GameInstance.GetBlackboardSystem( gameInstance ).Get( GetAllBlackboardDefs().UI_HUDProgressBar );
		statPoolSys = GameInstance.GetStatPoolsSystem( gameInstance );
		progressBarBB.SetFloat( GetAllBlackboardDefs().UI_HUDProgressBar.ProgressBump, 0.0 );
		hackingMinigameBB = GameInstance.GetBlackboardSystem( gameInstance ).Get( GetAllBlackboardDefs().HackingMinigame );
		hackingMinigameBB.SetVector4( GetAllBlackboardDefs().HackingMinigame.LastPlayerHackPosition, GetPlayer( gameInstance ).GetWorldPosition() );
		statMod = RPGManager.CreateStatModifier( gamedataStatType.QuickHackUpload, gameStatModifierType.Additive, 1.0 );
		GameInstance.GetStatsSystem( gameInstance ).RemoveAllModifiers( m_requesterID, gamedataStatType.QuickHackUpload );
		GameInstance.GetStatsSystem( gameInstance ).AddModifier( m_requesterID, statMod );
		actionUploadListener = new QuickHackUploadListener;
		actionUploadListener.m_action = this;
		actionUploadListener.m_gameInstance = gameInstance;
		statPoolSys.RequestRegisteringListener( m_requesterID, gamedataStatPoolType.QuickHackUpload, actionUploadListener );
		statPoolSys.RequestAddingStatPool( m_requesterID, T"BaseStatPools.BaseQuickHackUpload", true );
		if( IsQuickHack() )
		{
			setQuickHackAttempt = new SetQuickHackAttemptEvent;
			setQuickHackAttempt.wasQuickHackAttempt = true;
			GameInstance.GetPersistencySystem( gameInstance ).QueuePSEvent( GetPersistentID(), GetDeviceClassName(), setQuickHackAttempt );
		}
	}

	public override function CompleteAction( gameInstance : GameInstance )
	{
		var setQuickHack : SetQuickHackEvent;
		if( m_isTargetDead )
		{
			return;
		}
		GameInstance.GetPersistencySystem( gameInstance ).QueuePSDeviceEvent( this );
		super.CompleteAction( gameInstance );
		if( IsQuickHack() )
		{
			setQuickHack = new SetQuickHackEvent;
			setQuickHack.wasQuickHacked = true;
			setQuickHack.quickHackName = GetActionName();
			GameInstance.GetPersistencySystem( gameInstance ).QueuePSEvent( GetPersistentID(), GetDeviceClassName(), setQuickHack );
			QuickhackModule.RequestRefreshQuickhackMenu( gameInstance, GetRequesterID() );
			RPGManager.HealPuppetAfterQuickhack( gameInstance, m_executor );
		}
	}

	public override function GetCost() : Int32
	{
		return super.GetCost();
	}

	public virtual function SetInteractionIcon( iconType : TweakDBID )
	{
		m_interactionIconType = iconType;
	}

	public const virtual function GetInteractionIcon() : weak< ChoiceCaptionIconPart_Record >
	{
		var iconType : weak< ChoiceCaptionIconPart_Record >;
		if( TDBID.IsValid( m_objectActionID ) )
		{
			iconType = GetObjectActionRecord().ObjectActionUI().CaptionIcon();
		}
		if( iconType )
		{
			return iconType;
		}
		else
		{
			if( TDBID.IsValid( m_interactionIconType ) )
			{
				iconType = TweakDBInterface.GetChoiceCaptionIconPartRecord( m_interactionIconType );
			}
			else
			{
				iconType = InteractionChoiceMetaData.GetTweakData( interactionChoice.choiceMetaData ).CaptionIcon();
			}
		}
		return iconType;
	}

	public function SetAsSpiderbotAction()
	{
		m_isSpiderbotAction = true;
	}

	public const function IsRemoteHack() : Bool
	{
		var actionType : gamedataObjectActionType;
		var actionRecord : weak< ObjectAction_Record >;
		var typeRecord : weak< ObjectActionType_Record >;
		actionRecord = GetObjectActionRecord();
		if( actionRecord )
		{
			typeRecord = actionRecord.ObjectActionType();
		}
		if( typeRecord )
		{
			actionType = typeRecord.Type();
			return actionType == gamedataObjectActionType.Remote;
		}
		return false;
	}

	public const function IsQuickHack() : Bool
	{
		var actionType : gamedataObjectActionType;
		var actionRecord : weak< ObjectAction_Record >;
		var typeRecord : weak< ObjectActionType_Record >;
		if( m_isQuickHack )
		{
			return true;
		}
		actionRecord = GetObjectActionRecord();
		if( actionRecord )
		{
			typeRecord = actionRecord.ObjectActionType();
		}
		if( typeRecord )
		{
			actionType = typeRecord.Type();
			return ( actionType == gamedataObjectActionType.DeviceQuickHack || actionType == gamedataObjectActionType.PuppetQuickHack ) || actionType == gamedataObjectActionType.VehicleQuickHack;
		}
		return false;
	}

	public const function IsSpiderbotAction() : Bool
	{
		return m_isSpiderbotAction;
	}

	public function SetSpiderbotLocationOverrideReference( targetLocationReference : NodeRef )
	{
		m_spiderbotActionLocationOverride = targetLocationReference;
	}

	public function GetSpiderbotLocationOverrideReference() : NodeRef
	{
		return m_spiderbotActionLocationOverride;
	}

	public function GetInteractionChoice() : InteractionChoice
	{
		var choice : InteractionChoice;
		var i : Int32;
		if( m_hasInteraction )
		{
			choice.data.Insert( 0, ( ( DeviceAction )( this ) ) );
			choice.caption = interactionChoice.caption;
			choice.captionParts = interactionChoice.captionParts;
			choice.choiceMetaData.tweakDBID = interactionChoice.choiceMetaData.tweakDBID;
			choice.choiceMetaData.type = interactionChoice.choiceMetaData.type;
			if( !( TDBID.IsValid( interactionChoice.choiceMetaData.tweakDBID ) ) )
			{
				choice.choiceMetaData.tweakDBID = GetTweakDBChoiceID();
			}
			if( StringToName( interactionChoice.choiceMetaData.tweakDBName ) == GetActionName() )
			{
				choice.choiceMetaData.tweakDBName = GetTweakDBChoiceRecord();
			}
			else
			{
				choice.choiceMetaData.tweakDBName = interactionChoice.choiceMetaData.tweakDBName;
			}
			for( i = 0; i < interactionChoice.data.Size(); i += 1 )
			{
				choice.data.PushBack( ( ( DeviceAction )( interactionChoice.data[ i ] ) ) );
			}
			if( choice.captionParts.parts.Size() == 0 )
			{
				ProduceInteractionParts();
				choice.captionParts = interactionChoice.captionParts;
			}
		}
		return choice;
	}

	public function GetActionWidgetPackage() : SActionWidgetPackage
	{
		var actionWidgetPackage : SActionWidgetPackage;
		actionWidgetPackage.action = this;
		if( !( TDBID.IsValid( m_actionWidgetPackage.widgetTweakDBID ) ) )
		{
			actionWidgetPackage.widgetTweakDBID = GetInkWidgetTweakDBID();
			ResolveActionWidgetTweakDBData();
		}
		else
		{
			actionWidgetPackage.widgetTweakDBID = m_actionWidgetPackage.widgetTweakDBID;
		}
		actionWidgetPackage.wasInitalized = m_actionWidgetPackage.wasInitalized;
		actionWidgetPackage.dependendActions = m_actionWidgetPackage.dependendActions;
		actionWidgetPackage.libraryPath = m_actionWidgetPackage.libraryPath;
		actionWidgetPackage.libraryID = m_actionWidgetPackage.libraryID;
		actionWidgetPackage.widgetName = m_actionWidgetPackage.widgetName;
		actionWidgetPackage.displayName = m_actionWidgetPackage.displayName;
		actionWidgetPackage.iconID = m_actionWidgetPackage.iconID;
		actionWidgetPackage.isWidgetInactive = m_actionWidgetPackage.isWidgetInactive;
		actionWidgetPackage.widgetState = m_actionWidgetPackage.widgetState;
		actionWidgetPackage.isValid = ( ResRef.IsValid( actionWidgetPackage.libraryPath ) || IsNameValid( actionWidgetPackage.libraryID ) ) || TDBID.IsValid( actionWidgetPackage.widgetTweakDBID );
		return actionWidgetPackage;
	}

	public function CreateInteraction( optional actions : array< DeviceAction >, optional alternativeMainChoiceRecord : String, optional alternativeMainChoiceTweakDBID : TweakDBID )
	{
		var defaultChoiceID : TweakDBID;
		m_hasInteraction = true;
		if( TDBID.IsValid( alternativeMainChoiceTweakDBID ) )
		{
			interactionChoice.choiceMetaData.tweakDBID = alternativeMainChoiceTweakDBID;
		}
		else if( IsStringValid( alternativeMainChoiceRecord ) )
		{
			interactionChoice.choiceMetaData.tweakDBName = alternativeMainChoiceRecord;
		}
		else
		{
			defaultChoiceID = GetTweakDBChoiceID();
			if( TDBID.IsValid( defaultChoiceID ) )
			{
				interactionChoice.choiceMetaData.tweakDBID = defaultChoiceID;
			}
			else if( IsStringValid( alternativeMainChoiceRecord ) )
			{
				interactionChoice.choiceMetaData.tweakDBName = alternativeMainChoiceRecord;
			}
			else
			{
				interactionChoice.choiceMetaData.tweakDBName = GetTweakDBChoiceRecord();
			}
		}
		DeviceHelper.PushActionsIntoInteractionChoice( interactionChoice, actions );
	}

	public virtual function HasUI() : Bool
	{
		return m_actionWidgetPackage.wasInitalized == true && IsStringValid( m_actionWidgetPackage.widgetName );
	}

	public virtual function CreateActionWidgetPackage( optional actions : array< DeviceAction > )
	{
		m_actionWidgetPackage.wasInitalized = true;
		m_actionWidgetPackage.dependendActions = actions;
		m_actionWidgetPackage.libraryPath = GetInkWidgetLibraryPath();
		m_actionWidgetPackage.libraryID = GetInkWidgetLibraryID();
		m_actionWidgetPackage.widgetName = ( ( String )( GetActionName() ) );
		m_actionWidgetPackage.displayName = GetCurrentDisplayString();
		m_actionWidgetPackage.iconID = GetActionName();
		m_actionWidgetPackage.widgetTweakDBID = GetInkWidgetTweakDBID();
		ResolveActionWidgetTweakDBData();
	}

	public virtual function CreateActionWidgetPackage( widgetTweakDBID : TweakDBID, optional actions : array< DeviceAction > )
	{
		CreateActionWidgetPackage( actions );
		if( TDBID.IsValid( widgetTweakDBID ) )
		{
			m_actionWidgetPackage.widgetTweakDBID = widgetTweakDBID;
			ResolveActionWidgetTweakDBData();
		}
	}

	protected function ResolveActionWidgetTweakDBData()
	{
		var record : WidgetDefinition_Record;
		if( TDBID.IsValid( m_actionWidgetPackage.widgetTweakDBID ) )
		{
			record = TweakDBInterface.GetWidgetDefinitionRecord( m_actionWidgetPackage.widgetTweakDBID );
			if( record != NULL )
			{
				m_actionWidgetPackage.libraryPath = record.LibraryPath();
				m_actionWidgetPackage.libraryID = StringToName( record.LibraryID() );
			}
		}
	}

	public virtual function CreateCustomInteraction( optional actions : array< DeviceAction >, const customName1 : ref< String >, const customName2 : ref< String >, optional customID1 : TweakDBID, optional customID2 : TweakDBID ) {}

	public function SetInactiveWithReason( isActiveIf : Bool, const reason : ref< String > )
	{
		if( !( isActiveIf ) )
		{
			SetInactive();
			SetInactiveReason( reason );
		}
	}

	public function SetInactiveReason( const reasonStr : ref< String > )
	{
		if( reasonStr != "" )
		{
			m_inactiveReason = reasonStr;
		}
	}

	public const function GetInactiveReason() : String
	{
		return m_inactiveReason;
	}

	public function SetInactiveReasonAsCaption()
	{
		if( IsInactive() )
		{
			interactionChoice.caption = m_inactiveReason;
		}
	}

	public const function GetDurationFromTDBRecord( record : TweakDBID ) : Float
	{
		var minigameActionRecord : MinigameAction_Record;
		var duration : Float;
		minigameActionRecord = TweakDBInterface.GetMinigameActionRecord( record );
		duration = minigameActionRecord.Duration();
		return duration;
	}

}

abstract class ActionBool extends ScriptableDeviceAction
{

	public export override function GetProperties() : array< DeviceActionProperty >
	{
		var arr : array< DeviceActionProperty >;
		arr.PushBack( prop );
		return arr;
	}

	public const override function GetCurrentDisplayString() : String
	{
		var str : String;
		if( !( ( ( Bool )prop.first ) ) )
		{
			str = NameToString( ( ( CName )prop.second ) );
		}
		else
		{
			str = NameToString( ( ( CName )prop.third ) );
		}
		return str;
	}

	public function GetValue() : Bool
	{
		return ( ( Bool )prop.first );
	}

	public function OverrideInteractionRecord( newRecordforTrue, newRecordForFalse : TweakDBID )
	{
		var newRecord : TweakDBID;
		var isTrue : Bool;
		DeviceActionPropertyFunctions.GetProperty_Bool( prop, isTrue );
		if( isTrue )
		{
			newRecord = newRecordforTrue;
		}
		else
		{
			newRecord = newRecordForFalse;
		}
		if( TDBID.IsValid( newRecord ) )
		{
			m_hasInteraction = true;
			interactionChoice.choiceMetaData.tweakDBID = newRecord;
		}
	}

	public override function CreateCustomInteraction( optional actions : array< DeviceAction >, const customName1 : ref< String >, const customName2 : ref< String >, optional customID1 : TweakDBID, optional customID2 : TweakDBID )
	{
		var value : Bool;
		var useTweakDB : Bool;
		useTweakDB = TDBID.IsValid( customID1 ) && TDBID.IsValid( customID2 );
		if( ( IsStringValid( customName1 ) && IsStringValid( customName2 ) ) || useTweakDB )
		{
			m_hasInteraction = true;
			DeviceActionPropertyFunctions.GetProperty_Bool( prop, value );
			if( !( value ) )
			{
				if( useTweakDB )
				{
					interactionChoice.choiceMetaData.tweakDBID = customID1;
				}
				else
				{
					interactionChoice.choiceMetaData.tweakDBName = customName1;
				}
			}
			else
			{
				if( useTweakDB )
				{
					interactionChoice.choiceMetaData.tweakDBID = customID2;
				}
				else
				{
					interactionChoice.choiceMetaData.tweakDBName = customName2;
				}
			}
			DeviceHelper.PushActionsIntoInteractionChoice( interactionChoice, actions );
		}
		else
		{
			CreateInteraction( actions );
		}
	}

	public override function CreateActionWidgetPackage( optional actions : array< DeviceAction > )
	{
		var value : Bool;
		super.CreateActionWidgetPackage( actions );
		DeviceActionPropertyFunctions.GetProperty_Bool( prop, value );
		if( !( value ) )
		{
			m_actionWidgetPackage.widgetState = EWidgetState.OFF;
		}
		else
		{
			m_actionWidgetPackage.widgetState = EWidgetState.ON;
		}
	}

}

abstract class ActionInt extends ScriptableDeviceAction
{

	public export override function GetProperties() : array< DeviceActionProperty >
	{
		var arr : array< DeviceActionProperty >;
		arr.PushBack( prop );
		return arr;
	}

	public const override function GetCurrentDisplayString() : String
	{
		var str : String;
		str = ( NameToString( prop.name ) + " " ) + IntToString( ( ( Int32 )prop.first ) );
		return str;
	}

}

abstract class ActionFloat extends ScriptableDeviceAction
{

	public export override function GetProperties() : array< DeviceActionProperty >
	{
		var arr : array< DeviceActionProperty >;
		arr.PushBack( prop );
		return arr;
	}

	public const override function GetCurrentDisplayString() : String
	{
		var str : String;
		str = ( NameToString( prop.name ) + " " ) + FloatToString( ( ( Float )prop.first ) );
		return str;
	}

}

abstract class ActionEnum extends ActionInt
{
}

abstract class ActionName extends ScriptableDeviceAction
{

	public export override function GetProperties() : array< DeviceActionProperty >
	{
		var arr : array< DeviceActionProperty >;
		arr.PushBack( prop );
		return arr;
	}

	public const override function GetCurrentDisplayString() : String
	{
		var str : String;
		str = ( NameToString( prop.name ) + " " ) + NameToString( ( ( CName )prop.first ) );
		return str;
	}

}

abstract class ActionNodeRef extends ScriptableDeviceAction
{

	public export override function GetProperties() : array< DeviceActionProperty >
	{
		var arr : array< DeviceActionProperty >;
		arr.PushBack( prop );
		return arr;
	}

	public const override function GetCurrentDisplayString() : String
	{
		var str : String;
		str = NameToString( prop.name ) + " NodeRef (conversion to string not supported yet)";
		return str;
	}

}

abstract class ActionEntityReference extends ScriptableDeviceAction
{

	public export override function GetProperties() : array< DeviceActionProperty >
	{
		var arr : array< DeviceActionProperty >;
		arr.PushBack( prop );
		return arr;
	}

	public const override function GetCurrentDisplayString() : String
	{
		var str : String;
		str = NameToString( prop.name ) + " EntityReference (conversion to string not supported yet)";
		return str;
	}

}

abstract class ActionWorkSpot extends ActionBool
{
	private var m_workspotTarget : weak< gamePuppet >;

	public function SetUp( owner : DeviceComponentPS, workspotTarget : weak< gamePuppet > )
	{
		SetUp( owner );
		m_workspotTarget = workspotTarget;
	}

	public function GetWorkspotTarget() : weak< gamePuppet >
	{
		return m_workspotTarget;
	}

}

abstract class ActionSkillCheck extends ActionBool
{
	protected var m_skillCheck : SkillCheckBase;
	protected var m_skillCheckName : EDeviceChallengeSkill;
	protected var m_localizedName : String;
	protected var m_skillcheckDescription : UIInteractionSkillCheck;
	protected var m_wasPassed : Bool;
	protected var m_availableUnpowered : Bool;

	protected override function GetDefaultActionName() : CName
	{
		return 'ActionSkillCheck';
	}

	public function SetProperties( skillCheck : SkillCheckBase )
	{
		actionName = GetDefaultActionName();
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( actionName, true, actionName, actionName );
		m_skillCheck = skillCheck;
	}

	public function CreateInteraction( requester : GameObject, optional actions : array< DeviceAction >, optional alternativeMainChoiceRecord : String, optional alternativeMainChoiceRecordID : TweakDBID )
	{
		var choiceType : gameinteractionsChoiceType;
		m_hasInteraction = true;
		if( IsStringValid( alternativeMainChoiceRecord ) )
		{
			interactionChoice.choiceMetaData.tweakDBName = alternativeMainChoiceRecord;
		}
		else if( TDBID.IsValid( alternativeMainChoiceRecordID ) )
		{
			interactionChoice.choiceMetaData.tweakDBID = alternativeMainChoiceRecordID;
		}
		else if( TDBID.IsValid( m_skillCheck.GetAlternativeName() ) )
		{
			interactionChoice.choiceMetaData.tweakDBID = m_skillCheck.GetAlternativeName();
		}
		else
		{
			interactionChoice.choiceMetaData.tweakDBName = GetTweakDBChoiceRecord();
		}
		m_skillCheck.GetBaseSkill().SetEntityID( GetRequesterID() );
		m_skillcheckDescription = CreateSkillcheckInfo( requester );
		choiceType = ( ( m_wasPassed ) ? ( gameinteractionsChoiceType.CheckSuccess ) : ( gameinteractionsChoiceType.CheckFailed ) );
		ChoiceTypeWrapper.SetType( interactionChoice.choiceMetaData.type, choiceType );
		if( m_wasPassed )
		{
			DeviceHelper.PushActionsIntoInteractionChoice( interactionChoice, actions );
		}
	}

	public function CreateSkillcheckInfo( requester : GameObject ) : UIInteractionSkillCheck
	{
		var requiredSkill : Int32;
		m_wasPassed = m_skillCheck.Evaluate( requester );
		m_skillcheckDescription.isValid = true;
		m_skillcheckDescription.skillCheck = m_skillCheckName;
		m_skillcheckDescription.skillName = m_localizedName;
		if( m_skillCheck.GetDifficulty() == EGameplayChallengeLevel.TRIVIAL )
		{
			requiredSkill = 3;
		}
		else
		{
			requiredSkill = m_skillCheck.GetBaseSkill().GetRequiredLevel( requester.GetGame() );
		}
		m_skillcheckDescription.requiredSkill = requiredSkill;
		m_skillcheckDescription.playerSkill = m_skillCheck.GetBaseSkill().GetPlayerSkill( requester );
		m_skillcheckDescription.actionDisplayName = interactionChoice.caption;
		m_skillcheckDescription.isPassed = m_wasPassed;
		m_skillcheckDescription.ownerID = GetRequesterID();
		if( m_skillCheck.GetAdditionalRequirements().HasAdditionalRequirements() )
		{
			m_skillcheckDescription.hasAdditionalRequirements = true;
			m_skillcheckDescription.additionalReqOperator = m_skillCheck.GetAdditionalRequirements().GetOperator();
			m_skillcheckDescription.additionalRequirements = m_skillCheck.GetAdditionalRequirements().CreateDescription( requester, GetRequesterID() );
		}
		return m_skillcheckDescription;
	}

	public const function GetPlayerStateMachine( requester : GameObject ) : IBlackboard
	{
		var playerStateMachineBlackboard : IBlackboard;
		var playerPuppet : PlayerPuppet;
		playerPuppet = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( requester.GetGame() ).GetLocalPlayerMainGameObject() ) );
		playerStateMachineBlackboard = GameInstance.GetBlackboardSystem( requester.GetGame() ).GetLocalInstanced( playerPuppet.GetEntityID(), GetAllBlackboardDefs().PlayerStateMachine );
		return playerStateMachineBlackboard;
	}

	public const function GetSkillcheckInfo() : UIInteractionSkillCheck
	{
		return m_skillcheckDescription;
	}

	public const function SetSkillCheckReadyToPresentOnScreen()
	{
		m_skillCheck.GetBaseSkill().TrySetRequiredLevel( m_skillcheckDescription.requiredSkill );
	}

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext >, availableUnpowered : Bool ) : Bool
	{
		if( IsAvailable( device, availableUnpowered ) && IsClearanceValid( context.clearance ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS, availableUnpowered : Bool ) : Bool
	{
		if( ( device.IsDisabled() || ( device.IsUnpowered() && !( availableUnpowered ) ) ) || device.IsBroken() )
		{
			return false;
		}
		return true;
	}

	public override function GetTweakDBChoiceRecord() : String
	{
		var str : String;
		str = NameToString( GetDefaultActionName() );
		return str;
	}

	public function WasPassed() : Bool
	{
		return m_wasPassed;
	}

	public function AvailableOnUnpowered() : Bool
	{
		return m_availableUnpowered;
	}

	public function SetAvailableOnUnpowered()
	{
		m_availableUnpowered = true;
	}

	public virtual function GetAttributeCheckType() : EDeviceChallengeSkill
	{
		return m_skillCheckName;
	}

	public function ResetCaption()
	{
		interactionChoice.caption = "";
	}

}

class RemoteBreach extends ActionBool
{

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

}

class PingDevice extends ActionBool
{
	private var m_shouldForward : Bool;
	default m_shouldForward = true;

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

	public const function ShouldForward() : Bool
	{
		return m_shouldForward;
	}

	public function SetShouldForward( shouldForward : Bool )
	{
		m_shouldForward = shouldForward;
	}

	public override function CompleteAction( gameInstance : GameInstance )
	{
		super.CompleteAction( gameInstance );
		if( m_shouldForward )
		{
			GetExecutor().GetDeviceLink().PingDevicesNetwork();
		}
	}

}

class ActionHacking extends ActionSkillCheck
{
	default actionName = 'ActionHacking';
	default m_skillCheckName = EDeviceChallengeSkill.Hacking;
	default m_localizedName = "LocKey#22278";

	protected override function GetDefaultActionName() : CName
	{
		return 'ActionHacking';
	}

	public const override function GetInteractionIcon() : weak< ChoiceCaptionIconPart_Record >
	{
		return TweakDBInterface.GetChoiceCaptionIconPartRecord( T"ChoiceCaptionParts.JackInIcon" );
	}

}

class ActionEngineering extends ActionSkillCheck
{
	default actionName = 'ActionEngineering';
	default m_skillCheckName = EDeviceChallengeSkill.Engineering;
	default m_localizedName = "LocKey#22276";

	protected override function GetDefaultActionName() : CName
	{
		return 'ActionEngineering';
	}

	public const override function GetInteractionIcon() : weak< ChoiceCaptionIconPart_Record >
	{
		return TweakDBInterface.GetChoiceCaptionIconPartRecord( T"ChoiceCaptionParts.UseIcon" );
	}

}

class ActionDemolition extends ActionSkillCheck
{
	default actionName = 'ActionDemolition';
	default m_skillCheckName = EDeviceChallengeSkill.Athletics;
	default m_localizedName = "LocKey#22271";
	var slotID : MountingSlotId;

	protected override function GetDefaultActionName() : CName
	{
		return 'ActionDemolition';
	}

	public const override function GetInteractionIcon() : weak< ChoiceCaptionIconPart_Record >
	{
		return TweakDBInterface.GetChoiceCaptionIconPartRecord( T"ChoiceCaptionParts.UseIcon" );
	}

}

class ActionScavenge extends ActionInt
{

	public function SetProperties( amoutOfScraps : Int32 )
	{
		actionName = 'ActionScavenge';
		prop = DeviceActionPropertyFunctions.SetUpProperty_Int( actionName, amoutOfScraps );
	}

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( IsAvailable( device ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.CanBeScavenged() )
		{
			return true;
		}
		return false;
	}

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

}

class BaseDeviceStatus extends ActionEnum
{
	var m_isRestarting : Bool;

	public virtual function SetProperties( const deviceRef : ScriptableDeviceComponentPS )
	{
		m_isRestarting = deviceRef.IsRestarting();
		prop = DeviceActionPropertyFunctions.SetUpProperty_Int( 'STATUS', ( ( Int32 )( deviceRef.GetDeviceState() ) ) );
	}

	public const override function GetCurrentDisplayString() : String
	{
		var str : String;
		var baseStateValue : Int32;
		baseStateValue = 0;
		if( prop.first.IsValid() )
		{
			baseStateValue = ( ( Int32 )prop.first );
		}
		if( m_isRestarting )
		{
			return "LocKey#17797";
		}
		switch( baseStateValue )
		{
			case -2:
				str = "LocKey#17796";
			break;
			case -1:
				str = "LocKey#17793";
			break;
			case 0:
				str = "LocKey#17794";
			break;
			case 1:
				str = "LocKey#17795";
			break;
			default:
				str = "Unknown Status - DEBUG";
			break;
		}
		return str;
	}

	public const function GetScannerStatusRecord() : TweakDBID
	{
		var baseStateValue : Int32;
		var recordbase : String;
		var ending : String;
		var recordID : TweakDBID;
		recordbase = "scanning_devices.";
		baseStateValue = ( ( Int32 )prop.first );
		if( m_isRestarting )
		{
			ending = "booting";
		}
		else
		{
			switch( baseStateValue )
			{
				case -2:
					ending = "disabled";
				break;
				case -1:
					ending = "unpowered";
				break;
				case 0:
					ending = "off";
				break;
				case 1:
					ending = "on";
				break;
				default:
					break;
			}
		}
		recordID = TDBID.Create( recordbase + ending );
		return recordID;
	}

	public const virtual function GetStatusValue() : Int32
	{
		return ( ( Int32 )prop.first );
	}

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( IsAvailable( device ) && IsClearanceValid( context.clearance ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.IsDisabled() )
		{
			return false;
		}
		return true;
	}

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

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

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

}

class QuestForceDestructible extends ActionBool
{

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

}

class QuestForceIndestructible extends ActionBool
{

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

}

class QuestForceInvulnerable extends ActionBool
{

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

}

class QuestForceEnabled extends ActionBool
{

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

}

class QuestForceDisabled extends ActionBool
{

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

}

class QuestForcePower extends ActionBool
{

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

}

class QuestForceUnpower extends ActionBool
{

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

}

class QuestForceON extends ActionBool
{

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

}

class QuestForceOFF extends ActionBool
{

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

}

class QuestForceAuthorizationEnabled extends ActionBool
{

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

}

class QuestForceAuthorizationDisabled extends ActionBool
{

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

}

class QuestForceDisconnectPersonalLink extends ActionBool
{

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

}

class QuestForcePersonalLinkUnderStrictQuestControl extends ActionBool
{

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

}

class QuestEnableFixing extends ActionBool
{

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

}

class QuestDisableFixing extends ActionBool
{

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

}

class QuestForceJuryrigTrapArmed extends ActionBool
{

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

}

class QuestForceJuryrigTrapDeactivated extends ActionBool
{

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

}

class QuestForceSecuritySystemSafe extends ActionBool
{

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

}

class QuestForceSecuritySystemAlarmed extends ActionBool
{

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

}

class QuestForceSecuritySystemArmed extends ActionBool
{

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

}

class QuestStartGlitch extends ActionBool
{

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

}

class QuestStopGlitch extends ActionBool
{

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

}

class QuestEnableInteraction extends ActionBool
{

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

}

class QuestDisableInteraction extends ActionBool
{

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

}

class SetDeviceON extends ActionBool
{

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

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( IsAvailable( device ) && IsClearanceValid( context.clearance ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.IsUnpowered() || device.IsDisabled() )
		{
			return false;
		}
		return true;
	}

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

}

class SetDeviceOFF extends ActionBool
{

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

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( IsAvailable( device ) && IsClearanceValid( context.clearance ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.IsUnpowered() || device.IsDisabled() )
		{
			return false;
		}
		return true;
	}

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

}

class SetDeviceUnpowered extends ActionBool
{

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

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( IsAvailable( device ) && IsClearanceValid( context.clearance ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.GetDeviceStatusAction().GetStatusValue() == ( ( Int32 )( EDeviceStatus.DISABLED ) ) )
		{
			return false;
		}
		return true;
	}

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

}

class SetDevicePowered extends ActionBool
{

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

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( IsAvailable( device ) && IsClearanceValid( context.clearance ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.GetDeviceStatusAction().GetStatusValue() == ( ( Int32 )( EDeviceStatus.DISABLED ) ) )
		{
			return false;
		}
		return true;
	}

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

}

class DisassembleDevice extends ActionBool
{

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

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

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.CanBeDisassembled() )
		{
			return true;
		}
		return false;
	}

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

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

}

class FixDevice extends ActionBool
{

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

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

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.CanBeFixed() )
		{
			return true;
		}
		return false;
	}

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

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

}

class ToggleJuryrigTrap extends ActionBool
{

	public function SetProperties( state : EJuryrigTrapState )
	{
		var isArmed : Bool;
		actionName = 'ToggleJuryrigTrap';
		isArmed = state == EJuryrigTrapState.ARMED;
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'ToggleJuryrigTrap', isArmed, 'LocKey#270', 'LocKey#270' );
	}

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

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		return device.CanBeTrapped() && device.GetJuryrigTrapState() == EJuryrigTrapState.UNARMED;
	}

	public static function IsContextValid( const context : ref< GetActionsContext > ) : Bool
	{
		return context.requestType != gamedeviceRequestType.External;
	}

	public override function GetTweakDBChoiceRecord() : String
	{
		if( !( ( ( Bool )prop.first ) ) )
		{
			return "JuryrigTrap";
		}
		else
		{
			return "DisableJuryrigTrap";
		}
	}

}

class ToggleActivation extends ActionBool
{

	public function SetProperties( status : EDeviceStatus )
	{
		var disabled : Bool;
		actionName = 'ToggleActivation';
		disabled = false;
		if( status == EDeviceStatus.DISABLED )
		{
			disabled = true;
		}
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'ToggleActivation', disabled, 'LocKey#247', 'LocKey#245' );
	}

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( IsAvailable( device ) && IsClearanceValid( context.clearance ) )
		{
			return true;
		}
		return false;
	}

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

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

}

class TogglePower extends ActionBool
{
	protected var m_TrueRecordName : String;
	default m_TrueRecordName = "Power";
	protected var m_FalseRecordName : String;
	default m_FalseRecordName = "Unpower";

	public function SetProperties( status : EDeviceStatus )
	{
		var unpowered : Bool;
		actionName = 'TogglePower';
		if( status == EDeviceStatus.UNPOWERED )
		{
			unpowered = true;
		}
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'TogglePower', unpowered, 'LocKey#258', 'LocKey#257' );
	}

	public function SetProperties( status : EDeviceStatus, nameOnTrue : TweakDBID, nameOnFalse : TweakDBID )
	{
		var unpowered : Bool;
		var record : weak< InteractionBase_Record >;
		var displayNameOnTrue : CName;
		var displayNameOnFalse : CName;
		if( status == EDeviceStatus.UNPOWERED )
		{
			unpowered = true;
		}
		actionName = 'TogglePower';
		if( !( TDBID.IsValid( nameOnTrue ) ) )
		{
			displayNameOnTrue = 'LocKey#258';
		}
		else
		{
			record = TweakDBInterface.GetInteractionBaseRecord( nameOnTrue );
			if( record )
			{
				m_TrueRecordName = record.Name();
				displayNameOnTrue = StringToName( LocKeyToString( record.Caption() ) );
			}
		}
		if( !( TDBID.IsValid( nameOnFalse ) ) )
		{
			displayNameOnFalse = 'LocKey#257';
		}
		else
		{
			record = TweakDBInterface.GetInteractionBaseRecord( nameOnFalse );
			if( record )
			{
				m_FalseRecordName = record.Name();
				displayNameOnFalse = StringToName( LocKeyToString( record.Caption() ) );
			}
		}
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( actionName, unpowered, displayNameOnTrue, displayNameOnFalse );
	}

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( IsAvailable( device ) && IsClearanceValid( context.clearance ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.GetDeviceStatusAction().GetStatusValue() == ( ( Int32 )( EDeviceStatus.DISABLED ) ) )
		{
			return false;
		}
		return true;
	}

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

	public override function GetTweakDBChoiceRecord() : String
	{
		if( !( ( ( Bool )prop.first ) ) )
		{
			return "Unpower";
		}
		else
		{
			return "Power";
		}
	}

}

class ToggleON extends ActionBool
{
	protected var m_TrueRecordName : String;
	default m_TrueRecordName = "On";
	protected var m_FalseRecordName : String;
	default m_FalseRecordName = "Off";

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

	public function SetProperties( status : EDeviceStatus )
	{
		var isOn : Bool;
		actionName = 'ToggleON';
		if( status == EDeviceStatus.ON )
		{
			isOn = true;
		}
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'ToggleOn', isOn, 'LocKey#255', 'LocKey#256' );
	}

	public function SetProperties( status : EDeviceStatus, nameOnTrue : TweakDBID, nameOnFalse : TweakDBID )
	{
		var isOn : Bool;
		var record : weak< InteractionBase_Record >;
		var displayNameOnTrue : CName;
		var displayNameOnFalse : CName;
		actionName = 'ToggleON';
		if( status == EDeviceStatus.ON )
		{
			isOn = true;
		}
		if( !( TDBID.IsValid( nameOnTrue ) ) )
		{
			displayNameOnTrue = 'LocKey#255';
		}
		else
		{
			record = TweakDBInterface.GetInteractionBaseRecord( nameOnTrue );
			if( record )
			{
				m_TrueRecordName = record.Name();
				displayNameOnTrue = StringToName( LocKeyToString( record.Caption() ) );
			}
		}
		if( !( TDBID.IsValid( nameOnFalse ) ) )
		{
			displayNameOnFalse = 'LocKey#256';
		}
		else
		{
			record = TweakDBInterface.GetInteractionBaseRecord( nameOnFalse );
			if( record )
			{
				m_FalseRecordName = record.Name();
				displayNameOnFalse = StringToName( LocKeyToString( record.Caption() ) );
			}
		}
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'ToggleOn', isOn, displayNameOnTrue, displayNameOnFalse );
	}

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( IsAvailable( device ) && IsClearanceValid( context.clearance ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.IsDisabled() || device.IsUnpowered() )
		{
			return false;
		}
		return true;
	}

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

	public override function GetTweakDBChoiceRecord() : String
	{
		if( !( ( ( Bool )prop.first ) ) )
		{
			return m_TrueRecordName;
		}
		else
		{
			return m_FalseRecordName;
		}
	}

	public override function GetInkWidgetTweakDBID() : TweakDBID
	{
		switch( m_widgetStyle )
		{
			case gamedataComputerUIStyle.Orange:
				return T"DevicesUIDefinitions.ToggleDeviceActionWidgetOA";
			default:
				return T"DevicesUIDefinitions.ToggleDeviceActionWidget";
		}
	}

	public override function GetActivationTime() : Float
	{
		if( IsQuickHack() )
		{
			return super.GetActivationTime();
		}
		return 0.0;
	}

}

class QuickHackToggleON extends ActionBool
{
	var Repeat : Bool;

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

	public const override function GetInteractionIcon() : weak< ChoiceCaptionIconPart_Record >
	{
		return TweakDBInterface.GetChoiceCaptionIconPartRecord( T"ChoiceCaptionParts.OnOff" );
	}

	public function SetProperties( status : EDeviceStatus )
	{
		var isOn : Bool;
		actionName = 'QuickHackToggleON';
		if( status == EDeviceStatus.ON )
		{
			isOn = true;
		}
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'ToggleOn', isOn, 'LocKey#256', 'LocKey#256' );
	}

	public override function GetTweakDBChoiceRecord() : String
	{
		if( TDBID.IsValid( m_objectActionID ) )
		{
			return super.GetTweakDBChoiceRecord();
		}
		else
		{
			if( !( ( ( Bool )prop.first ) ) )
			{
				return "On";
			}
			else
			{
				return "Off";
			}
		}
	}

}

class ToggleBlockade extends ActionBool
{
	protected var m_TrueRecordName : String;
	default m_TrueRecordName = "Raise";
	protected var m_FalseRecordName : String;
	default m_FalseRecordName = "Lower";

	public function SetProperties( isActive : Bool, nameOnTrue : TweakDBID, nameOnFalse : TweakDBID )
	{
		var record : weak< InteractionBase_Record >;
		var displayNameOnTrue : CName;
		var displayNameOnFalse : CName;
		actionName = 'ToggleBlockade';
		if( !( TDBID.IsValid( nameOnTrue ) ) )
		{
			nameOnTrue = T"Interactions.Raise";
		}
		if( !( TDBID.IsValid( nameOnFalse ) ) )
		{
			nameOnFalse = nameOnTrue = T"Interactions.Lower";
		}
		record = TweakDBInterface.GetInteractionBaseRecord( nameOnTrue );
		m_FalseRecordName = record.Name();
		displayNameOnTrue = StringToName( LocKeyToString( record.Caption() ) );
		record = TweakDBInterface.GetInteractionBaseRecord( nameOnFalse );
		m_TrueRecordName = record.Name();
		displayNameOnFalse = StringToName( LocKeyToString( record.Caption() ) );
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'ToggleBlockade', isActive, displayNameOnTrue, displayNameOnFalse );
	}

	public static function IsDefaultConditionMet( device : RoadBlockControllerPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( IsAvailable( device ) && IsClearanceValid( context.clearance ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : RoadBlockControllerPS ) : Bool
	{
		if( device.IsON() )
		{
			return true;
		}
		return false;
	}

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

	public override function GetTweakDBChoiceRecord() : String
	{
		if( !( ( ( Bool )prop.first ) ) )
		{
			return m_TrueRecordName;
		}
		else
		{
			return m_FalseRecordName;
		}
	}

}

class QuickHackToggleBlockade extends ToggleBlockade
{

	public override function GetTweakDBChoiceRecord() : String
	{
		var recordName : String;
		if( TDBID.IsValid( m_objectActionID ) )
		{
			recordName = GetObjectActionRecord().ObjectActionUI().Name();
		}
		if( IsStringValid( recordName ) )
		{
			return recordName;
		}
		else
		{
			return super.GetTweakDBChoiceRecord();
		}
	}

}

class QuestForceRoadBlockadeActivate extends ActionBool
{

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

}

class QuestForceRoadBlockadeDeactivate extends ActionBool
{

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

}

class QuestForceActivate extends ActionBool
{

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

}

class QuestForceDeactivate extends ActionBool
{

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

}

class QuickHackToggleActivate extends ToggleActivate
{
}

class QuestPickUpCall extends ActionBool
{

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

}

class QuestHangUpCall extends ActionBool
{

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

}

class ToggleActivate extends ActionBool
{
	protected var m_TrueRecordName : String;
	protected var m_FalseRecordName : String;

	public function SetProperties( activationStatus : EActivationState )
	{
		var isActivated : Bool;
		if( activationStatus == EActivationState.DEACTIVATED )
		{
			isActivated = false;
		}
		else
		{
			isActivated = true;
		}
		actionName = 'ToggleActivate';
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'ToggleActivate', isActivated, 'LocKey#233', 'LocKey#234' );
	}

	public function SetProperties( isActive : Bool, nameOnTrue : TweakDBID, nameOnFalse : TweakDBID )
	{
		var record : weak< InteractionBase_Record >;
		var displayNameOnTrue : CName;
		var displayNameOnFalse : CName;
		actionName = 'ToggleActivate';
		if( !( TDBID.IsValid( nameOnTrue ) ) )
		{
			nameOnTrue = T"Interactions.Activate";
		}
		if( !( TDBID.IsValid( nameOnFalse ) ) )
		{
			nameOnFalse = T"Interactions.Deactivate";
		}
		record = TweakDBInterface.GetInteractionBaseRecord( nameOnTrue );
		m_FalseRecordName = record.Name();
		displayNameOnTrue = StringToName( LocKeyToString( record.Caption() ) );
		record = TweakDBInterface.GetInteractionBaseRecord( nameOnFalse );
		m_TrueRecordName = record.Name();
		displayNameOnFalse = StringToName( LocKeyToString( record.Caption() ) );
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'ToggleActivate', isActive, displayNameOnTrue, displayNameOnFalse );
	}

	public override function GetTweakDBChoiceRecord() : String
	{
		if( TDBID.IsValid( m_objectActionID ) )
		{
			return super.GetTweakDBChoiceRecord();
		}
		else
		{
			if( !( ( ( Bool )prop.first ) ) )
			{
				return m_TrueRecordName;
			}
			else
			{
				return m_FalseRecordName;
			}
		}
	}

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

}

class ActivateDevice extends ActionBool
{
	var m_tweakDBChoiceName : String;

	public function SetProperties( optional action_name : CName )
	{
		var displayName : CName;
		actionName = 'ActivateDevice';
		if( IsNameValid( action_name ) )
		{
			displayName = action_name;
		}
		else
		{
			displayName = 'LocKey#233';
		}
		m_tweakDBChoiceName = NameToString( action_name );
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'ActivateDevice', true, displayName, displayName );
	}

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

}

class DeactivateDevice extends ActionBool
{

	public function SetProperties( optional action_name : CName )
	{
		if( action_name != '' )
		{
			actionName = action_name;
		}
		else
		{
			actionName = 'LocKey#234';
		}
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'DeactivateDevice', true, actionName, actionName );
	}

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

}

class AuthorizeUser extends ActionBool
{
	private var m_enteredPassword : CName;
	private var m_validPasswords : array< CName >;
	private var m_libraryName : CName;
	private var m_isforced : Bool;

	public function SetProperties( const validPasswords : ref< array< CName > >, optional isforced : Bool )
	{
		actionName = 'AuthorizeUser';
		m_validPasswords = validPasswords;
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( actionName, true, 'LocKey#17813', 'LocKey#17813' );
		m_isforced = isforced;
		if( m_isforced )
		{
			if( m_validPasswords.Size() > 0 )
			{
				m_enteredPassword = m_validPasswords[ 0 ];
			}
		}
	}

	public function IsForced() : Bool
	{
		return m_isforced;
	}

	public function GetEnteredPassword() : CName
	{
		return m_enteredPassword;
	}

	public override function ResolveAction( data : ResolveActionData ) : Bool
	{
		m_enteredPassword = StringToName( data.m_password );
		return true;
	}

	public function GetValidPasswords() : array< CName >
	{
		return m_validPasswords;
	}

	public function CreateActionWidgetPackage( authorizationWidgetName : CName, const authorizationDisplayNameOverride : ref< String > )
	{
		m_libraryName = authorizationWidgetName;
		super.CreateActionWidgetPackage();
		if( authorizationDisplayNameOverride != "" )
		{
			m_actionWidgetPackage.displayName = authorizationDisplayNameOverride;
		}
		else
		{
			m_actionWidgetPackage.displayName = "LocKey#210";
		}
	}

	public function CreateActionWidgetPackage( const authorizationDisplayNameOverride : ref< String > )
	{
		super.CreateActionWidgetPackage();
		if( IsStringValid( authorizationDisplayNameOverride ) )
		{
			m_actionWidgetPackage.displayName = authorizationDisplayNameOverride;
		}
	}

	public override function GetInkWidgetTweakDBID() : TweakDBID
	{
		if( m_libraryName == 'elevator' )
		{
			return T"DevicesUIDefinitions.AuthorizationBlockedActionWidget";
		}
		else
		{
			return super.GetInkWidgetTweakDBID();
		}
	}

}

class FactQuickHack extends ActionBool
{
	private var m_factProperties : ComputerQuickHackData;

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

	public override function GetTweakDBChoiceID() : TweakDBID
	{
		var id : TweakDBID;
		id = m_factProperties.alternativeName;
		return id;
	}

	public function GetFactProperties() : ComputerQuickHackData
	{
		return m_factProperties;
	}

	public function SetProperties( properties : ComputerQuickHackData )
	{
		m_factProperties = properties;
	}

}

class QuickHackAuthorization extends ActionBool
{

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

}

class SetAuthorizationModuleON extends ActionBool
{

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

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( IsAvailable( device ) && IsClearanceValid( context.clearance ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.HasAuthorizationModule() && !( device.IsAuthorizationModuleOn() ) )
		{
			return true;
		}
		return false;
	}

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

}

class SetAuthorizationModuleOFF extends ActionBool
{

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

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( IsAvailable( device ) && IsClearanceValid( context.clearance ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.HasAuthorizationModule() && device.IsAuthorizationModuleOn() )
		{
			return true;
		}
		return false;
	}

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

}

class InstallKeylogger extends ActionBool
{

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

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( IsAvailable( device ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.IsON() )
		{
			return true;
		}
		return false;
	}

}

class SetExposeQuickHacks extends ActionBool
{
	var isRemote : Bool;
	default isRemote = true;

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

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

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		return device.IsPowered();
	}

	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.Direct )
		{
			return true;
		}
		return false;
	}

}

enum EPersonalLinkConnectionStatus
{
	NOT_CONNECTED = 0,
	CONNECTING = 1,
	CONNECTED = 2,
	DISCONNECTING = 3,
}

class TogglePersonalLink extends ActionBool
{
	default m_duration = 2.733;
	var m_cachedStatus : EPersonalLinkConnectionStatus;
	var m_shouldSkipMiniGame : Bool;

	public function SetProperties( personalLinkStatus : EPersonalLinkConnectionStatus, shouldSkipMinigame : Bool )
	{
		var isPersonalLinkConnected : Bool;
		m_cachedStatus = personalLinkStatus;
		m_shouldSkipMiniGame = shouldSkipMinigame;
		if( m_cachedStatus == EPersonalLinkConnectionStatus.NOT_CONNECTED )
		{
			isPersonalLinkConnected = false;
		}
		else
		{
			isPersonalLinkConnected = true;
		}
		actionName = 'TogglePersonalLink';
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'Personal Link', isPersonalLinkConnected, 'LocKey#284', 'LocKey#285' );
	}

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( ( IsAvailable( device ) && IsClearanceValid( context.clearance ) ) && IsContextValid( context ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		return device.IsON() && device.HasPersonalLinkSlot();
	}

	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.Direct )
		{
			return true;
		}
		return false;
	}

	public function ShouldConnect() : Bool
	{
		var value : Bool;
		DeviceActionPropertyFunctions.GetProperty_Bool( prop, value );
		return value;
	}

	public override function GetTweakDBChoiceRecord() : String
	{
		var value : Bool;
		DeviceActionPropertyFunctions.GetProperty_Bool( prop, value );
		if( m_cachedStatus == EPersonalLinkConnectionStatus.NOT_CONNECTED )
		{
			if( m_shouldSkipMiniGame )
			{
				return "ConnectPersonalLinkNoMinigame";
			}
			else
			{
				return "ConnectPersonalLink";
			}
		}
		else
		{
			return "DisconnectPersonalLink";
		}
	}

	public const override function GetInteractionIcon() : weak< ChoiceCaptionIconPart_Record >
	{
		return TweakDBInterface.GetChoiceCaptionIconPartRecord( T"ChoiceCaptionParts.JackInIcon" );
	}

}

class OpenFullscreenUI extends ActionBool
{

	public function SetProperties( isZoomInteraction : Bool )
	{
		actionName = 'OpenFullscreenUI';
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'Zoom Interaction', isZoomInteraction, 'LocKey#288', 'LocKey#289' );
	}

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		return ( IsAvailable( device ) && IsClearanceValid( context.clearance ) ) && IsContextValid( context );
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		return device.IsPowered();
	}

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

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

	public function ShouldConnect() : Bool
	{
		var value : Bool;
		DeviceActionPropertyFunctions.GetProperty_Bool( prop, value );
		return !( value );
	}

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

}

class SpiderbotDistraction extends ActionBool
{

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

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

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( !( AIActionHelper.CheckFlatheadStatPoolRequirements( device.GetGameInstance(), "DeviceAction" ) ) )
		{
			return false;
		}
		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 SpiderbotBoolAction extends ActionBool
{
	protected var m_TrueRecord : String;
	default m_TrueRecord = "SpiderbotToggleOn";
	protected var m_FalseRecord : String;
	default m_FalseRecord = "SpiderbotToggleOff";

	public function SetProperties( status : EDeviceStatus )
	{
		var isOn : Bool;
		actionName = 'SpiderbotToggleON';
		if( status == EDeviceStatus.ON )
		{
			isOn = true;
		}
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( actionName, isOn, 'LocKey#255', 'LocKey#256' );
	}

	public function SetProperties( status : EDeviceStatus, nameOnTrue : CName, nameOnFalse : CName )
	{
		var isOn : Bool;
		actionName = 'SpiderbotToggleON';
		if( status == EDeviceStatus.ON )
		{
			isOn = true;
		}
		if( !( IsNameValid( nameOnTrue ) ) )
		{
			nameOnTrue = 'LocKey#255';
		}
		else
		{
			m_TrueRecord = NameToString( nameOnTrue );
		}
		if( !( IsNameValid( nameOnFalse ) ) )
		{
			nameOnFalse = 'LocKey#256';
		}
		else
		{
			m_FalseRecord = NameToString( nameOnFalse );
		}
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( actionName, isOn, nameOnTrue, nameOnFalse );
	}

	public override function GetTweakDBChoiceRecord() : String
	{
		if( !( ( ( Bool )prop.first ) ) )
		{
			return m_TrueRecord;
		}
		else
		{
			return m_FalseRecord;
		}
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( !( AIActionHelper.CheckFlatheadStatPoolRequirements( device.GetGameInstance(), "DeviceAction" ) ) )
		{
			return false;
		}
		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 ToggleZoomInteraction extends ActionBool
{

	public function SetProperties( isZoomInteraction : Bool )
	{
		actionName = 'ToggleZoomInteraction';
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'Zoom Interaction', isZoomInteraction, 'LocKey#288', 'LocKey#289' );
	}

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		return ( IsAvailable( device ) && IsClearanceValid( context.clearance ) ) && IsContextValid( context );
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		return device.IsPowered();
	}

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

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

	public function ShouldConnect() : Bool
	{
		var value : Bool;
		DeviceActionPropertyFunctions.GetProperty_Bool( prop, value );
		return !( value );
	}

	public override function GetTweakDBChoiceRecord() : String
	{
		var value : Bool;
		DeviceActionPropertyFunctions.GetProperty_Bool( prop, value );
		if( !( value ) )
		{
			return "EnterZoomInteraction";
		}
		else
		{
			return "ExitZoomInteraction";
		}
	}

}

class SetDeviceAttitude extends ActionBool
{
	var Repeat : Bool;
	var IgnoreHostiles : Bool;
	var Attitude : EAIAttitude;

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

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

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

	public const override function GetInteractionIcon() : weak< ChoiceCaptionIconPart_Record >
	{
		return TweakDBInterface.GetChoiceCaptionIconPartRecord( T"ChoiceCaptionParts.ChangeToFriendlyIcon" );
	}

}

class ThumbnailUI extends ActionBool
{
	protected var m_thumbnailWidgetPackage : SThumbnailWidgetPackage;

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

	public virtual function CreateThumbnailWidgetPackage( optional status : String )
	{
		m_thumbnailWidgetPackage.libraryPath = GetInkWidgetLibraryPath();
		m_thumbnailWidgetPackage.libraryID = GetInkWidgetLibraryID();
		m_thumbnailWidgetPackage.widgetName = ( ( String )( GetActionName() ) );
		m_thumbnailWidgetPackage.displayName = GetDeviceName();
		m_thumbnailWidgetPackage.deviceStatus = status;
		m_thumbnailWidgetPackage.widgetTweakDBID = GetInkWidgetTweakDBID();
		ResolveThumbnailWidgetTweakDBData();
	}

	public virtual function CreateThumbnailWidgetPackage( widgetTweakDBID : TweakDBID, optional status : String )
	{
		CreateThumbnailWidgetPackage( status );
		if( TDBID.IsValid( widgetTweakDBID ) )
		{
			m_thumbnailWidgetPackage.widgetTweakDBID = widgetTweakDBID;
			ResolveThumbnailWidgetTweakDBData();
		}
	}

	public override function GetInkWidgetLibraryPath() : ResRef
	{
		return R"";
	}

	public override function GetInkWidgetLibraryID() : CName
	{
		return '';
	}

	public override function GetInkWidgetTweakDBID() : TweakDBID
	{
		switch( m_widgetStyle )
		{
			case gamedataComputerUIStyle.Orange:
				return T"DevicesUIDefinitions.GenericDeviceThumnbnailWidgetOA";
			default:
				return T"DevicesUIDefinitions.GenericDeviceThumnbnailWidget";
		}
	}

	public function GetThumbnailWidgetPackage() : SThumbnailWidgetPackage
	{
		var widgetPackage : SThumbnailWidgetPackage;
		widgetPackage.thumbnailAction = this;
		if( !( TDBID.IsValid( m_thumbnailWidgetPackage.widgetTweakDBID ) ) )
		{
			widgetPackage.widgetTweakDBID = GetInkWidgetTweakDBID();
			ResolveThumbnailWidgetTweakDBData();
		}
		else
		{
			widgetPackage.widgetTweakDBID = m_thumbnailWidgetPackage.widgetTweakDBID;
		}
		widgetPackage.libraryID = m_thumbnailWidgetPackage.libraryID;
		widgetPackage.widgetName = m_thumbnailWidgetPackage.widgetName;
		widgetPackage.displayName = m_thumbnailWidgetPackage.displayName;
		widgetPackage.deviceStatus = m_thumbnailWidgetPackage.deviceStatus;
		widgetPackage.widgetTweakDBID = m_thumbnailWidgetPackage.widgetTweakDBID;
		widgetPackage.libraryPath = m_thumbnailWidgetPackage.libraryPath;
		widgetPackage.isValid = ResRef.IsValid( widgetPackage.libraryPath ) || IsNameValid( widgetPackage.libraryID );
		return widgetPackage;
	}

	private function ResolveThumbnailWidgetTweakDBData()
	{
		var record : WidgetDefinition_Record;
		if( TDBID.IsValid( m_thumbnailWidgetPackage.widgetTweakDBID ) )
		{
			record = TweakDBInterface.GetWidgetDefinitionRecord( m_thumbnailWidgetPackage.widgetTweakDBID );
			if( record != NULL )
			{
				m_thumbnailWidgetPackage.libraryPath = record.LibraryPath();
				m_thumbnailWidgetPackage.libraryID = StringToName( record.LibraryID() );
			}
		}
	}

}

class ResolveSkillchecksEvent extends Event
{
}

class QuestResetDeviceToInitialState extends ActionBool
{

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

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

}

class QuestForceCameraZoom extends ActionBool
{
	private var m_useWorkspot : Bool;
	default m_useWorkspot = true;
	private var m_instant : Bool;

	public function SetProperties( enable : Bool, optional instant : Bool )
	{
		if( enable )
		{
			actionName = 'QuestForceEnableCameraZoom';
		}
		else
		{
			actionName = 'QuestForceDisableCameraZoom';
		}
		m_instant = instant;
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( actionName, enable, 'QuestForceEnableCameraZoom', 'QuestForceDisableCameraZoom' );
	}

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

	public const function UseWorkspot() : Bool
	{
		return m_useWorkspot;
	}

	public function SetUseWorkspot( useWorkspot : Bool )
	{
		m_useWorkspot = useWorkspot;
	}

	public const function IsInstant() : Bool
	{
		return m_instant;
	}

}

class PlayDeafeningMusic extends ActionBool
{

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

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( IsAvailable( device ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.IsON() || device.IsOFF() )
		{
			return true;
		}
		return false;
	}

	public const override function GetInteractionIcon() : weak< ChoiceCaptionIconPart_Record >
	{
		return TweakDBInterface.GetChoiceCaptionIconPartRecord( T"ChoiceCaptionParts.DistractIcon" );
	}

}

class ChangeMusicAction extends ActionBool
{
	protected var m_interactionRecordName : String;
	default m_interactionRecordName = "NextStation";
	var m_settings : MusicSettings;

	public function SetProperties( settings : MusicSettings )
	{
		actionName = 'NextStation';
		m_settings = settings;
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'Next Station', true, 'LocKey#252', 'LocKey#252' );
	}

	public function SetProperties( settings : MusicSettings, nameOnTrue : TweakDBID )
	{
		var record : weak< InteractionBase_Record >;
		var displayName : CName;
		m_settings = settings;
		if( !( TDBID.IsValid( nameOnTrue ) ) )
		{
			displayName = 'LocKey#252';
			actionName = 'NextStation';
		}
		else
		{
			record = TweakDBInterface.GetInteractionBaseRecord( nameOnTrue );
			m_interactionRecordName = record.Name();
			actionName = StringToName( m_interactionRecordName );
			displayName = StringToName( LocKeyToString( record.Caption() ) );
		}
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( actionName, true, displayName, displayName );
	}

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

	public function GetMusicSettings() : MusicSettings
	{
		return m_settings;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( !( AIActionHelper.CheckFlatheadStatPoolRequirements( device.GetGameInstance(), "DeviceAction" ) ) )
		{
			return false;
		}
		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 StartCall extends ActionBool
{

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

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

	public override function GetInkWidgetTweakDBID() : TweakDBID
	{
		return T"DevicesUIDefinitions.IntercomCallActionWidget";
	}

}

class Flush extends ActionBool
{

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

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

}

class ToggleGlassTint extends ActionBool
{
	default actionName = 'ToggleTint';
	protected var m_TrueRecord : String;
	default m_TrueRecord = "TintGlass";
	protected var m_FalseRecord : String;
	default m_FalseRecord = "ClearGlass";

	public function SetProperties( isActive : Bool )
	{
		var record : TweakDBID;
		var nameOnTrue : CName;
		var nameOnFalse : CName;
		record = TDBID.Create( "Interactions." + m_TrueRecord );
		nameOnTrue = StringToName( TweakDBInterface.GetInteractionBaseRecord( record ).Name() );
		record = TDBID.Create( "Interactions." + m_FalseRecord );
		nameOnFalse = StringToName( TweakDBInterface.GetInteractionBaseRecord( record ).Name() );
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( actionName, isActive, nameOnTrue, nameOnFalse );
	}

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( IsAvailable( device ) && IsClearanceValid( context.clearance ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.IsON() )
		{
			return true;
		}
		return false;
	}

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

	public override function GetTweakDBChoiceRecord() : String
	{
		if( TDBID.IsValid( m_objectActionID ) )
		{
			return super.GetTweakDBChoiceRecord();
		}
		else
		{
			if( !( ( ( Bool )prop.first ) ) )
			{
				return m_TrueRecord;
			}
			else
			{
				return m_FalseRecord;
			}
		}
	}

}

class ToggleGlassTintHack extends ToggleGlassTint
{
	default actionName = 'ToggleGlassTintHack';
}

class QuestForceTintGlass extends ActionBool
{

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

}

class QuestForceClearGlass extends ActionBool
{

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

}

class PresetAction extends ActionBool
{
	protected var m_preset : SmartHousePreset;

	public function SetProperties( preset : SmartHousePreset )
	{
		actionName = preset.GetClassName();
		m_preset = preset;
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'SmartHousePreset', true, GetDisplayName(), GetDisplayName() );
	}

	public function GetPreset() : SmartHousePreset
	{
		return m_preset;
	}

	protected function GetDisplayName() : CName
	{
		return m_preset.GetPresetName();
	}

	public override function CreateActionWidgetPackage( optional actions : array< DeviceAction > )
	{
		super.CreateActionWidgetPackage( actions );
		m_actionWidgetPackage.iconID = m_preset.GetIconName();
	}

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( IsAvailable( device ) && IsClearanceValid( context.clearance ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( !( device.IsON() ) )
		{
			return false;
		}
		return true;
	}

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

	public override function GetInkWidgetTweakDBID() : TweakDBID
	{
		return T"DevicesUIDefinitions.SmartHousePresetWidget";
	}

}

class ToggleAlarm extends ActionBool
{

	public function SetProperties( status : ESecuritySystemState )
	{
		var isOn : Bool;
		actionName = 'ToggleAlarm';
		if( status != ESecuritySystemState.SAFE )
		{
			isOn = true;
		}
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'ToggleAlarm', isOn, 'LocKey#346', 'LocKey#345' );
	}

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

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.IsON() )
		{
			return true;
		}
		return false;
	}

	public override function GetTweakDBChoiceRecord() : String
	{
		if( TDBID.IsValid( m_objectActionID ) )
		{
			return super.GetTweakDBChoiceRecord();
		}
		else
		{
			if( !( ( ( Bool )prop.first ) ) )
			{
				return "TurnOnCarAlarm";
			}
			else
			{
				return "TurnOffCarAlarm";
			}
		}
	}

}

class SecurityAlarmBreachResponse extends ActionBool
{
	private var m_currentSecurityState : ESecuritySystemState;

	public function SetProperties( currentSecuritySystemState : ESecuritySystemState )
	{
		actionName = 'SecurityAlarmBreachResponse';
		m_currentSecurityState = currentSecuritySystemState;
	}

	public const function GetSecurityState() : ESecuritySystemState
	{
		return m_currentSecurityState;
	}

}

class SecurityAlarmEscalate extends ActionBool
{

	public function SetProperties()
	{
		actionName = 'StartAlarm';
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'StartAlarm', true, 'LocKey#340', 'LocKey#344' );
	}

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

}

class MasterDeviceDestroyed extends ActionBool
{

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

}

class DelayEvent extends ActionBool
{

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

}

class Distraction extends ActionBool
{

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

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

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( device.IsPowered() )
		{
			return true;
		}
		else
		{
			return false;
		}
	}

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

}

class TogglePlay extends ActionBool
{

	public function SetProperties( isPlaying : Bool )
	{
		actionName = 'TogglePlay';
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'Play', isPlaying, 'LocKey#280', 'LocKey#281' );
	}

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( IsAvailable( device ) && IsClearanceValid( context.clearance ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.IsDisabled() )
		{
			return false;
		}
		if( device.IsUnpowered() )
		{
			return false;
		}
		if( device.IsDeviceSecured() )
		{
			return false;
		}
		if( !( device.IsON() ) )
		{
			return false;
		}
		return true;
	}

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

	public override function GetInkWidgetTweakDBID() : TweakDBID
	{
		return T"DevicesUIDefinitions.JukeboxPlayActionWidget";
	}

}

class OpenInteriorManager extends ActionBool
{

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

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

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

}

class EnterLadder extends ActionBool
{

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

	public static function IsPlayerInAcceptableState( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		var playerSMBlackboard : IBlackboard;
		var isUsingLadder : Bool;
		var isJumping : Bool;
		playerSMBlackboard = GetPlayerStateMachine( context.processInitiatorObject );
		isUsingLadder = ( ( ( playerSMBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.LocomotionDetailed ) == ( ( Int32 )( gamePSMDetailedLocomotionStates.Ladder ) ) ) || ( playerSMBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.LocomotionDetailed ) == ( ( Int32 )( gamePSMDetailedLocomotionStates.LadderSprint ) ) ) ) || ( playerSMBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.LocomotionDetailed ) == ( ( Int32 )( gamePSMDetailedLocomotionStates.LadderSlide ) ) ) ) || ( playerSMBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.LocomotionDetailed ) == ( ( Int32 )( gamePSMDetailedLocomotionStates.LadderJump ) ) );
		isJumping = playerSMBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.Locomotion ) == ( ( Int32 )( gamePSMLocomotionStates.Jump ) );
		if( isUsingLadder )
		{
			return false;
		}
		if( isJumping )
		{
			return false;
		}
		if( playerSMBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.HighLevel ) != ( ( Int32 )( gamePSMHighLevel.SceneTier1 ) ) )
		{
			return false;
		}
		if( playerSMBlackboard.GetBool( GetAllBlackboardDefs().PlayerStateMachine.Carrying ) )
		{
			return false;
		}
		if( playerSMBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.Takedown ) != ( ( Int32 )( gamePSMTakedown.Default ) ) )
		{
			return false;
		}
		if( StatusEffectSystem.ObjectHasStatusEffectWithTag( context.processInitiatorObject, 'NoWorldInteractions' ) )
		{
			return false;
		}
		return true;
	}

	public static function PushOnEnterLadderEventToPSM( requester : GameObject )
	{
		var psmEvent : PSMPostponedParameterBool;
		psmEvent = new PSMPostponedParameterBool;
		psmEvent.id = 'actionEnterLadder';
		psmEvent.value = true;
		requester.QueueEvent( psmEvent );
	}

	public static function GetPlayerStateMachine( requester : GameObject ) : IBlackboard
	{
		var playerStateMachineBlackboard : IBlackboard;
		var playerPuppet : PlayerPuppet;
		playerPuppet = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( requester.GetGame() ).GetLocalPlayerMainGameObject() ) );
		playerStateMachineBlackboard = GameInstance.GetBlackboardSystem( requester.GetGame() ).GetLocalInstanced( playerPuppet.GetEntityID(), GetAllBlackboardDefs().PlayerStateMachine );
		return playerStateMachineBlackboard;
	}

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

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

}

class ProgramSetDeviceOff extends ActionBool
{

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

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

}

class ProgramSetDeviceAttitude extends ActionBool
{

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

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

}

class QuestResetPerformedActionsStorage extends ActionBool
{

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

}

class TargetAcquiredEvent extends Event
{
	var target : weak< ScriptedPuppet >;
}

class TargetLostEvent extends Event
{
	var target : weak< ScriptedPuppet >;
}

