class GrappleInteractionCondition extends InteractionScriptedCondition
{

	public export const function Test( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject > ) : Bool
	{
		return IsAreaBetweenPlayerAndVictim( activatorObject, hotSpotObject );
	}

	protected const function IsAreaBetweenPlayerAndVictim( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject > ) : Bool
	{
		var maxGrabDistOverCover : Float;
		var toHotSpot : Vector4;
		var distanceFromHotspot : Float;
		var behindCoverHeightDifferenceLockout : Float;
		maxGrabDistOverCover = 1.29999995;
		toHotSpot = hotSpotObject.GetWorldPosition() - activatorObject.GetWorldPosition();
		distanceFromHotspot = Vector4.Length2D( toHotSpot );
		behindCoverHeightDifferenceLockout = -0.5;
		if( !( SpatialQueriesHelper.HasSpaceInFront( activatorObject, toHotSpot, 1.29999995, 0.5, distanceFromHotspot, 0.40000001 ) ) )
		{
			return false;
		}
		if( ( toHotSpot.Z < behindCoverHeightDifferenceLockout ) && !( SpatialQueriesHelper.HasSpaceInFront( activatorObject, toHotSpot, 0.60000002, 0.5, distanceFromHotspot, 0.69999999 ) ) )
		{
			return false;
		}
		if( distanceFromHotspot < maxGrabDistOverCover )
		{
			return true;
		}
		return SpatialQueriesHelper.HasSpaceInFront( hotSpotObject, toHotSpot * -1.0, 0.60000002, 0.5, distanceFromHotspot - maxGrabDistOverCover, 1.10000002 );
	}

}

class NewPerkFinisherCondition extends InteractionScriptedCondition
{

