class ToggleOperationEvent extends Event
{
	var enable : Bool;
	var index : Int32;
	var type : EOperationClassType;
}

class DelayedOperationEvent extends Event
{
	var operationHandler : DeviceOperations;
	var operation : SBaseDeviceOperationData;
}

enum EOperationClassType
{
	Local = 0,
	BaseState = 1,
	DoorState = 2,
	BaseAction = 3,
	CustomActions = 4,
	TriggerVolume = 5,
	Hit = 6,
	InteractionArea = 7,
	Senses = 8,
	FocusMode = 9,
}

enum ETriggerOperationType
{
	ENTER = 0,
	EXIT = 1,
}

enum EWorkspotOperationType
{
	ENTER = 0,
	LEAVE = 1,
}

enum EEffectOperationType
{
	START = 0,
	STOP = 1,
	BRAKE_LOOP = 2,
}

enum ETransformAnimationOperationType
{
	PLAY = 0,
	PAUSE = 1,
	RESET = 2,
	SKIP = 3,
}

enum EItemOperationType
{
	ADD = 0,
	REMOVE = 1,
}

enum EBinkOperationType
{
	PLAY = 0,
	STOP = 1,
	PAUSE = 2,
	RESUME = 3,
}

struct SVfxInstanceData
{
	var fx : FxInstance;
	var id : CName;
}

struct SToggleOperationData
{
	instanceeditable var index : Int32;
	instanceeditable var enable : Bool;
	instanceeditable var classType : EOperationClassType;
}

struct STransformAnimationData
{
	instanceeditable var animationName : CName;
	instanceeditable var operationType : ETransformAnimationOperationType;
	instanceeditable var playData : STransformAnimationPlayEventData;
	instanceeditable var skipData : STransformAnimationSkipEventData;
}

struct STeleportOperationData
{
	instanceeditable var nodeRef : NodeRef;
}

struct STransformAnimationPlayEventData
{
	instanceeditable var timeScale : Float;
	default timeScale = 1;
	instanceeditable var looping : Bool;
	instanceeditable var timesPlayed : Uint32;
	default timesPlayed = 1;
}

struct STransformAnimationSkipEventData
{
	instanceeditable var time : Float;
	instanceeditable var skipToEnd : Bool;
}

struct SBinkperationData
{
	instanceeditable var componentName : CName;
	instanceeditable var binkPath : ResRef;
	instanceeditable var loop : Bool;
	instanceeditable var operationType : EBinkOperationType;
}

struct SVFXOperationData
{
	instanceeditable var vfxName : CName;
	instanceeditable var vfxResource : FxResource;
	instanceeditable var shouldPersist : Bool;
	[ rangeMin = "0.f" ][ rangeMax = "1.f" ]
	instanceeditable var size : Float;
	instanceeditable var nodeRef : NodeRef;
	instanceeditable var operationType : EEffectOperationType;
}

struct SSFXOperationData
{
	[ customEditor = "AudioEvent" ]
	instanceeditable var sfxName : CName;
	instanceeditable var operationType : EEffectOperationType;
}

struct SWorkspotData
{
	instanceeditable var componentName : CName;
	instanceeditable var freeCamera : Bool;
	instanceeditable var operationType : EWorkspotOperationType;
}

struct SStimOperationData
{
	instanceeditable var stimType : DeviceStimType;
	default stimType = DeviceStimType.Distract;
	instanceeditable var lifeTime : Float;
	default lifeTime = 3f;
	instanceeditable var radius : Float;
	default radius = 5.f;
	instanceeditable var operationType : EEffectOperationType;
	instanceeditable var nodeRef : NodeRef;
}

struct SStatusEffectOperationData
{
	instanceeditable var range : Float;
	default range = 1.f;
	instanceeditable var duration : Float;
	instanceeditable var offset : Vector4;
	instanceeditable var effect : StatusEffectTDBPicker;
}

struct SDamageOperationData
{
	instanceeditable var range : Float;
	default range = -1.f;
	instanceeditable var offset : Vector4;
	[ customEditor = "TweakDBGroupInheritance;Attacks.DeviceAttack" ]
	instanceeditable var damageType : TweakDBID;
}

struct SBaseDeviceOperationData
{
	instanceeditable var delay : Float;
	instanceeditable var resetDelay : Bool;
	instanceeditable var executeOnce : Bool;
	instanceeditable var isEnabled : Bool;
	default isEnabled = true;
	const instanceeditable var transformAnimations : array< STransformAnimationData >;
	const instanceeditable var VFXs : array< SVFXOperationData >;
	const instanceeditable var SFXs : array< SSFXOperationData >;
	const instanceeditable var facts : array< SFactOperationData >;
	const instanceeditable var components : array< SComponentOperationData >;
	const instanceeditable var stims : array< SStimOperationData >;
	const instanceeditable var statusEffects : array< SStatusEffectOperationData >;
	const instanceeditable var damages : array< SDamageOperationData >;
	const instanceeditable var items : array< SInventoryOperationData >;
	instanceeditable var teleport : STeleportOperationData;
	instanceeditable var meshesAppearence : CName;
	instanceeditable var playerWorkspot : SWorkspotData;
	instanceeditable var disableDevice : Bool;
	const instanceeditable var toggleOperations : array< SToggleOperationData >;
	var id : Int32;
	var delayID : DelayID;
	var isDelayActive : Bool;
}

struct SInventoryOperationData
{
	[ category = "Trigger Data" ][ customEditor = "TweakDBGroupInheritance;Item" ]
	instanceeditable var itemName : TweakDBID;
	[ category = "Trigger Data" ]
	instanceeditable var quantity : Int32;
	instanceeditable var operationType : EItemOperationType;
}

struct SBaseStateOperationData
{
	[ category = "Trigger Data" ]
	instanceeditable var state : EDeviceStatus;
	instanceeditable var operation : SBaseDeviceOperationData;
}

struct SDoorStateOperationData
{
	[ category = "Trigger Data" ]
	instanceeditable var state : EDoorStatus;
	instanceeditable var operation : SBaseDeviceOperationData;
}

struct SBaseActionOperationData
{
	[ category = "Trigger Data" ]
	instanceeditable inlined var action : ScriptableDeviceAction;
	instanceeditable var operation : SBaseDeviceOperationData;
}

struct SCustomActionOperationData
{
	[ category = "Trigger Data" ]
	instanceeditable var actionID : CName;
	instanceeditable var operation : SBaseDeviceOperationData;
}

struct STriggerVolumeOperationData
{
	[ category = "Trigger Data" ]
	instanceeditable var isActivatorPlayer : Bool;
	[ category = "Trigger Data" ]
	instanceeditable var isActivatorNPC : Bool;
	[ category = "Trigger Data" ]
	instanceeditable var componentName : CName;
	[ category = "Trigger Data" ]
	instanceeditable var operationType : ETriggerOperationType;
	instanceeditable var operation : SBaseDeviceOperationData;
}

struct SInteractionAreaOperationData
{
	[ category = "Trigger Data" ]
	instanceeditable var isActivatorPlayer : Bool;
	[ category = "Trigger Data" ]
	instanceeditable var isActivatorNPC : Bool;
	[ category = "Trigger Data" ]
	instanceeditable var areaTag : CName;
	[ category = "Trigger Data" ]
	instanceeditable var operationType : gameinteractionsEInteractionEventType;
	instanceeditable var operation : SBaseDeviceOperationData;
}

struct SHitOperationData
{
	[ category = "Trigger Data" ]
	instanceeditable var isAttackerPlayer : Bool;
	default isAttackerPlayer = true;
	[ category = "Trigger Data" ]
	instanceeditable var isAttackerNPC : Bool;
	[ category = "Trigger Data" ]
	instanceeditable var bullets : Bool;
	default bullets = true;
	[ category = "Trigger Data" ]
	instanceeditable var explosions : Bool;
	[ category = "Trigger Data" ]
	instanceeditable var melee : Bool;
	[ category = "Trigger Data" ][ rangeMin = "0.f" ][ rangeMax = "100.f" ]
	instanceeditable var healthPercentage : Float;
	default healthPercentage = 100.0f;
	instanceeditable var operation : SBaseDeviceOperationData;
}

struct SSensesOperationData
{
	[ category = "Trigger Data" ]
	instanceeditable var isActivatorPlayer : Bool;
	[ category = "Trigger Data" ]
	instanceeditable var isActivatorNPC : Bool;
	[ category = "Trigger Data" ]
	instanceeditable var attitudeGroup : CName;
	[ category = "Trigger Data" ]
	instanceeditable var operationType : ETriggerOperationType;
	instanceeditable var operation : SBaseDeviceOperationData;
}

struct SFocusModeOperationData
{
	[ category = "Trigger Data" ]
	instanceeditable var operationType : ETriggerOperationType;
	[ category = "Trigger Data" ]
	instanceeditable var isLookedAt : Bool;
	default isLookedAt = true;
	instanceeditable var operation : SBaseDeviceOperationData;
}

class FocusModeOperations extends DeviceOperations
{
	protected const instanceeditable var m_focusModeOperations : array< SFocusModeOperationData >;

	public override function RequestComponents( ri : EntityRequestComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var componentName : CName;
		for( i = 0; i < m_focusModeOperations.Size(); i += 1 )
		{
			m_focusModeOperations[ i ].operation.id = i;
			for( k = 0; k < m_focusModeOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_focusModeOperations[ i ].operation.components[ k ].componentName;
				EntityRequestComponentsInterface.RequestComponent( ri, componentName, 'IPlacedComponent', false );
			}
		}
	}

	public override function TakeControl( ri : EntityResolveComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var component : weak< IPlacedComponent >;
		var componentName : CName;
		for( i = 0; i < m_focusModeOperations.Size(); i += 1 )
		{
			for( k = 0; k < m_focusModeOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_focusModeOperations[ i ].operation.components[ k ].componentName;
				component = ( ( IPlacedComponent )( EntityResolveComponentsInterface.GetComponent( ri, componentName ) ) );
				if( ( component != NULL ) && !( m_components.Contains( component ) ) )
				{
					m_components.PushBack( component );
				}
			}
		}
	}

	public override function ToggleOperation( enable : Bool, index : Int32 )
	{
		if( ( index >= 0 ) && ( index < m_focusModeOperations.Size() ) )
		{
			m_focusModeOperations[ index ].operation.isEnabled = enable;
		}
	}

	public const override function IsOperationEnabled( index : Int32 ) : Bool
	{
		if( ( index >= 0 ) && ( index < m_focusModeOperations.Size() ) )
		{
			return m_focusModeOperations[ index ].operation.isEnabled;
		}
		return false;
	}

	public override function SetDelayIdOnOperation( delayId : DelayID, operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_focusModeOperations.Size() ) )
		{
			m_focusModeOperations[ operationID ].operation.delayID = delayId;
			m_focusModeOperations[ operationID ].operation.isDelayActive = true;
		}
	}

	public override function ClearDelayIdOnOperation( operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_focusModeOperations.Size() ) )
		{
			m_focusModeOperations[ operationID ].operation.isDelayActive = false;
		}
	}

	public function ExecuteOperation( owner : weak< GameObject >, operationType : ETriggerOperationType )
	{
		var i : Int32;
		for( i = 0; i < m_focusModeOperations.Size(); i += 1 )
		{
			if( m_focusModeOperations[ i ].operationType == operationType )
			{
				if( ( m_focusModeOperations[ i ].operationType == ETriggerOperationType.ENTER && m_focusModeOperations[ i ].isLookedAt ) && !( IsLookedAt( owner ) ) )
				{
					return;
				}
				Execute( m_focusModeOperations[ i ].operation, owner );
			}
		}
	}

	public function RestoreOperation( owner : weak< GameObject >, operationType : ETriggerOperationType )
	{
		var i : Int32;
		for( i = 0; i < m_focusModeOperations.Size(); i += 1 )
		{
			if( m_focusModeOperations[ i ].operationType == operationType )
			{
				Restore( m_focusModeOperations[ i ].operation, owner );
			}
		}
	}

	private function IsLookedAt( object : GameObject ) : Bool
	{
		var lookedAtObect : GameObject;
		lookedAtObect = GameInstance.GetTargetingSystem( object.GetGame() ).GetLookAtObject( ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( object.GetGame() ).GetLocalPlayerMainGameObject() ) ) );
		return lookedAtObect == object;
	}

}

class SensesOperations extends DeviceOperations
{
	protected const instanceeditable var m_sensesOperations : array< SSensesOperationData >;

	public override function RequestComponents( ri : EntityRequestComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var componentName : CName;
		for( i = 0; i < m_sensesOperations.Size(); i += 1 )
		{
			m_sensesOperations[ i ].operation.id = i;
			for( k = 0; k < m_sensesOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_sensesOperations[ i ].operation.components[ k ].componentName;
				EntityRequestComponentsInterface.RequestComponent( ri, componentName, 'IPlacedComponent', false );
			}
		}
	}

	public override function TakeControl( ri : EntityResolveComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var component : weak< IPlacedComponent >;
		var componentName : CName;
		for( i = 0; i < m_sensesOperations.Size(); i += 1 )
		{
			for( k = 0; k < m_sensesOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_sensesOperations[ i ].operation.components[ k ].componentName;
				component = ( ( IPlacedComponent )( EntityResolveComponentsInterface.GetComponent( ri, componentName ) ) );
				if( ( component != NULL ) && !( m_components.Contains( component ) ) )
				{
					m_components.PushBack( component );
				}
			}
		}
	}

	public override function ToggleOperation( enable : Bool, index : Int32 )
	{
		if( ( index >= 0 ) && ( index < m_sensesOperations.Size() ) )
		{
			m_sensesOperations[ index ].operation.isEnabled = enable;
		}
	}

	public const override function IsOperationEnabled( index : Int32 ) : Bool
	{
		if( ( index >= 0 ) && ( index < m_sensesOperations.Size() ) )
		{
			return m_sensesOperations[ index ].operation.isEnabled;
		}
		return false;
	}