	public export const function Test( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject > ) : Bool
	{
		var equippedWeapon : WeaponObject;
		var weaponRecord : Item_Record;
		var tags : array< CName >;
		var targetPuppet : weak< ScriptedPuppet >;
		var gameInstance : GameInstance;
		var interactonsBlackboard : IBlackboard;
		var interactionData : UIInteractionsDef;
		var choiceData : DialogChoiceHubs;
		var psmBlackBoard : IBlackboard;
		var eMeleeWeaponState : gamePSMMeleeWeapon;
		var result : Bool;
		var npcTarget : NPCPuppet;
		var statsSystem : StatsSystem;
		statsSystem = GameInstance.GetStatsSystem( activatorObject.GetGame() );
		equippedWeapon = GameObject.GetActiveWeapon( activatorObject );
		if( !( equippedWeapon.IsMelee() ) )
		{
			return false;
		}
		weaponRecord = TDB.GetWeaponItemRecord( ItemID.GetTDBID( equippedWeapon.GetItemID() ) );
		tags = weaponRecord.Tags();
		if( !( tags.Contains( 'FinisherFront' ) ) && !( tags.Contains( 'FinisherBack' ) ) )
		{
			return false;
		}
		targetPuppet = ( ( ScriptedPuppet )( hotSpotObject ) );
		if( !( targetPuppet ) )
		{
			return false;
		}
		if( targetPuppet.IsCrowd() || targetPuppet.IsCharacterCivilian() )
		{
			return false;
		}
		if( !( ScriptedPuppet.IsActive( targetPuppet ) ) )
		{
			return false;
		}
		if( StatusEffectSystem.ObjectHasStatusEffect( activatorObject, T"GameplayRestriction.FistFight" ) )
		{
			return false;
		}
		gameInstance = activatorObject.GetGame();
		if( GameInstance.GetGodModeSystem( gameInstance ).HasGodMode( targetPuppet.GetEntityID(), gameGodModeType.Immortal ) )
		{
			return false;
		}
		if( GameInstance.GetGodModeSystem( gameInstance ).HasGodMode( targetPuppet.GetEntityID(), gameGodModeType.Invulnerable ) )
		{
			return false;
		}
		if( GameInstance.GetMountingFacility( gameInstance ).IsMountedToAnything( activatorObject.GetEntityID() ) )
		{
			return false;
		}
		if( GameInstance.GetMountingFacility( gameInstance ).IsMountedToAnything( targetPuppet.GetEntityID() ) )
		{
			return false;
		}
		interactonsBlackboard = GameInstance.GetBlackboardSystem( gameInstance ).Get( GetAllBlackboardDefs().UIInteractions );
		interactionData = GetAllBlackboardDefs().UIInteractions;
		choiceData = ( ( DialogChoiceHubs )( interactonsBlackboard.GetVariant( interactionData.DialogChoiceHubs ) ) );
		if( choiceData.choiceHubs.Size() > 0 )
		{
			return false;
		}
		psmBlackBoard = GameInstance.GetBlackboardSystem( gameInstance ).GetLocalInstanced( activatorObject.GetEntityID(), GetAllBlackboardDefs().PlayerStateMachine );
		eMeleeWeaponState = ( ( gamePSMMeleeWeapon )( psmBlackBoard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.MeleeWeapon ) ) );
		if( eMeleeWeaponState == gamePSMMeleeWeapon.NotReady )
		{
			return false;
		}
		if( eMeleeWeaponState == gamePSMMeleeWeapon.StrongAttack )
		{
			return false;
		}
		npcTarget = ( ( NPCPuppet )( hotSpotObject ) );
		if( npcTarget && npcTarget.IsAboutToDieOrDefeated() )
		{
			return false;
		}
		if( equippedWeapon.IsBlunt() && statsSystem.GetStatBoolValue( activatorObject.GetEntityID(), gamedataStatType.CanPerformBluntFinisher ) )
		{
			result = IsFinisherAvailable( activatorObject, hotSpotObject ) && NewPerkFinisherBluntEnabled( activatorObject, hotSpotObject, equippedWeapon );
		}
		else if( equippedWeapon.IsThrowable() && statsSystem.GetStatBoolValue( activatorObject.GetEntityID(), gamedataStatType.CanPerformCoolFinisher ) )
		{
			result = IsFinisherAvailable( activatorObject, hotSpotObject ) && NewPerkFinisherThrowableEnabled( activatorObject, hotSpotObject, equippedWeapon );
		}
		else if( equippedWeapon.IsBlade() && statsSystem.GetStatBoolValue( activatorObject.GetEntityID(), gamedataStatType.CanPerformReflexFinisher ) )
		{
			result = IsFinisherAvailable( activatorObject, hotSpotObject ) && NewPerkFinisherBladeEnabled( activatorObject, hotSpotObject, equippedWeapon );
		}
		else if( equippedWeapon.IsMonowire() && statsSystem.GetStatBoolValue( activatorObject.GetEntityID(), gamedataStatType.CanPerformMonowireFinisher ) )
		{
			result = IsFinisherAvailable( activatorObject, hotSpotObject ) && NewPerkFinisherMonowireEnabled( activatorObject, hotSpotObject, equippedWeapon );
		}
		else
		{
			return false;
		}
		if( !( result ) )
		{
			return false;
		}
		else
		{
			if( !( targetPuppet.IsFinisherSoundPlayed() ) && !( hotSpotObject.GetIsInFastFinisher() ) )
			{
				GameObject.PlaySound( activatorObject, 'w_melee_perk_finisher_ready' );
				targetPuppet.SetFinisherSoundPlayed( true );
			}
		}
		return IsAreaClear( activatorObject, hotSpotObject );
	}

	private const function IsFinisherAvailable( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject > ) : Bool
	{
		var isInPoiseState : Bool;
		var isInThreshold : Bool;
		isInPoiseState = StatusEffectSystem.ObjectHasStatusEffect( hotSpotObject, T"BaseStatusEffect.FinisherActiveStatusEffect" );
		isInThreshold = hotSpotObject.IsInFinisherHealthThreshold( activatorObject );
		if( !( isInPoiseState ) && !( isInThreshold ) )
		{
			return false;
		}
		return true;
	}

	protected const function NewPerkFinisherBladeEnabled( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject >, equippedWeapon : WeaponObject ) : Bool
	{
		var statsSystem : StatsSystem;
		var minDistance : Float;
		var distanceFromHotspot : Float;
		statsSystem = GameInstance.GetStatsSystem( activatorObject.GetGame() );
		distanceFromHotspot = Vector4.Length2D( hotSpotObject.GetWorldPosition() - activatorObject.GetWorldPosition() );
		minDistance = statsSystem.GetStatValue( activatorObject.GetEntityID(), gamedataStatType.NewPerkFinisherReflexes_TargetDistanceMax );
		if( PlayerDevelopmentSystem.GetData( activatorObject ).IsNewPerkBoughtAnyLevel( gamedataNewPerkType.Reflexes_Right_Perk_3_4 ) )
		{
			minDistance *= TweakDBInterface.GetFloat( T"NewPerks.Reflexes_Right_Perk_3_4.distanceMult", 2.0 );
		}
		return distanceFromHotspot < minDistance;
	}

	protected const function NewPerkFinisherThrowableEnabled( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject >, equippedWeapon : WeaponObject ) : Bool
	{
		var statsSystem : StatsSystem;
		var minDistance : Float;
		var distanceFromHotspot : Float;
		statsSystem = GameInstance.GetStatsSystem( activatorObject.GetGame() );
		distanceFromHotspot = Vector4.Length2D( hotSpotObject.GetWorldPosition() - activatorObject.GetWorldPosition() );
		minDistance = statsSystem.GetStatValue( activatorObject.GetEntityID(), gamedataStatType.NewPerkFinisherCool_TargetDistanceMax );
		minDistance += ( TweakDBInterface.GetFloat( T"NewPerks.Cool_Inbetween_Right_3.distanceBase", 5.0 ) * ClampF( GameInstance.GetStatsSystem( hotSpotObject.GetGame() ).GetStatValue( hotSpotObject.GetEntityID(), gamedataStatType.Cool_Inbetween_Right_3_Stacks ), 0.0, TweakDBInterface.GetFloat( T"NewPerks.Cool_Inbetween_Right_3.distanceMaxStacks", 3.0 ) ) );
		if( distanceFromHotspot > minDistance )
		{
			return false;
		}
		return true;
	}

	protected const function NewPerkFinisherMonowireEnabled( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject >, equippedWeapon : WeaponObject ) : Bool
	{
		var statsSystem : StatsSystem;
		var minDistance : Float;
		var distanceFromHotspot : Float;
		statsSystem = GameInstance.GetStatsSystem( activatorObject.GetGame() );
		distanceFromHotspot = Vector4.Length2D( hotSpotObject.GetWorldPosition() - activatorObject.GetWorldPosition() );
		minDistance = statsSystem.GetStatValue( activatorObject.GetEntityID(), gamedataStatType.NewPerkFinisherMonowire_TargetDistanceMax );
		minDistance += ( TweakDBInterface.GetFloat( T"NewPerks.Reflexes_Right_Perk_3_4.distanceMult", 3.0 ) * ( ( Float )( ( ( ScriptedPuppet )( hotSpotObject ) ).GetDeviceActionQueueSize() ) ) );
		if( distanceFromHotspot > minDistance )
		{
			return false;
		}
		return true;
	}

	protected const function NewPerkFinisherBluntEnabled( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject >, const equippedWeapon : WeaponObject ) : Bool
	{
		var statsSystem : StatsSystem;
		var targetDistanceMax : Float;
		statsSystem = GameInstance.GetStatsSystem( activatorObject.GetGame() );
		targetDistanceMax = statsSystem.GetStatValue( activatorObject.GetEntityID(), gamedataStatType.NewPerkFinisherBlunt_TargetDistanceMax );
		if( Vector4.Length2D( hotSpotObject.GetWorldPosition() - activatorObject.GetWorldPosition() ) > targetDistanceMax )
		{
			return false;
		}
		return true;
	}

	private const function IsAreaClear( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject > ) : Bool
	{
		var toHotSpot : Vector4;
		var leapAngle : EulerAngles;
		var distanceFromHotspot : Float;
		var isObstacleVaultable : Bool;
		toHotSpot = hotSpotObject.GetWorldPosition() - activatorObject.GetWorldPosition();
		leapAngle = Vector4.ToRotation( toHotSpot );
		if( -( leapAngle.Pitch ) > TDB.GetFloat( T"playerStateMachineFinisher.finisherLeapToTarget.leapMaxPitch" ) )
		{
			return false;
		}
		distanceFromHotspot = Vector4.Length2D( toHotSpot );
		distanceFromHotspot = MinF( distanceFromHotspot, 1.5 );
		if( !( SpatialQueriesHelper.HasSpaceInFront( activatorObject, toHotSpot, 1.29999995, 0.5, distanceFromHotspot, 0.40000001 ) ) )
		{
			return false;
		}
		if( !( GameInstance.GetTargetingSystem( activatorObject.GetGame() ).IsVisibleTarget( activatorObject, hotSpotObject ) ) )
		{
			return false;
		}
		return SpatialQueriesHelper.IsTargetReachable( activatorObject, hotSpotObject, hotSpotObject.GetWorldPosition(), true, isObstacleVaultable );
	}

}

class BlackwallForceInteractionCondition extends InteractionScriptedCondition
{

	public export const function Test( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject > ) : Bool
	{
		return CanUseBlackwall( activatorObject, hotSpotObject );
	}

	protected const function BlackwallForceEnabled( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject > ) : Bool
	{
		const var player : PlayerPuppet;
		player = ( ( PlayerPuppet )( activatorObject ) );
		return player.IsBlackwallForceEquippedOnPlayer() && !( StatusEffectSystem.ObjectHasStatusEffectWithTag( player, 'BlackwallSQCooldown' ) );
	}

	protected const function TargetMarkedByBlackwall( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject > ) : Bool
	{
		var target : GameObject;
		target = hotSpotObject;
		return StatusEffectSystem.ObjectHasStatusEffectWithTag( target, 'BlackwallMark' );
	}

	protected const function CanUseBlackwall( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject > ) : Bool
	{
		return BlackwallForceEnabled( activatorObject, hotSpotObject ) && TargetMarkedByBlackwall( activatorObject, hotSpotObject );
	}

}

class ContainerStateInteractionCondition extends InteractionScriptedCondition
{

	public export const function Test( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject > ) : Bool
	{
		var container : gameLootContainerBase;
		container = ( ( gameLootContainerBase )( hotSpotObject ) );
		if( container )
		{
			return !( container.IsDisabled() );
		}
		else
		{
			return false;
		}
	}

}