	public override function SetDelayIdOnOperation( delayId : DelayID, operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_sensesOperations.Size() ) )
		{
			m_sensesOperations[ operationID ].operation.delayID = delayId;
			m_sensesOperations[ operationID ].operation.isDelayActive = true;
		}
	}

	public override function ClearDelayIdOnOperation( operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_sensesOperations.Size() ) )
		{
			m_sensesOperations[ operationID ].operation.isDelayActive = false;
		}
	}

	public function ExecuteOperation( owner : weak< GameObject >, activator : weak< GameObject >, operationType : ETriggerOperationType )
	{
		var i : Int32;
		var attitudeGroup : CName;
		var attitudeAgent : AttitudeAgent;
		for( i = 0; i < m_sensesOperations.Size(); i += 1 )
		{
			if( m_sensesOperations[ i ].operationType == operationType )
			{
				if( ( ( PlayerPuppet )( activator ) ) && m_sensesOperations[ i ].isActivatorPlayer )
				{
					Execute( m_sensesOperations[ i ].operation, owner );
				}
				else if( ( ( ( PlayerPuppet )( activator ) ) == NULL ) && m_sensesOperations[ i ].isActivatorNPC )
				{
					if( IsNameValid( m_sensesOperations[ i ].attitudeGroup ) )
					{
						attitudeAgent = activator.GetAttitudeAgent();
						if( attitudeAgent != NULL )
						{
							attitudeGroup = attitudeAgent.GetAttitudeGroup();
							if( attitudeGroup != m_sensesOperations[ i ].attitudeGroup )
							{
								return;
							}
						}
					}
					Execute( m_sensesOperations[ i ].operation, owner );
				}
			}
		}
	}

	public function RestoreOperation( owner : weak< GameObject >, activator : weak< GameObject >, operationType : ETriggerOperationType )
	{
		var i : Int32;
		for( i = 0; i < m_sensesOperations.Size(); i += 1 )
		{
			if( m_sensesOperations[ i ].operationType == operationType )
			{
				Restore( m_sensesOperations[ i ].operation, owner );
			}
		}
	}

}

class HitOperations extends DeviceOperations
{
	protected const instanceeditable var m_hitOperations : array< SHitOperationData >;

	public override function RequestComponents( ri : EntityRequestComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var componentName : CName;
		for( i = 0; i < m_hitOperations.Size(); i += 1 )
		{
			m_hitOperations[ i ].operation.id = i;
			for( k = 0; k < m_hitOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_hitOperations[ i ].operation.components[ k ].componentName;
				EntityRequestComponentsInterface.RequestComponent( ri, componentName, 'IPlacedComponent', false );
			}
		}
	}

	public override function TakeControl( ri : EntityResolveComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var component : weak< IPlacedComponent >;
		var componentName : CName;
		for( i = 0; i < m_hitOperations.Size(); i += 1 )
		{
			for( k = 0; k < m_hitOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_hitOperations[ i ].operation.components[ k ].componentName;
				component = ( ( IPlacedComponent )( EntityResolveComponentsInterface.GetComponent( ri, componentName ) ) );
				if( ( component != NULL ) && !( m_components.Contains( component ) ) )
				{
					m_components.PushBack( component );
				}
			}
		}
	}

	public override function ToggleOperation( enable : Bool, index : Int32 )
	{
		if( ( index >= 0 ) && ( index < m_hitOperations.Size() ) )
		{
			m_hitOperations[ index ].operation.isEnabled = enable;
		}
	}

	public const override function IsOperationEnabled( index : Int32 ) : Bool
	{
		if( ( index >= 0 ) && ( index < m_hitOperations.Size() ) )
		{
			return m_hitOperations[ index ].operation.isEnabled;
		}
		return false;
	}

	public override function SetDelayIdOnOperation( delayId : DelayID, operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_hitOperations.Size() ) )
		{
			m_hitOperations[ operationID ].operation.delayID = delayId;
			m_hitOperations[ operationID ].operation.isDelayActive = true;
		}
	}

	public override function ClearDelayIdOnOperation( operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_hitOperations.Size() ) )
		{
			m_hitOperations[ operationID ].operation.isDelayActive = false;
		}
	}

	public function ExecuteOperation( owner : weak< GameObject >, activator : weak< GameObject >, attackData : AttackData )
	{
		var i : Int32;
		var attackType : gamedataAttackType;
		var healthPercentage : Float;
		var device : Device;
		device = ( ( Device )( owner ) );
		if( device == NULL )
		{
			return;
		}
		attackType = attackData.GetAttackType();
		healthPercentage = device.GetCurrentHealth();
		for( i = 0; i < m_hitOperations.Size(); i += 1 )
		{
			if( AttackData.IsRangedOrDirect( attackType ) && !( m_hitOperations[ i ].bullets ) )
			{
				return;
			}
			if( AttackData.IsExplosion( attackType ) && !( m_hitOperations[ i ].explosions ) )
			{
				return;
			}
			if( AttackData.IsMelee( attackType ) && !( m_hitOperations[ i ].melee ) )
			{
				return;
			}
			if( healthPercentage > m_hitOperations[ i ].healthPercentage )
			{
				return;
			}
			if( ( ( PlayerPuppet )( activator ) ) && m_hitOperations[ i ].isAttackerPlayer )
			{
				Execute( m_hitOperations[ i ].operation, owner );
			}
			else if( ( ( ( PlayerPuppet )( activator ) ) == NULL ) && m_hitOperations[ i ].isAttackerNPC )
			{
				Execute( m_hitOperations[ i ].operation, owner );
			}
		}
	}

	public function RestoreOperation( owner : weak< GameObject >, activator : weak< GameObject > )
	{
		var i : Int32;
		for( i = 0; i < m_hitOperations.Size(); i += 1 )
		{
			Restore( m_hitOperations[ i ].operation, owner );
		}
	}

}

class InteractionAreaOperations extends DeviceOperations
{
	protected const instanceeditable var m_interactionAreaOperations : array< SInteractionAreaOperationData >;

	public override function RequestComponents( ri : EntityRequestComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var componentName : CName;
		for( i = 0; i < m_interactionAreaOperations.Size(); i += 1 )
		{
			m_interactionAreaOperations[ i ].operation.id = i;
			for( k = 0; k < m_interactionAreaOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_interactionAreaOperations[ i ].operation.components[ k ].componentName;
				EntityRequestComponentsInterface.RequestComponent( ri, componentName, 'IPlacedComponent', false );
			}
		}
	}

	public override function TakeControl( ri : EntityResolveComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var component : weak< IPlacedComponent >;
		var componentName : CName;
		for( i = 0; i < m_interactionAreaOperations.Size(); i += 1 )
		{
			for( k = 0; k < m_interactionAreaOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_interactionAreaOperations[ i ].operation.components[ k ].componentName;
				component = ( ( IPlacedComponent )( EntityResolveComponentsInterface.GetComponent( ri, componentName ) ) );
				if( ( component != NULL ) && !( m_components.Contains( component ) ) )
				{
					m_components.PushBack( component );
				}
			}
		}
	}

	public override function ToggleOperation( enable : Bool, index : Int32 )
	{
		if( ( index >= 0 ) && ( index < m_interactionAreaOperations.Size() ) )
		{
			m_interactionAreaOperations[ index ].operation.isEnabled = enable;
		}
	}

	public const override function IsOperationEnabled( index : Int32 ) : Bool
	{
		if( ( index >= 0 ) && ( index < m_interactionAreaOperations.Size() ) )
		{
			return m_interactionAreaOperations[ index ].operation.isEnabled;
		}
		return false;
	}

	public override function SetDelayIdOnOperation( delayId : DelayID, operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_interactionAreaOperations.Size() ) )
		{
			m_interactionAreaOperations[ operationID ].operation.delayID = delayId;
			m_interactionAreaOperations[ operationID ].operation.isDelayActive = true;
		}
	}

	public override function ClearDelayIdOnOperation( operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_interactionAreaOperations.Size() ) )
		{
			m_interactionAreaOperations[ operationID ].operation.isDelayActive = false;
		}
	}

	public function ExecuteOperation( areaTag : CName, owner : weak< GameObject >, activator : weak< GameObject >, operationType : gameinteractionsEInteractionEventType )
	{
		var i : Int32;
		for( i = 0; i < m_interactionAreaOperations.Size(); i += 1 )
		{
			if( m_interactionAreaOperations[ i ].areaTag == areaTag && m_interactionAreaOperations[ i ].operationType == operationType )
			{
				if( ( ( PlayerPuppet )( activator ) ) && m_interactionAreaOperations[ i ].isActivatorPlayer )
				{
					Execute( m_interactionAreaOperations[ i ].operation, owner );
				}
				else if( ( ( ( PlayerPuppet )( activator ) ) == NULL ) && m_interactionAreaOperations[ i ].isActivatorNPC )
				{
					Execute( m_interactionAreaOperations[ i ].operation, owner );
				}
			}
		}
	}

	public function RestoreOperation( areaTag : CName, owner : weak< GameObject >, activator : weak< GameObject >, operationType : gameinteractionsEInteractionEventType )
	{
		var i : Int32;
		for( i = 0; i < m_interactionAreaOperations.Size(); i += 1 )
		{
			if( m_interactionAreaOperations[ i ].areaTag == areaTag && m_interactionAreaOperations[ i ].operationType == operationType )
			{
				Restore( m_interactionAreaOperations[ i ].operation, owner );
			}
		}
	}

}

class TriggerVolumeOperations extends DeviceOperations
{
	protected const instanceeditable var m_triggerVolumeOperations : array< STriggerVolumeOperationData >;

	public override function RequestComponents( ri : EntityRequestComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var componentName : CName;
		for( i = 0; i < m_triggerVolumeOperations.Size(); i += 1 )
		{
			m_triggerVolumeOperations[ i ].operation.id = i;
			for( k = 0; k < m_triggerVolumeOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_triggerVolumeOperations[ i ].operation.components[ k ].componentName;
				EntityRequestComponentsInterface.RequestComponent( ri, componentName, 'IPlacedComponent', false );
			}
		}
	}

	public override function TakeControl( ri : EntityResolveComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var component : weak< IPlacedComponent >;
		var componentName : CName;
		for( i = 0; i < m_triggerVolumeOperations.Size(); i += 1 )
		{
			for( k = 0; k < m_triggerVolumeOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_triggerVolumeOperations[ i ].operation.components[ k ].componentName;
				component = ( ( IPlacedComponent )( EntityResolveComponentsInterface.GetComponent( ri, componentName ) ) );
				if( ( component != NULL ) && !( m_components.Contains( component ) ) )
				{
					m_components.PushBack( component );
				}
			}
		}
	}

	public override function ToggleOperation( enable : Bool, index : Int32 )
	{
		if( ( index >= 0 ) && ( index < m_triggerVolumeOperations.Size() ) )
		{
			m_triggerVolumeOperations[ index ].operation.isEnabled = enable;
		}
	}

	public const override function IsOperationEnabled( index : Int32 ) : Bool
	{
		if( ( index >= 0 ) && ( index < m_triggerVolumeOperations.Size() ) )
		{
			return m_triggerVolumeOperations[ index ].operation.isEnabled;
		}
		return false;
	}

	public override function SetDelayIdOnOperation( delayId : DelayID, operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_triggerVolumeOperations.Size() ) )
		{
			m_triggerVolumeOperations[ operationID ].operation.delayID = delayId;
			m_triggerVolumeOperations[ operationID ].operation.isDelayActive = true;
		}
	}

	public override function ClearDelayIdOnOperation( operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_triggerVolumeOperations.Size() ) )
		{
			m_triggerVolumeOperations[ operationID ].operation.isDelayActive = false;
		}
	}

	public function ExecuteOperation( componentName : CName, owner : weak< GameObject >, activator : weak< GameObject >, operationType : ETriggerOperationType )
	{
		var i : Int32;
		for( i = 0; i < m_triggerVolumeOperations.Size(); i += 1 )
		{
			if( m_triggerVolumeOperations[ i ].componentName == componentName && m_triggerVolumeOperations[ i ].operationType == operationType )
			{
				if( ( ( PlayerPuppet )( activator ) ) && m_triggerVolumeOperations[ i ].isActivatorPlayer )
				{
					Execute( m_triggerVolumeOperations[ i ].operation, owner );
				}
				else if( ( ( ( PlayerPuppet )( activator ) ) == NULL ) && m_triggerVolumeOperations[ i ].isActivatorNPC )
				{
					Execute( m_triggerVolumeOperations[ i ].operation, owner );
				}
			}
		}
	}

	public function RestoreOperation( componentName : CName, owner : weak< GameObject >, activator : weak< GameObject >, operationType : ETriggerOperationType )
	{
		var i : Int32;
		for( i = 0; i < m_triggerVolumeOperations.Size(); i += 1 )
		{
			if( m_triggerVolumeOperations[ i ].componentName == componentName && m_triggerVolumeOperations[ i ].operationType == operationType )
			{
				Restore( m_triggerVolumeOperations[ i ].operation, owner );
			}
		}
	}

}

class BaseActionOperations extends DeviceOperations
{
	protected const instanceeditable var m_baseActionsOperations : array< SBaseActionOperationData >;

	public override function RequestComponents( ri : EntityRequestComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var componentName : CName;
		for( i = 0; i < m_baseActionsOperations.Size(); i += 1 )
		{
			m_baseActionsOperations[ i ].operation.id = i;
			for( k = 0; k < m_baseActionsOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_baseActionsOperations[ i ].operation.components[ k ].componentName;
				EntityRequestComponentsInterface.RequestComponent( ri, componentName, 'IPlacedComponent', false );
			}
		}
	}

	public override function TakeControl( ri : EntityResolveComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var component : weak< IPlacedComponent >;
		var componentName : CName;
		for( i = 0; i < m_baseActionsOperations.Size(); i += 1 )
		{
			for( k = 0; k < m_baseActionsOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_baseActionsOperations[ i ].operation.components[ k ].componentName;
				component = ( ( IPlacedComponent )( EntityResolveComponentsInterface.GetComponent( ri, componentName ) ) );
				if( ( component != NULL ) && !( m_components.Contains( component ) ) )
				{
					m_components.PushBack( component );
				}
			}
		}
	}

	public override function ToggleOperation( enable : Bool, index : Int32 )
	{
		if( ( index >= 0 ) && ( index < m_baseActionsOperations.Size() ) )
		{
			m_baseActionsOperations[ index ].operation.isEnabled = enable;
		}
	}

	public const override function IsOperationEnabled( index : Int32 ) : Bool
	{
		if( ( index >= 0 ) && ( index < m_baseActionsOperations.Size() ) )
		{
			return m_baseActionsOperations[ index ].operation.isEnabled;
		}
		return false;
	}