class DeviceDirectInteractionCondition extends InteractionScriptedCondition
{

	public export const function Test( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject > ) : Bool
	{
		return ( ( Device )( hotSpotObject ) ).IsDirectInteractionCondition();
	}

}

class IsPlayerNotInteractingWithDevice extends InteractionScriptedCondition
{

	public const function Test( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject > ) : Bool
	{
		const var player : PlayerPuppet;
		var result : Bool;
		player = ( ( PlayerPuppet )( activatorObject ) );
		result = !( player.GetPlayerStateMachineBlackboard().GetBool( GetAllBlackboardDefs().PlayerStateMachine.IsInteractingWithDevice ) );
		return result;
	}

}

class DeviceRemoteInteractionCondition extends InteractionScriptedCondition
{

	public const function Test( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject > ) : Bool
	{
		if( !( IsScannerTarget( hotSpotObject ) ) && !( IsLookaAtTarget( activatorObject, hotSpotObject ) ) )
		{
			return false;
		}
		return ShouldEnableLayer( hotSpotObject );
	}

	private const function IsScannerTarget( const hotSpotObject : weak< GameObject > ) : Bool
	{
		var blackBoard : IBlackboard;
		var entityID : EntityID;
		blackBoard = GameInstance.GetBlackboardSystem( hotSpotObject.GetGame() ).Get( GetAllBlackboardDefs().UI_Scanner );
		entityID = blackBoard.GetEntityID( GetAllBlackboardDefs().UI_Scanner.ScannedObject );
		return hotSpotObject.GetEntityID() == entityID;
	}