	public override function SetDelayIdOnOperation( delayId : DelayID, operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_baseActionsOperations.Size() ) )
		{
			m_baseActionsOperations[ operationID ].operation.delayID = delayId;
			m_baseActionsOperations[ operationID ].operation.isDelayActive = true;
		}
	}

	public override function ClearDelayIdOnOperation( operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_baseActionsOperations.Size() ) )
		{
			m_baseActionsOperations[ operationID ].operation.isDelayActive = false;
		}
	}

	public function ExecuteOperation( actionClassName : CName, owner : weak< GameObject > )
	{
		var i : Int32;
		var currentActionName : CName;
		for( i = 0; i < m_baseActionsOperations.Size(); i += 1 )
		{
			currentActionName = m_baseActionsOperations[ i ].action.GetClassName();
			if( currentActionName == actionClassName )
			{
				Execute( m_baseActionsOperations[ i ].operation, owner );
			}
		}
	}

	public function RestoreOperation( actionClassName : CName, owner : weak< GameObject > )
	{
		var i : Int32;
		for( i = 0; i < m_baseActionsOperations.Size(); i += 1 )
		{
			if( m_baseActionsOperations[ i ].action.GetClassName() == actionClassName )
			{
				Restore( m_baseActionsOperations[ i ].operation, owner );
			}
		}
	}

}

class CustomActionOperations extends DeviceOperations
{
	instanceeditable var m_customActions : SCustomDeviceActionsData;
	protected const instanceeditable var m_customActionsOperations : array< SCustomActionOperationData >;

	public override function RequestComponents( ri : EntityRequestComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var componentName : CName;
		for( i = 0; i < m_customActionsOperations.Size(); i += 1 )
		{
			m_customActionsOperations[ i ].operation.id = i;
			for( k = 0; k < m_customActionsOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_customActionsOperations[ i ].operation.components[ k ].componentName;
				EntityRequestComponentsInterface.RequestComponent( ri, componentName, 'IPlacedComponent', false );
			}
		}
	}

	public override function TakeControl( ri : EntityResolveComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var component : weak< IPlacedComponent >;
		var componentName : CName;
		for( i = 0; i < m_customActionsOperations.Size(); i += 1 )
		{
			for( k = 0; k < m_customActionsOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_customActionsOperations[ i ].operation.components[ k ].componentName;
				component = ( ( IPlacedComponent )( EntityResolveComponentsInterface.GetComponent( ri, componentName ) ) );
				if( ( component != NULL ) && !( m_components.Contains( component ) ) )
				{
					m_components.PushBack( component );
				}
			}
		}
	}

	public override function ToggleOperation( enable : Bool, index : Int32 )
	{
		if( ( index >= 0 ) && ( index < m_customActionsOperations.Size() ) )
		{
			m_customActionsOperations[ index ].operation.isEnabled = enable;
		}
	}

	public const override function IsOperationEnabled( index : Int32 ) : Bool
	{
		if( ( index >= 0 ) && ( index < m_customActionsOperations.Size() ) )
		{
			return m_customActionsOperations[ index ].operation.isEnabled;
		}
		return false;
	}

	public override function SetDelayIdOnOperation( delayId : DelayID, operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_customActionsOperations.Size() ) )
		{
			m_customActionsOperations[ operationID ].operation.delayID = delayId;
			m_customActionsOperations[ operationID ].operation.isDelayActive = true;
		}
	}

	public override function ClearDelayIdOnOperation( operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_customActionsOperations.Size() ) )
		{
			m_customActionsOperations[ operationID ].operation.isDelayActive = false;
		}
	}

	public function ExecuteOperation( actionID : CName, owner : weak< GameObject > )
	{
		var i : Int32;
		for( i = 0; i < m_customActionsOperations.Size(); i += 1 )
		{
			if( m_customActionsOperations[ i ].actionID == actionID )
			{
				Execute( m_customActionsOperations[ i ].operation, owner );
			}
		}
	}

	public function RestoreOperation( actionID : CName, owner : weak< GameObject > )
	{
		var i : Int32;
		for( i = 0; i < m_customActionsOperations.Size(); i += 1 )
		{
			if( m_customActionsOperations[ i ].actionID == actionID )
			{
				Restore( m_customActionsOperations[ i ].operation, owner );
			}
		}
	}

}

class DoorStateOperations extends DeviceOperations
{
	protected const instanceeditable var m_doorStateOperations : array< SDoorStateOperationData >;
	private var m_wasStateCached : Bool;
	private var m_cachedState : EDoorStatus;

	public override function RequestComponents( ri : EntityRequestComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var componentName : CName;
		for( i = 0; i < m_doorStateOperations.Size(); i += 1 )
		{
			m_doorStateOperations[ i ].operation.id = i;
			for( k = 0; k < m_doorStateOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_doorStateOperations[ i ].operation.components[ k ].componentName;
				EntityRequestComponentsInterface.RequestComponent( ri, componentName, 'IPlacedComponent', false );
			}
		}
	}

	public override function TakeControl( ri : EntityResolveComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var component : weak< IPlacedComponent >;
		var componentName : CName;
		for( i = 0; i < m_doorStateOperations.Size(); i += 1 )
		{
			for( k = 0; k < m_doorStateOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_doorStateOperations[ i ].operation.components[ k ].componentName;
				component = ( ( IPlacedComponent )( EntityResolveComponentsInterface.GetComponent( ri, componentName ) ) );
				if( ( component != NULL ) && !( m_components.Contains( component ) ) )
				{
					m_components.PushBack( component );
				}
			}
		}
	}

	public override function ToggleOperation( enable : Bool, index : Int32 )
	{
		if( ( index >= 0 ) && ( index < m_doorStateOperations.Size() ) )
		{
			m_doorStateOperations[ index ].operation.isEnabled = enable;
		}
	}

	public const override function IsOperationEnabled( index : Int32 ) : Bool
	{
		if( ( index >= 0 ) && ( index < m_doorStateOperations.Size() ) )
		{
			return m_doorStateOperations[ index ].operation.isEnabled;
		}
		return false;
	}

	public override function SetDelayIdOnOperation( delayId : DelayID, operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_doorStateOperations.Size() ) )
		{
			m_doorStateOperations[ operationID ].operation.delayID = delayId;
			m_doorStateOperations[ operationID ].operation.isDelayActive = true;
		}
	}

	public override function ClearDelayIdOnOperation( operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_doorStateOperations.Size() ) )
		{
			m_doorStateOperations[ operationID ].operation.isDelayActive = false;
		}
	}

	public function ExecuteOperation( state : EDoorStatus, owner : weak< GameObject > )
	{
		var i : Int32;
		if( m_wasStateCached && m_cachedState == state )
		{
			return;
		}
		m_cachedState = state;
		m_wasStateCached = true;
		for( i = 0; i < m_doorStateOperations.Size(); i += 1 )
		{
			if( m_doorStateOperations[ i ].state == state )
			{
				Execute( m_doorStateOperations[ i ].operation, owner );
			}
		}
	}

}

class BaseStateOperations extends DeviceOperations
{
	instanceeditable var m_stateActionsOverrides : SGenericDeviceActionsData;
	protected const instanceeditable var m_baseStateOperations : array< SBaseStateOperationData >;
	private var m_wasStateCached : Bool;
	private var m_cachedState : EDeviceStatus;

	public override function RequestComponents( ri : EntityRequestComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var componentName : CName;
		for( i = 0; i < m_baseStateOperations.Size(); i += 1 )
		{
			m_baseStateOperations[ i ].operation.id = i;
			for( k = 0; k < m_baseStateOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_baseStateOperations[ i ].operation.components[ k ].componentName;
				EntityRequestComponentsInterface.RequestComponent( ri, componentName, 'IPlacedComponent', false );
			}
		}
	}

	public override function TakeControl( ri : EntityResolveComponentsInterface )
	{
		var i : Int32;
		var k : Int32;
		var component : weak< IPlacedComponent >;
		var componentName : CName;
		for( i = 0; i < m_baseStateOperations.Size(); i += 1 )
		{
			for( k = 0; k < m_baseStateOperations[ i ].operation.components.Size(); k += 1 )
			{
				componentName = m_baseStateOperations[ i ].operation.components[ k ].componentName;
				component = ( ( IPlacedComponent )( EntityResolveComponentsInterface.GetComponent( ri, componentName ) ) );
				if( ( component != NULL ) && !( m_components.Contains( component ) ) )
				{
					m_components.PushBack( component );
				}
			}
		}
	}

	public override function ToggleOperation( enable : Bool, index : Int32 )
	{
		if( ( index >= 0 ) && ( index < m_baseStateOperations.Size() ) )
		{
			m_baseStateOperations[ index ].operation.isEnabled = enable;
		}
	}

	public const override function IsOperationEnabled( index : Int32 ) : Bool
	{
		if( ( index >= 0 ) && ( index < m_baseStateOperations.Size() ) )
		{
			return m_baseStateOperations[ index ].operation.isEnabled;
		}
		return false;
	}

	public override function SetDelayIdOnOperation( delayId : DelayID, operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_baseStateOperations.Size() ) )
		{
			m_baseStateOperations[ operationID ].operation.delayID = delayId;
			m_baseStateOperations[ operationID ].operation.isDelayActive = true;
		}
	}

	public override function ClearDelayIdOnOperation( operationID : Int32 )
	{
		if( ( operationID >= 0 ) && ( operationID < m_baseStateOperations.Size() ) )
		{
			m_baseStateOperations[ operationID ].operation.isDelayActive = false;
		}
	}

	public function ExecuteOperation( state : EDeviceStatus, owner : weak< GameObject > )
	{
		var i : Int32;
		if( m_wasStateCached && m_cachedState == state )
		{
			return;
		}
		m_cachedState = state;
		m_wasStateCached = true;
		for( i = 0; i < m_baseStateOperations.Size(); i += 1 )
		{
			if( m_baseStateOperations[ i ].state == state )
			{
				Execute( m_baseStateOperations[ i ].operation, owner );
			}
		}
	}

}

abstract class DeviceOperations extends IScriptable
{
	protected var m_components : array< weak< IPlacedComponent > >;
	protected var m_fxInstances : array< SVfxInstanceData >;

	public virtual function RequestComponents( ri : EntityRequestComponentsInterface ) {}

	public virtual function TakeControl( ri : EntityResolveComponentsInterface ) {}

	public virtual function ToggleOperation( enable : Bool, index : Int32 ) {}

	public const virtual function IsOperationEnabled( index : Int32 ) : Bool
	{
		return true;
	}

	public virtual function SetDelayIdOnOperation( delayId : DelayID, operationID : Int32 ) {}

	public virtual function ClearDelayIdOnOperation( operationID : Int32 ) {}

	protected function SendToggleOperataionEvent( enable : Bool, index : Int32, type : EOperationClassType, owner : weak< GameObject > )
	{
		var evt : ToggleOperationEvent;
		evt = new ToggleOperationEvent;
		evt.enable = enable;
		evt.index = index;
		evt.type = type;
		owner.QueueEvent( evt );
	}

	protected function DelayOperation( const operation : ref< SBaseDeviceOperationData >, owner : weak< GameObject > )
	{
		var evt : DelayedOperationEvent;
		var delayID : DelayID;
		evt = new DelayedOperationEvent;
		evt.operationHandler = this;
		evt.operation = operation;
		delayID = GameInstance.GetDelaySystem( owner.GetGame() ).DelayEvent( owner, evt, operation.delay );
		SetDelayIdOnOperation( delayID, operation.id );
	}

	public function Execute( const operation : ref< SBaseDeviceOperationData >, owner : weak< GameObject > )
	{
		if( !( IsOperationEnabled( operation.id ) ) )
		{
			return;
		}
		if( operation.delay <= 0.0 )
		{
			ClearDelayIdOnOperation( operation.id );
			ResolveVFXs( operation.VFXs, owner );
			ResolveSFXs( operation.SFXs, owner );
			ResolveFacts( operation.facts, owner );
			ResolveComponents( operation.components );
			ResolveMeshesAppearence( operation.meshesAppearence, owner );
			ResolveTransformAnimations( operation.transformAnimations, owner );
			ResolveWorkspots( operation.playerWorkspot, owner );
			ResolveStims( operation.stims, owner );
			ResolveStatusEffects( operation.statusEffects, owner );
			ResolveDamages( operation.damages, owner );
			ResolveItems( operation.items, owner );
			ResolveTeleport( operation.teleport, owner );
			ResolveOperations( operation.toggleOperations, owner );
			ResolveDisable( operation.disableDevice, owner );
			if( operation.executeOnce )
			{
				ToggleOperation( false, operation.id );
			}
		}
		else
		{
			if( !( operation.isDelayActive ) )
			{
				DelayOperation( operation, owner );
			}
			else
			{
				if( operation.resetDelay )
				{
					GameInstance.GetDelaySystem( owner.GetGame() ).CancelDelay( operation.delayID );
					DelayOperation( operation, owner );
				}
			}
		}
	}

	public function Restore( const operation : ref< SBaseDeviceOperationData >, owner : weak< GameObject > )
	{
		ResolveVFXs( operation.VFXs, owner );
		ResolveSFXs( operation.SFXs, owner );
		ResolveComponents( operation.components );
		ResolveMeshesAppearence( operation.meshesAppearence, owner );
		ResolveTransformAnimations( operation.transformAnimations, owner );
		ResolveWorkspots( operation.playerWorkspot, owner );
		ResolveStims( operation.stims, owner );
		ResolveStatusEffects( operation.statusEffects, owner );
	}

	private function ResolveDisable( disable : Bool, owner : weak< GameObject > )
	{
		var device : Device;
		if( disable )
		{
			device = ( ( Device )( owner ) );
			if( device == NULL )
			{
				return;
			}
			device.GetDevicePS().ForceDisableDevice();
		}
	}

	private function ResolveOperations( const operations : ref< array< SToggleOperationData > >, owner : weak< GameObject > )
	{
		var i : Int32;
		for( i = 0; i < operations.Size(); i += 1 )
		{
			if( operations[ i ].classType == EOperationClassType.Local )
			{
				ToggleOperation( operations[ i ].enable, operations[ i ].index );
			}
			else
			{
				SendToggleOperataionEvent( operations[ i ].enable, operations[ i ].index, operations[ i ].classType, owner );
			}
		}
	}

	private function ResolveTeleport( teleport : STeleportOperationData, owner : weak< GameObject > )
	{
		var puppet : GameObject;
		if( owner == NULL )
		{
			return;
		}
		puppet = GameInstance.GetPlayerSystem( owner.GetGame() ).GetLocalPlayerMainGameObject();
		if( puppet == NULL )
		{
			return;
		}
		GameInstance.GetTeleportationFacility( owner.GetGame() ).TeleportToNode( puppet, teleport.nodeRef );
	}