	private const function IsLookaAtTarget( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject > ) : Bool
	{
		return GameInstance.GetInteractionManager( activatorObject.GetGame() ).IsInteractionLookAtTarget( activatorObject, hotSpotObject );
	}

	private const function ShouldEnableLayer( const hotSpotObject : weak< GameObject > ) : Bool
	{
		if( hotSpotObject )
		{
			return hotSpotObject.ShouldEnableRemoteLayer();
		}
		else
		{
			return false;
		}
	}

}

class PlayerIsSwimmingCondition extends InteractionScriptedCondition
{

	public const function Test( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject > ) : Bool
	{
		const var player : PlayerPuppet;
		var result : Bool;
		player = ( ( PlayerPuppet )( activatorObject ) );
		result = player.GetPlayerStateMachineBlackboard().GetInt( GetAllBlackboardDefs().PlayerStateMachine.HighLevel ) == ( ( Int32 )( gamePSMHighLevel.Swimming ) );
		return result;
	}

}

class LootPickupScriptedCondition extends InteractionScriptedCondition
{

	public export const function Test( const activatorObject : weak< GameObject >, const hotSpotObject : weak< GameObject > ) : Bool
	{
		var weaponRecord : WeaponItem_Record;
		var weaponObject : WeaponObject;
		var itemObject : ItemObject;
		var itemDropObject : gameItemDropObject;
		var itemType : gamedataItemType;
		var isGrenade, isHealingItem : Bool;
		var player : PlayerPuppet;
		var chargeItemCurrentCharge, chargeItemMaxCharge, chargeCost : Float;
		player = ( ( PlayerPuppet )( activatorObject ) );
		itemDropObject = ( ( gameItemDropObject )( hotSpotObject ) );
		itemObject = itemDropObject.GetItemObject();
		weaponObject = ( ( WeaponObject )( itemObject ) );
		if( weaponObject )
		{
			weaponRecord = weaponObject.GetWeaponRecord();
			if( weaponRecord.EquipArea().Type() == gamedataEquipmentArea.WeaponHeavy )
			{
				if( player.GetPlayerStateMachineBlackboard().GetBool( GetAllBlackboardDefs().PlayerStateMachine.Carrying ) )
				{
					return false;
				}
			}
		}
		itemType = itemObject.GetItemData().GetItemType();
		isGrenade = itemType == gamedataItemType.Gad_Grenade;
		isHealingItem = itemType == gamedataItemType.Con_Inhaler || itemType == gamedataItemType.Con_Injector;
		if( ( isGrenade || isHealingItem ) && !( itemObject.GetItemData().HasTag( 'ForceRevealConsumable' ) ) )
		{
			chargeItemCurrentCharge = GameInstance.GetStatPoolsSystem( player.GetGame() ).GetStatPoolValue( player.GetEntityID(), ( ( isGrenade ) ? ( gamedataStatPoolType.GrenadesCharges ) : ( gamedataStatPoolType.HealingItemsCharges ) ), false );
			chargeItemMaxCharge = GameInstance.GetStatsSystem( player.GetGame() ).GetStatValue( player.GetEntityID(), ( ( isGrenade ) ? ( gamedataStatType.GrenadesMaxCharges ) : ( gamedataStatType.HealingItemMaxCharges ) ) );
			chargeCost = ( ( Float )( ( ( isGrenade ) ? ( player.GetGrenadeThrowCostClean() ) : ( player.GetHealingItemUseCost() ) ) ) );
			return ( chargeItemCurrentCharge / chargeCost ) < chargeItemMaxCharge;
		}
		return true;
	}

}