	private function ResolveItems( const items : ref< array< SInventoryOperationData > >, owner : weak< GameObject > )
	{
		var i : Int32;
		var transactionSystem : TransactionSystem;
		var puppet : GameObject;
		if( owner == NULL )
		{
			return;
		}
		puppet = GameInstance.GetPlayerSystem( owner.GetGame() ).GetLocalPlayerMainGameObject();
		if( puppet == NULL )
		{
			return;
		}
		transactionSystem = GameInstance.GetTransactionSystem( owner.GetGame() );
		for( i = 0; i < items.Size(); i += 1 )
		{
			if( items[ i ].operationType == EItemOperationType.ADD )
			{
				transactionSystem.GiveItem( puppet, ItemID.FromTDBID( items[ i ].itemName ), items[ i ].quantity );
			}
			else if( items[ i ].operationType == EItemOperationType.REMOVE )
			{
				transactionSystem.RemoveItem( puppet, ItemID.FromTDBID( items[ i ].itemName ), items[ i ].quantity );
			}
		}
	}

	private function ResolveVFXs( const VFXs : ref< array< SVFXOperationData > >, owner : weak< GameObject > )
	{
		var i : Int32;
		var effectBlackboard : worldEffectBlackboard;
		var targetID : EntityID;
		var target : GameEntity;
		var fxInstance : FxInstance;
		var transform : WorldTransform;
		var position : WorldPosition;
		if( owner == NULL )
		{
			return;
		}
		for( i = 0; i < VFXs.Size(); i += 1 )
		{
			targetID = ( ( EntityID )( ResolveNodeRefWithEntityID( VFXs[ i ].nodeRef, owner.GetEntityID() ) ) );
			target = ( ( GameEntity )( GameInstance.FindEntityByID( owner.GetGame(), targetID ) ) );
			if( target == NULL )
			{
				target = owner;
			}
			if( target == NULL )
			{
				continue;
			}
			if( VFXs[ i ].operationType == EEffectOperationType.START )
			{
				if( FxResource.IsValid( VFXs[ i ].vfxResource ) )
				{
					fxInstance = GetFxInstance( VFXs[ i ].vfxName );
					if( fxInstance != NULL )
					{
						RemoveFxInstance( VFXs[ i ].vfxName );
						fxInstance.Kill();
					}
					WorldPosition.SetVector4( position, target.GetWorldPosition() );
					WorldTransform.SetWorldPosition( transform, position );
					fxInstance = CreateFxInstance( owner, VFXs[ i ].vfxName, VFXs[ i ].vfxResource, transform );
					fxInstance.SetBlackboardValue( 'change_size', VFXs[ i ].size );
					StoreFxInstance( VFXs[ i ].vfxName, fxInstance );
				}
				else
				{
					effectBlackboard = new worldEffectBlackboard;
					effectBlackboard.SetValue( 'change_size', VFXs[ i ].size );
					GameObjectEffectHelper.StartEffectEvent( ( ( GameObject )( target ) ), VFXs[ i ].vfxName, VFXs[ i ].shouldPersist, effectBlackboard );
				}
			}
			else if( VFXs[ i ].operationType == EEffectOperationType.STOP )
			{
				fxInstance = GetFxInstance( VFXs[ i ].vfxName );
				if( fxInstance == NULL )
				{
					GameObjectEffectHelper.StopEffectEvent( ( ( GameObject )( target ) ), VFXs[ i ].vfxName );
				}
				else
				{
					RemoveFxInstance( VFXs[ i ].vfxName );
					fxInstance.Kill();
				}
			}
			else if( VFXs[ i ].operationType == EEffectOperationType.BRAKE_LOOP )
			{
				fxInstance = GetFxInstance( VFXs[ i ].vfxName );
				if( fxInstance == NULL )
				{
					GameObjectEffectHelper.BreakEffectLoopEvent( ( ( GameObject )( target ) ), VFXs[ i ].vfxName );
				}
				else
				{
					fxInstance.BreakLoop();
				}
			}
		}
	}

	private function ResolveSFXs( const SFXs : ref< array< SSFXOperationData > >, owner : weak< GameObject > )
	{
		var i : Int32;
		if( owner == NULL )
		{
			return;
		}
		for( i = 0; i < SFXs.Size(); i += 1 )
		{
			GameObject.PlaySoundEvent( owner, SFXs[ i ].sfxName );
		}
	}

	private function ResolveFacts( const facts : ref< array< SFactOperationData > >, owner : weak< GameObject > )
	{
		var i : Int32;
		if( owner == NULL )
		{
			return;
		}
		for( i = 0; i < facts.Size(); i += 1 )
		{
			if( IsNameValid( facts[ i ].factName ) )
			{
				if( facts[ i ].operationType == EMathOperationType.Add )
				{
					AddFact( owner.GetGame(), facts[ i ].factName, facts[ i ].factValue );
				}
				else
				{
					SetFactValue( owner.GetGame(), facts[ i ].factName, facts[ i ].factValue );
				}
			}
		}
	}

	private function ResolveComponents( const componentsData : ref< array< SComponentOperationData > > )
	{
		var i : Int32;
		var k : Int32;
		for( i = 0; i < componentsData.Size(); i += 1 )
		{
			for( k = 0; k < m_components.Size(); k += 1 )
			{
				if( m_components[ k ] == NULL )
				{
					continue;
				}
				if( componentsData[ i ].componentName == m_components[ k ].GetName() )
				{
					if( componentsData[ i ].operationType == EComponentOperation.Enable )
					{
						m_components[ k ].Toggle( true );
					}
					else
					{
						m_components[ k ].Toggle( false );
					}
				}
			}
		}
	}

	private function ResolveMeshesAppearence( appearanceName : CName, owner : weak< GameObject > )
	{
		if( owner == NULL )
		{
			return;
		}
		if( IsNameValid( appearanceName ) )
		{
			GameObject.SetMeshAppearanceEvent( owner, appearanceName );
		}
	}

	private function ResolveTransformAnimations( const animations : ref< array< STransformAnimationData > >, owner : weak< GameObject > )
	{
		var i : Int32;
		var playEvent : gameTransformAnimationPlayEvent;
		var pauseEvent : gameTransformAnimationPauseEvent;
		var resetEvent : gameTransformAnimationResetEvent;
		var skipEvent : gameTransformAnimationSkipEvent;
		if( owner == NULL )
		{
			return;
		}
		for( i = 0; i < animations.Size(); i += 1 )
		{
			if( animations[ i ].operationType == ETransformAnimationOperationType.PLAY )
			{
				playEvent = new gameTransformAnimationPlayEvent;
				playEvent.animationName = animations[ i ].animationName;
				playEvent.timeScale = animations[ i ].playData.timeScale;
				playEvent.looping = animations[ i ].playData.looping;
				playEvent.timesPlayed = animations[ i ].playData.timesPlayed;
				owner.QueueEvent( playEvent );
				return;
			}
			else if( animations[ i ].operationType == ETransformAnimationOperationType.PAUSE )
			{
				pauseEvent = new gameTransformAnimationPauseEvent;
				pauseEvent.animationName = animations[ i ].animationName;
				owner.QueueEvent( pauseEvent );
				return;
			}
			else if( animations[ i ].operationType == ETransformAnimationOperationType.RESET )
			{
				resetEvent = new gameTransformAnimationResetEvent;
				resetEvent.animationName = animations[ i ].animationName;
				owner.QueueEvent( resetEvent );
				return;
			}
			else if( animations[ i ].operationType == ETransformAnimationOperationType.SKIP )
			{
				skipEvent = new gameTransformAnimationSkipEvent;
				skipEvent.animationName = animations[ i ].animationName;
				skipEvent.time = animations[ i ].skipData.time;
				skipEvent.skipToEnd = animations[ i ].skipData.skipToEnd;
				owner.QueueEvent( skipEvent );
				return;
			}
		}
	}

	private function ResolveWorkspots( workspot : SWorkspotData, owner : weak< GameObject > )
	{
		var device : Device;
		var player : GameObject;
		device = ( ( Device )( owner ) );
		if( device == NULL )
		{
			return;
		}
		player = GameInstance.GetPlayerSystem( device.GetGame() ).GetLocalPlayerMainGameObject();
		if( player == NULL )
		{
			return;
		}
		if( workspot.operationType == EWorkspotOperationType.ENTER )
		{
			if( IsNameValid( workspot.componentName ) )
			{
				EnterWorkspot( device, player, workspot.freeCamera, workspot.componentName );
			}
		}
		else if( workspot.operationType == EWorkspotOperationType.LEAVE )
		{
			LeaveWorkspot( player );
		}
	}

	private function ResolveStims( const stims : ref< array< SStimOperationData > >, owner : weak< GameObject > )
	{
		var i : Int32;
		var broadcaster : StimBroadcasterComponent;
		var target : GameObject;
		var targetID : EntityID;
		var stimType : gamedataStimType;
		for( i = 0; i < stims.Size(); i += 1 )
		{
			stimType = Device.MapStimType( stims[ i ].stimType );
			targetID = ( ( EntityID )( ResolveNodeRefWithEntityID( stims[ i ].nodeRef, owner.GetEntityID() ) ) );
			target = ( ( GameObject )( GameInstance.FindEntityByID( owner.GetGame(), targetID ) ) );
			if( target == NULL )
			{
				target = owner;
			}
			if( target == NULL )
			{
				continue;
			}
			if( stimType == gamedataStimType.Invalid )
			{
				continue;
			}
			broadcaster = target.GetStimBroadcasterComponent();
			if( broadcaster )
			{
				if( stims[ i ].operationType == EEffectOperationType.START )
				{
					broadcaster.SetSingleActiveStimuli( owner, stimType, stims[ i ].lifeTime, stims[ i ].radius );
				}
				else
				{
					broadcaster.RemoveActiveStimuliByName( owner, stimType );
				}
			}
		}
	}

	private function ResolveStatusEffects( statusEffects : array< SStatusEffectOperationData >, owner : weak< GameObject > )
	{
		var i : Int32;
		var effect : EffectInstance;
		var position : Vector4;
		if( owner == NULL )
		{
			return;
		}
		position = owner.GetWorldPosition();
		for( i = 0; i < statusEffects.Size(); i += 1 )
		{
			if( statusEffects[ i ].range > 0.0 )
			{
				effect = GameInstance.GetGameEffectSystem( owner.GetGame() ).CreateEffectStatic( 'applyStatusEffect', 'inRange', owner );
				EffectData.SetVector( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.position, position + statusEffects[ i ].offset );
				EffectData.SetFloat( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.radius, statusEffects[ i ].range );
				EffectData.SetFloat( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.duration, statusEffects[ i ].duration );
				EffectData.SetVariant( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.statusEffect, statusEffects[ i ].effect.statusEffect );
				effect.Run();
			}
		}
	}

	private function ResolveDamages( const damages : ref< array< SDamageOperationData > >, owner : weak< GameObject > )
	{
		var i : Int32;
		var damageEffect : EffectInstance;
		var explosionAttack : Attack_GameEffect;
		var attackContext : AttackInitContext;
		var statMods : array< gameStatModifierData >;
		var player : GameObject;
		var position : Vector4;
		if( owner == NULL )
		{
			return;
		}
		player = GameInstance.GetPlayerSystem( owner.GetGame() ).GetLocalPlayerMainGameObject();
		position = owner.GetWorldPosition();
		attackContext.instigator = player;
		attackContext.source = owner;
		for( i = 0; i < damages.Size(); i += 1 )
		{
			if( damages[ i ].range > 0.0 )
			{
				attackContext.record = TweakDBInterface.GetAttackRecord( damages[ i ].damageType );
				explosionAttack = ( ( Attack_GameEffect )( IAttack.Create( attackContext ) ) );
				damageEffect = explosionAttack.PrepareAttack( owner );
				explosionAttack.GetStatModList( statMods );
				EffectData.SetFloat( damageEffect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.radius, damages[ i ].range );
				EffectData.SetVector( damageEffect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.position, position + damages[ i ].offset );
				EffectData.SetVariant( damageEffect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.attack, ( ( IAttack )( explosionAttack ) ) );
				EffectData.SetVariant( damageEffect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.attackStatModList, statMods );
				explosionAttack.StartAttack();
			}
		}
	}

	protected virtual function EnterWorkspot( target : Device, activator : GameObject, optional freeCamera : Bool, optional componentName : CName )
	{
		var workspotSystem : WorkspotGameSystem;
		workspotSystem = GameInstance.GetWorkspotSystem( activator.GetGame() );
		workspotSystem.PlayInDeviceSimple( target, activator, freeCamera, componentName );
	}

	protected virtual function LeaveWorkspot( activator : GameObject )
	{
		var orientation : Quaternion;
		var direction : Vector4;
		var workspotSystem : WorkspotGameSystem;
		Quaternion.SetIdentity( orientation );
		direction = Vector4( 0.0, 0.0, 0.0, 1.0 );
		workspotSystem = GameInstance.GetWorkspotSystem( activator.GetGame() );
		workspotSystem.StopInDevice( activator, direction, orientation );
	}

	private function GetFxInstance( id : CName ) : FxInstance
	{
		var i : Int32;
		var fx : FxInstance;
		for( i = 0; i < m_fxInstances.Size(); i += 1 )
		{
			if( m_fxInstances[ i ].id == id )
			{
				fx = m_fxInstances[ i ].fx;
				if( fx == NULL )
				{
					m_fxInstances.EraseFast( i );
				}
				break;
			}
		}
		return fx;
	}

	private function RemoveFxInstance( id : CName )
	{
		var i : Int32;
		for( i = 0; i < m_fxInstances.Size(); i += 1 )
		{
			if( m_fxInstances[ i ].id == id )
			{
				m_fxInstances.EraseFast( i );
				break;
			}
		}
	}

	private function CreateFxInstance( owner : weak< GameObject >, id : CName, resource : FxResource, transform : WorldTransform ) : FxInstance
	{
		var fx : FxInstance;
		var fxSystem : FxSystem;
		fxSystem = GameInstance.GetFxSystem( owner.GetGame() );
		fx = fxSystem.SpawnEffect( resource, transform );
		return fx;
	}

	private function StoreFxInstance( id : CName, fx : FxInstance )
	{
		var fxInstanceData : SVfxInstanceData;
		fxInstanceData.id = id;
		fxInstanceData.fx = fx;
		m_fxInstances.PushBack( fxInstanceData );
	}

}

