#531 fix

#531 fix

//---------------------------------------------------------------------------------------
//  Copyright (c) 2016 Firaxis Games, Inc. All rights reserved.
//---------------------------------------------------------------------------------------
class X2Ability_ChosenAssassin extends X2Ability
	config(GameData_SoldierSkills);

var localized string HarborWave_Stun_Resisted;

var config int PARTINGSILK_PUSH_APPLY_CHANCE_PERCENT;
var config int PARTINGSILK_PUSH_APPLY_CHANCE_PERCENT_VANISHINGWIND;
var config int PARTINGSILK_DAZE_TURNS;
var config int VANISHINGWIND_ACTIONPOINTCOST;
var config int VANISHINGWIND_COOLDOWN_LOCAL;
var config int VANISHINGWIND_COOLDOWN_GLOBAL;
var config float VANISHINGWIND_MOBILITY_INCREASE;
var config float BENDINGREED_MOBILITY_INCREASE;
var config int HARBORWAVE_APPLY_CHANCE;
var config int HARBORWAVE_ACTIONPOINTCOST;
var config int HARBORWAVE_COOLDOWN_LOCAL;
var config int HARBORWAVE_COOLDOWN_GLOBAL;
var config int HARBORWAVE_LENGTH_TILES;
var config int HARBORWAVE_END_DIAMETER_TILES;
var config int HARBORWAVE_MAX_STUNS_ALLOWED;
var config int HARBORWAVE_KNOCKBACK_DISTANCE;
var config WeaponDamageValue HARBORWAVE_BASEDAMAGE;
var config int HARBORWAVE_DAZE_TURNS;
var config array<name> VANISHINGWIND_REVEAL_IGNORE_ABILITIES;
var config float LOSTANDABANDONED_HEALTH_THRESHOLD_PERCENT;

var privatewrite name LostAndAbandonedHealthThresholdEventName;

static function array<X2DataTemplate> CreateTemplates()
{
	local array<X2DataTemplate> Templates;

	Templates.AddItem(CreatePartingSilk());
	Templates.AddItem(CreateVanishingWind());
	Templates.AddItem(CreateVanishingWind_Scamper());
	Templates.AddItem(CreateVanishingWindReveal());
	Templates.AddItem(CreateBendingReed());
	Templates.AddItem(PurePassive('BendingReedPassive', "img:///UILibrary_XPACK_Common.PerkIcons.UIPerk_bendingreed"));
	Templates.AddItem(CreateHarborWave());

	// Special abilities for Lost and Abandonoed
	Templates.AddItem(CreateLostAndAbandonedChosenHealthThreshold());
	Templates.AddItem(CreateLostAndAbandonedChosenInit());

	return Templates;
}

static function X2DataTemplate CreatePartingSilk()
{
	local X2AbilityTemplate Template;
	local X2AbilityCost_ActionPoints ActionPointCost;
	local X2AbilityToHitCalc_StandardMelee StandardMelee;
	local array<name> SkipExclusions;
	local X2Effect_RemoveEffects RemoveEffects;
	local X2Effect_Knockback KnockbackEffect;
	local X2Effect_Dazed DazedEffect;
	local X2Effect_ApplyWeaponDamage WeaponDamageEffect;
	local X2AbilityCooldown_LocalAndGlobal Cooldown;
	local X2Condition_UnitProperty UnitPropertyCondition;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'PartingSilk');
	Template.IconImage = "img:///UILibrary_XPACK_Common.PerkIcons.UIPerk_partingsilk";
	Template.Hostility = eHostility_Offensive;
	Template.AbilitySourceName = 'eAbilitySource_Standard';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_AlwaysShow;
//BEGIN AUTOGENERATED CODE: Template Overrides 'PartingSilk'
	Template.bOverrideMeleeDeath = false;
	Template.bFrameEvenWhenUnitIsHidden = true;
//END AUTOGENERATED CODE: Template Overrides 'PartingSilk'

	ActionPointCost = new class'X2AbilityCost_ActionPoints';
	ActionPointCost.iNumPoints = 1;
	Template.AbilityCosts.AddItem(ActionPointCost);

	StandardMelee = new class'X2AbilityToHitCalc_StandardMelee';
	StandardMelee.bGuaranteedHit = true;
	Template.AbilityToHitCalc = StandardMelee;

	Template.AbilityTargetStyle = new class'X2AbilityTarget_MovingMelee';
	Template.TargetingMethod = class'X2TargetingMethod_MeleePath';

	Template.AbilityTriggers.AddItem(default.PlayerInputTrigger);
	Template.AbilityTriggers.AddItem(new class'X2AbilityTrigger_EndOfMove');

	Cooldown = new class'X2AbilityCooldown_LocalAndGlobal';
	Cooldown.iNumTurns = 1;
	Cooldown.NumGlobalTurns = 0;
	Template.AbilityCooldown = Cooldown;

	// Shooter Conditions
	//
	Template.AbilityShooterConditions.AddItem(default.LivingShooterProperty);
	SkipExclusions.AddItem(class'X2StatusEffects'.default.BurningName);
	SkipExclusions.AddItem(class'X2AbilityTemplateManager'.default.DisorientedName);
	Template.AddShooterEffectExclusions(SkipExclusions);

	RemoveEffects = new class'X2Effect_RemoveEffects';
	RemoveEffects.EffectNamesToRemove.AddItem(class'X2Effect_VanishingWind'.default.EffectName);
	RemoveEffects.bApplyOnMiss = true;
	Template.AddShooterEffect(RemoveEffects);

	// Target Conditions
	//
	Template.AbilityTargetConditions.AddItem(default.LivingHostileTargetProperty);
	Template.AbilityTargetConditions.AddItem(default.MeleeVisibilityCondition);

	// Exclude Turrets. Also only consider targets that are eligible for Extract/Kidnap.
	UnitPropertyCondition = new class'X2Condition_UnitProperty';
	UnitPropertyCondition.ExcludeTurret = true;
	UnitPropertyCondition.ExcludeRobotic = true;
	UnitPropertyCondition.ExcludeAlien = true;
	UnitPropertyCondition.ExcludeFriendlyToSource = true;
	UnitPropertyCondition.FailOnNonUnits = true;
	UnitPropertyCondition.RequireUnitSelectedFromHQ = true;
	Template.AbilityTargetConditions.AddItem(UnitPropertyCondition);

	WeaponDamageEffect = new class'X2Effect_ApplyWeaponDamage';
	WeaponDamageEffect.bIgnoreBaseDamage = true;
	WeaponDamageEffect.DamageTag = 'PartingSilk';
	Template.AddTargetEffect(WeaponDamageEffect);

	KnockbackEffect = new class'X2Effect_Knockback';
	KnockbackEffect.KnockbackDistance = 2;
	KnockbackEffect.ApplyChanceFn = ApplyChance_PartingSilk_Push;
	Template.AddTargetEffect(KnockbackEffect);

	//  Stunned effect if the unit is knocked back
	DazedEffect = class'X2StatusEffects_XPack'.static.CreateDazedStatusEffect(default.PARTINGSILK_DAZE_TURNS, 100);
	DazedEffect.bRemoveWhenSourceDies = true;
	DazedEffect.ApplyChanceFn = ApplyChance_PartingSilk_Daze;
	Template.AddTargetEffect(DazedEffect);

	Template.bAllowBonusWeaponEffects = true;
	Template.bSkipMoveStop = true;

	Template.BuildNewGameStateFn = PartingSilk_BuildGameState;
	Template.BuildVisualizationFn = TypicalAbility_BuildVisualization;
	Template.BuildInterruptGameStateFn = TypicalMoveEndAbility_BuildInterruptGameState;

	Template.CinescriptCameraType = "ChosenAssassin_PartingSilk";

	Template.PostActivationEvents.AddItem('PartingSilkActivated');

	Template.LostSpawnIncreasePerUse = class'X2AbilityTemplateManager'.default.MeleeLostSpawnIncreasePerUse;

	return Template;
}

static protected function XComGameState PartingSilk_BuildGameState(XComGameStateContext Context)
{
	local XComGameState GameState;
	local XComGameStateContext_Ability AbilityContext;
	local XComGameState_Unit AssassinUnitState;
	local int NumTilesToHide;
	local int TileIndex;

	// start with the normal movement game state
	GameState = TypicalMoveEndAbility_BuildGameState(Context);

	// and then truncate the movement so that the assassin teleports to the location
	// she will reveal from
	AbilityContext = XComGameStateContext_Ability(GameState.GetContext());

	AssassinUnitState = XComGameState_Unit(`XCOMHISTORY.GetGameStateForObjectID(AbilityContext.InputContext.SourceObject.ObjectID));
	if(AbilityContext.InputContext.MovementPaths.Length > 0 && (AssassinUnitState.AffectedByEffectNames.Find(class'X2Effect_VanishingWind'.default.EffectName) != INDEX_NONE))
	{
		// remove any local viewers before the point at which the assassin becomes visible. This behaves
		// as fog, where we want to begin visualizing the move to the local player at the point where
		// the assassin materializes
		NumTilesToHide = AbilityContext.ResultContext.PathResults[0].PathTileData.Length - class'X2Effect_VanishingWind'.default.PARTINGSILKREVEAL_MIN_TILE_DISTANCE;
		for(TileIndex = 0; TileIndex < NumTilesToHide; TileIndex++)
		{
			AbilityContext.ResultContext.PathResults[0].PathTileData[TileIndex].NumLocalViewers = 0;
		}
	}

	return GameState;
}

static function name ApplyChance_PartingSilk_Push(const out EffectAppliedData ApplyEffectParameters, XComGameState_BaseObject kNewTargetState, XComGameState NewGameState)
{
	local int RandRoll;
	local float ApplyChance;
	local XComGameState_Unit SourceUnit;

	SourceUnit = XComGameState_Unit(NewGameState.GetGameStateForObjectID(ApplyEffectParameters.SourceStateObjectRef.ObjectID));
	if( SourceUnit == none )
	{
		SourceUnit = XComGameState_Unit(`XCOMHISTORY.GetGameStateForObjectID(ApplyEffectParameters.SourceStateObjectRef.ObjectID));
	}

	ApplyChance = default.PARTINGSILK_PUSH_APPLY_CHANCE_PERCENT;

	if( SourceUnit.AffectedByEffectNames.Find(class'X2Effect_VanishingWind'.default.EffectName) != INDEX_NONE )
	{
		ApplyChance = default.PARTINGSILK_PUSH_APPLY_CHANCE_PERCENT_VANISHINGWIND;
	}

	RandRoll = `SYNC_RAND_STATIC(100);

	`log("ApplyChance_PartingSilk_Push check chance" @ ApplyChance @ "rolled" @ RandRoll);
	if (RandRoll <= ApplyChance)
	{
		`log("Success!");
		return 'AA_Success';
	}
	`log("Failed.");

	return 'AA_EffectChanceFailed';
}

static function name ApplyChance_PartingSilk_Daze(const out EffectAppliedData ApplyEffectParameters, XComGameState_BaseObject kNewTargetState, XComGameState NewGameState)
{
	local X2AbilityTemplate AbilityTemplate;
	local XComGameStateContext_Ability AbilityContext;
	local X2Effect TestEffect;
	local int EffectIndex;

	AbilityTemplate = class'XComGameState_Ability'.static.GetMyTemplateManager().FindAbilityTemplate(ApplyEffectParameters.AbilityInputContext.AbilityTemplateName);
	AbilityContext = XComGameStateContext_Ability(NewGameState.GetContext());

	// Check to see if Knockback was applied by the ability
	for (EffectIndex = 0; EffectIndex < AbilityTemplate.AbilityTargetEffects.Length; ++EffectIndex)
	{
		TestEffect = AbilityTemplate.AbilityTargetEffects[EffectIndex];
		if (X2Effect_Knockback(TestEffect) != None)
		{
			if (AbilityContext.FindTargetEffectApplyResult(TestEffect) == 'AA_Success')
			{
				return 'AA_Success';
			}

			break;
		}
	}

	return 'AA_EffectChanceFailed';
}

static function X2AbilityTemplate CreateVanishingWind(optional name TemplateName = 'VanishingWind')
{
	local X2AbilityTemplate Template;
	local X2AbilityCost_ActionPoints ActionPointCost;
	local X2AbilityCooldown_LocalAndGlobal Cooldown;
	local X2Effect_RemoveEffects RemoveEffects;
	local X2Effect_VanishingWind VanishingWindEffect;

	`CREATE_X2ABILITY_TEMPLATE(Template, TemplateName);
	Template.IconImage = "img:///UILibrary_XPACK_Common.PerkIcons.UIPerk_vanishingwind";
	Template.Hostility = eHostility_Neutral;
	Template.AbilitySourceName = 'eAbilitySource_Standard';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_AlwaysShow;

	Template.AdditionalAbilities.AddItem('VanishingWindReveal');
	Template.AdditionalAbilities.AddItem('VanishingWind_Scamper');

	ActionPointCost = new class'X2AbilityCost_ActionPoints';
	ActionPointCost.iNumPoints = default.VANISHINGWIND_ACTIONPOINTCOST;
	Template.AbilityCosts.AddItem(ActionPointCost);

	Cooldown = new class'X2AbilityCooldown_LocalAndGlobal';
	Cooldown.iNumTurns = default.VANISHINGWIND_COOLDOWN_LOCAL;
	Cooldown.NumGlobalTurns = default.VANISHINGWIND_COOLDOWN_GLOBAL;
	Template.AbilityCooldown = Cooldown;

	Template.AbilityToHitCalc = default.DeadEye;
	Template.AbilityTargetStyle = default.SelfTarget;
	Template.AbilityTriggers.AddItem(default.PlayerInputTrigger);

	Template.AbilityShooterConditions.AddItem(default.LivingShooterProperty);
	Template.AbilityShooterConditions.AddItem(class'X2Effect_Vanish'.static.VanishShooterEffectsCondition());

	// Add remove suppression
	RemoveEffects = new class'X2Effect_RemoveEffects';
	RemoveEffects.EffectNamesToRemove.AddItem(class'X2Effect_Suppression'.default.EffectName);
	RemoveEffects.EffectNamesToRemove.AddItem(class'X2Effect_TargetDefinition'.default.EffectName);
	Template.AddTargetEffect(RemoveEffects);

	VanishingWindEffect = new class'X2Effect_VanishingWind';
	VanishingWindEffect.BuildPersistentEffect(1, true, false, true);
	VanishingWindEffect.AddPersistentStatChange(eStat_Mobility, default.VANISHINGWIND_MOBILITY_INCREASE, MODOP_Multiplication);
	VanishingWindEffect.VanishSyncAnimName = 'ADD_HL_VanishingWindBase_Immediate';
	Template.AddTargetEffect(VanishingWindEffect);

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	Template.BuildVisualizationFn = TypicalAbility_BuildVisualization;

	Template.CustomFireAnim = 'HL_VanishingWind';
	Template.bSkipExitCoverWhenFiring = true;
	Template.bShowActivation = true;

	Template.CinescriptCameraType = "ChosenAssassin_VanishingWind";

	return Template;
}

static function X2DataTemplate CreateVanishingWind_Scamper()
{
	local X2AbilityTemplate Template;

	Template = CreateVanishingWind('VanishingWind_Scamper');

	// Clear the AdditionalAbilities
	Template.AdditionalAbilities.Length = 0;

	Template.BuildVisualizationFn = CreateVanishingWind_Scamper_BuildVisualization;
	Template.MergeVisualizationFn = CreateVanishingWind_Scamper_MergeVisualization;

	Template.bShowActivation = false;
	Template.bSkipFireAction = true;
	Template.bFrameEvenWhenUnitIsHidden = false;
	Template.FrameAbilityCameraType = eCameraFraming_Never;
	Template.CinescriptCameraType = "";

	return Template;
}

simulated function CreateVanishingWind_Scamper_BuildVisualization(XComGameState VisualizeGameState)
{

	local XComGameStateHistory History;
	local VisualizationActionMetadata ActionMetadata;
	local XComGameStateContext_Ability Context;
	local X2Action_PlayAnimation PlayAnimAction;
	local XComGameState_Ability Ability;
	local X2AbilityTemplate AbilityTemplate;
	local int EffectIndex;
	local X2Effect_Persistent TestEffect;

	History = `XCOMHISTORY;

	Context = XComGameStateContext_Ability(VisualizeGameState.GetContext());
	Ability = XComGameState_Ability(History.GetGameStateForObjectID(Context.InputContext.AbilityRef.ObjectID));
	AbilityTemplate = Ability.GetMyTemplate();

	//Configure the visualization track for the shooter
	//****************************************************************************************
	ActionMetadata.StateObject_OldState = History.GetGameStateForObjectID(Context.InputContext.SourceObject.ObjectID, eReturnType_Reference, VisualizeGameState.HistoryIndex - 1);
	ActionMetadata.StateObject_NewState = VisualizeGameState.GetGameStateForObjectID(Context.InputContext.SourceObject.ObjectID);
	ActionMetadata.VisualizeActor = History.GetVisualizer(Context.InputContext.SourceObject.ObjectID);

	// Play the immediate animation
	PlayAnimAction = X2Action_PlayAnimation(class'X2Action_PlayAnimation'.static.AddToVisualizationTree(ActionMetadata, Context));
	PlayAnimAction.Params.AnimName = 'ADD_HL_VanishingWindBase_Immediate';
	PlayAnimAction.Params.BlendTime = 0.0f;
	PlayAnimAction.Params.Additive = true;

	// Do the usual VanishingWind effect visuals
	for (EffectIndex = 0; EffectIndex < AbilityTemplate.AbilityTargetEffects.Length; ++EffectIndex)
	{
		TestEffect = X2Effect_Persistent(AbilityTemplate.AbilityTargetEffects[EffectIndex]);
		if( (TestEffect != none) &&
			(TestEffect.EffectName == 'VanishingWind') )
		{
			AbilityTemplate.AbilityTargetEffects[EffectIndex].AddX2ActionsForVisualization(VisualizeGameState, ActionMetadata, Context.FindShooterEffectApplyResult(AbilityTemplate.AbilityTargetEffects[EffectIndex]));
			break;
		}
	}
}

function CreateVanishingWind_Scamper_MergeVisualization(X2Action BuildTree, out X2Action VisualizationTree)
{
	local XComGameStateVisualizationMgr VisMgr;
	local XComGameStateContext_Ability Context;
	local X2Action_MarkerTreeInsertBegin MarkerStart;
	local X2Action_MarkerNamed RemoveShowSpawnedUnit;
	local Array<X2Action> FoundActions;
	local X2Action ShowUnitAction;
	local int i;

	VisMgr = `XCOMVISUALIZATIONMGR;

	MarkerStart = X2Action_MarkerTreeInsertBegin(VisMgr.GetNodeOfType(BuildTree, class'X2Action_MarkerTreeInsertBegin'));
	Context = XComGameStateContext_Ability(MarkerStart.StateChangeContext);

	Context.SuperMergeIntoVisualizationTree(BuildTree, VisualizationTree);

	VisMgr.GetNodesOfType(VisualizationTree, class'X2Action_ShowSpawnedUnit', FoundActions, BuildTree.Metadata.VisualizeActor);
	for( i = 0; i < FoundActions.Length; ++i )
	{
		ShowUnitAction = FoundActions[i];
		if( !ShowUnitAction.bCompleted )
		{
			RemoveShowSpawnedUnit = X2Action_MarkerNamed(class'X2Action'.static.CreateVisualizationActionClass(class'X2Action_MarkerNamed', ShowUnitAction.StateChangeContext));
			RemoveShowSpawnedUnit.SetName("RemoveShowSpawnedUnitStub");
			VisMgr.ReplaceNode(RemoveShowSpawnedUnit, ShowUnitAction);
		}
	}
}
static function X2DataTemplate CreateVanishingWindReveal()
{
	local X2AbilityTemplate Template;
	local X2Condition_UnitEffects UnitEffectsCondition;
	local X2Effect_RemoveEffects RemoveEffects;
	local X2AbilityTrigger_EventListener Trigger;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'VanishingWindReveal');
	Template.IconImage = "img:///UILibrary_XPACK_Common.PerkIcons.UIPerk_vanishingwind";
	Template.Hostility = eHostility_Neutral;
	Template.AbilitySourceName = 'eAbilitySource_Standard';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_ShowIfAvailable;

	Template.AbilityToHitCalc = default.DeadEye;
	Template.AbilityTargetStyle = default.SelfTarget;

	Template.AbilityTriggers.AddItem(default.PlayerInputTrigger);

	// This ability fires can when the unit gets hit by a scan
	Trigger = new class'X2AbilityTrigger_EventListener';
	Trigger.ListenerData.Deferral = ELD_OnStateSubmitted;
	Trigger.ListenerData.EventID = class'X2Effect_ScanningProtocol'.default.ScanningProtocolTriggeredEventName;
	Trigger.ListenerData.EventFn = class'XComGameState_Ability'.static.AbilityTriggerEventListener_Self;
	Trigger.ListenerData.Filter = eFilter_Unit;
	Template.AbilityTriggers.AddItem(Trigger);

	// This ability fires when the unit is flanked by an enemy
	Trigger = new class'X2AbilityTrigger_EventListener';
	Trigger.ListenerData.Deferral = ELD_OnStateSubmitted;
	Trigger.ListenerData.EventFn = class'XComGameState_Ability'.static.AbilityTriggerEventListener_AssassinIsFlankedByMovedUnit;
	Trigger.ListenerData.EventID = 'UnitMoveFinished';
	Template.AbilityTriggers.AddItem(Trigger);

	// This ability fires when the unit is flanked by an enemy
	Trigger = new class'X2AbilityTrigger_EventListener';
	Trigger.ListenerData.Deferral = ELD_OnStateSubmitted;
	Trigger.ListenerData.EventFn = class'XComGameState_Ability'.static.AbilityTriggerEventListener_UnitIsFlankedByMovedUnit;
	Trigger.ListenerData.EventID = 'TileDataChanged';
	Template.AbilityTriggers.AddItem(Trigger);

	// This ability fires when the unit is damaged
	Trigger = new class'X2AbilityTrigger_EventListener';
	Trigger.ListenerData.Deferral = ELD_OnStateSubmitted;
	Trigger.ListenerData.EventID = 'UnitTakeEffectDamage';
	Trigger.ListenerData.EventFn = class'XComGameState_Ability'.static.AbilityTriggerEventListener_Self;
	Trigger.ListenerData.Filter = eFilter_Unit;
	Template.AbilityTriggers.AddItem(Trigger);

	// This ability fires when the unit gets a certain effect added to it
	Trigger = new class'X2AbilityTrigger_EventListener';
	Trigger.ListenerData.Deferral = ELD_OnStateSubmitted;
	Trigger.ListenerData.EventFn = class'XComGameState_Ability'.static.AbilityTriggerEventListener_VanishedUnitPersistentEffectAdded;
	Trigger.ListenerData.EventID = 'PersistentEffectAdded';
	Trigger.ListenerData.Filter = eFilter_Unit;
	Template.AbilityTriggers.AddItem(Trigger);

	// The shooter must have the VanishingWind Effect
	UnitEffectsCondition = new class'X2Condition_UnitEffects';
	UnitEffectsCondition.AddRequireEffect(class'X2Effect_VanishingWind'.default.EffectName, 'AA_MissingRequiredEffect');
	Template.AbilityShooterConditions.AddItem(UnitEffectsCondition);

	RemoveEffects = new class'X2Effect_RemoveEffects';
	RemoveEffects.EffectNamesToRemove.AddItem(class'X2Effect_VanishingWind'.default.EffectName);
	Template.AddShooterEffect(RemoveEffects);

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	Template.BuildVisualizationFn = TypicalAbility_BuildVisualization;
	Template.MergeVisualizationFn = VanishingWindReveal_MergeVisualization;

	Template.bSkipFireAction = true;
	Template.bShowPostActivation = true;

	Template.CinescriptCameraType = "ChosenAssassin_VanishingWindReveal";
//BEGIN AUTOGENERATED CODE: Template Overrides 'VanishingWindReveal'
	Template.bFrameEvenWhenUnitIsHidden = true;
//END AUTOGENERATED CODE: Template Overrides 'VanishingWindReveal'

	Template.AssociatedPlayTiming = SPT_AfterSequential;

	return Template;
}

function VanishingWindReveal_MergeVisualization(X2Action BuildTree, out X2Action VisualizationTree)
{
	local XComGameStateVisualizationMgr VisMgr;
	local X2Action_MarkerTreeInsertBegin MarkerStart;
	local X2Action_RevealArea RevealAction;
	local X2Action_CameraLookAt CameraAction;
	local XComGameStateContext_Ability Context;
	local Array<X2Action> FoundActions;
	local XComGameState_Unit GameStateUnit;
	local XComWorldData WorldData;
	local XComGameStateHistory History;
	local int i;
	local vector NewTargetLoc;

	VisMgr = `XCOMVISUALIZATIONMGR;
	History = `XCOMHISTORY;

	MarkerStart = X2Action_MarkerTreeInsertBegin(VisMgr.GetNodeOfType(BuildTree, class'X2Action_MarkerTreeInsertBegin'));
	Context = XComGameStateContext_Ability(MarkerStart.StateChangeContext);

	GameStateUnit = XComGameState_Unit(History.GetGameStateForObjectID(Context.InputContext.PrimaryTarget.ObjectID, , Context.AssociatedState.HistoryIndex));

	if( GameStateUnit != none )
	{
		WorldData = `XWORLD;
		NewTargetLoc = WorldData.GetPositionFromTileCoordinates(GameStateUnit.TileLocation);

		VisMgr.GetNodesOfType(BuildTree, class'X2Action_RevealArea', FoundActions, , Context.InputContext.PrimaryTarget.ObjectID);
		for( i = 0; i < FoundActions.Length; ++i )
		{
			RevealAction = X2Action_RevealArea(FoundActions[i]);
			if( (RevealAction != none) &&
				!RevealAction.bDestroyViewer )
			{
				RevealAction.bUseCurrentVisualizerLoc = false;
				RevealAction.TargetLocation = NewTargetLoc;
			}
		}

		FoundActions.Length = 0;
		VisMgr.GetNodesOfType(BuildTree, class'X2Action_CameraLookAt', FoundActions, , Context.InputContext.PrimaryTarget.ObjectID);

		for( i = 0; i < FoundActions.Length; ++i )
		{
			CameraAction = X2Action_CameraLookAt(FoundActions[i]);
			if( CameraAction != none )
			{
				CameraAction.LookAtActor = none;
				CameraAction.LookAtLocation = NewTargetLoc;
			}
		}
	}

	Context.SuperMergeIntoVisualizationTree(BuildTree, VisualizationTree);
}

static function X2AbilityTemplate CreateBendingReed(name TemplateName = 'BendingReed')
{
	local X2AbilityTemplate Template;
	local X2Effect_GrantActionPoints ActionPointEffect;
	local X2AbilityTrigger_EventListener EventListener;
	local X2Effect_PersistentStatChange MobilityIncrease;

	`CREATE_X2ABILITY_TEMPLATE(Template, TemplateName);
	Template.IconImage = "img:///UILibrary_XPACK_Common.PerkIcons.UIPerk_bendingreed";
	Template.Hostility = eHostility_Neutral;
	Template.AbilitySourceName = 'eAbilitySource_Standard';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_NeverShow;

	Template.AdditionalAbilities.AddItem('BendingReedPassive');

	Template.AbilityToHitCalc = default.DeadEye;
	Template.AbilityTargetStyle = default.SelfTarget;

	EventListener = new class'X2AbilityTrigger_EventListener';
	EventListener.ListenerData.Deferral = ELD_OnStateSubmitted;
	EventListener.ListenerData.EventFn = class'XComGameState_Ability'.static.AbilityTriggerEventListener_Self;
	EventListener.ListenerData.EventID = 'PartingSilkActivated';
	EventListener.ListenerData.Filter = eFilter_Unit;
	Template.AbilityTriggers.AddItem(EventListener);

	Template.AbilityShooterConditions.AddItem(default.LivingShooterProperty);

	ActionPointEffect = new class'X2Effect_GrantActionPoints';
	ActionPointEffect.NumActionPoints = 1;
	ActionPointEffect.PointType = class'X2CharacterTemplateManager'.default.MoveActionPoint;
	Template.AddShooterEffect(ActionPointEffect);

	MobilityIncrease = new class'X2Effect_PersistentStatChange';
	// Single line change for #531. eGameRule_PlayerTurnEnd used not eGameRule_PlayerTurnBegin so that the normal mobility is shown by mods which can show enemy stats. Because of this bIgnorePlayerCheckOnTick also set to gurantee never starts a turn with this active, somehow!
	MobilityIncrease.BuildPersistentEffect(1, false, true, true, eGameRule_PlayerTurnEnd);
	MobilityIncrease.AddPersistentStatChange(eStat_Mobility, default.BENDINGREED_MOBILITY_INCREASE, MODOP_Multiplication);
	Template.AddShooterEffect(MobilityIncrease);

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	Template.BuildVisualizationFn = TypicalAbility_BuildVisualization;

	Template.bSkipFireAction = true;
	Template.bShowActivation = true;
	Template.bFrameEvenWhenUnitIsHidden = true;

	return Template;
}

static function X2DataTemplate CreateHarborWave()
{
	local X2AbilityTemplate Template;
	local X2AbilityCost_ActionPoints ActionPointCost;
	local X2AbilityCooldown_LocalAndGlobal Cooldown;
	local X2AbilityTarget_Cursor CursorTarget;
	local X2AbilityMultiTarget_Cone ConeMultiTarget;
	local X2Effect_Dazed DazedEffect;
	local X2Effect_ApplyWeaponDamage PhysicalDamageEffect;
	local X2Condition_UnitType UnitTypeCondition;
	local X2Effect_Knockback KnockbackEffect;
	local X2AbilityToHitCalc_PercentChance ApplyChance;
	local array<name> SkipExclusions;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'HarborWave');
	Template.IconImage = "img:///UILibrary_XPACK_Common.PerkIcons.UIPerk_harborwave";

	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_AlwaysShow;
	Template.AbilitySourceName = 'eAbilitySource_Standard';
	Template.Hostility = eHostility_Offensive;

	// This ability is a free action
	ActionPointCost = new class'X2AbilityCost_ActionPoints';
	ActionPointCost.iNumPoints = default.HARBORWAVE_ACTIONPOINTCOST;
	Template.AbilityCosts.AddItem(ActionPointCost);

	Cooldown = new class'X2AbilityCooldown_LocalAndGlobal';
	Cooldown.iNumTurns = default.HARBORWAVE_COOLDOWN_LOCAL;
	Cooldown.NumGlobalTurns = default.HARBORWAVE_COOLDOWN_GLOBAL;
	Template.AbilityCooldown = Cooldown;

	//Can't use while dead
	Template.AbilityShooterConditions.AddItem(default.LivingShooterProperty);

	Template.AbilityShooterConditions.AddItem(default.LivingShooterProperty);

	SkipExclusions.AddItem(class'X2StatusEffects'.default.BurningName);
	SkipExclusions.AddItem(class'X2AbilityTemplateManager'.default.DisorientedName);
	Template.AddShooterEffectExclusions(SkipExclusions);

	ApplyChance = new class'X2AbilityToHitCalc_PercentChance';
	ApplyChance.PercentToHit = default.HARBORWAVE_APPLY_CHANCE;
	Template.AbilityToHitCalc = ApplyChance;
	Template.AbilityTriggers.AddItem(default.PlayerInputTrigger);

	Template.TargetingMethod = class'X2TargetingMethod_Cone';

	CursorTarget = new class'X2AbilityTarget_Cursor';
	CursorTarget.bRestrictToWeaponRange = false;
	CursorTarget.FixedAbilityRange = default.HARBORWAVE_LENGTH_TILES * class'XComWorldData'.const.WORLD_StepSize;
	Template.AbilityTargetStyle = CursorTarget;

	ConeMultiTarget = new class'X2AbilityMultiTarget_Cone';
	ConeMultiTarget.ConeEndDiameter = default.HARBORWAVE_END_DIAMETER_TILES * class'XComWorldData'.const.WORLD_StepSize;
	ConeMultiTarget.ConeLength = default.HARBORWAVE_LENGTH_TILES * class'XComWorldData'.const.WORLD_StepSize;
	ConeMultiTarget.fTargetRadius = Sqrt(Square(ConeMultiTarget.ConeEndDiameter / 2) + Square(ConeMultiTarget.ConeLength)) * class'XComWorldData'.const.WORLD_UNITS_TO_METERS_MULTIPLIER;
	ConeMultiTarget.bExcludeSelfAsTargetIfWithinRadius = true;
	ConeMultiTarget.bLockShooterZ = true;
	Template.AbilityMultiTargetStyle = ConeMultiTarget;

	Template.AbilityMultiTargetConditions.AddItem(default.LivingHostileUnitOnlyProperty);

	// Damage from Harbor Wave
	PhysicalDamageEffect = new class'X2Effect_ApplyWeaponDamage';
	PhysicalDamageEffect.EffectDamageValue = default.HARBORWAVE_BASEDAMAGE;
	PhysicalDamageEffect.EffectDamageValue.DamageType = 'HarborWave';
	PhysicalDamageEffect.bApplyOnMiss = true;
	PhysicalDamageEffect.OverrideMissMessage = default.HarborWave_Stun_Resisted;

	// Only The Lost get damaged (for now)
	UnitTypeCondition = new class'X2Condition_UnitType';
	UnitTypeCondition.IncludeTypes.AddItem('TheLost');
	PhysicalDamageEffect.TargetConditions.AddItem(UnitTypeCondition);

	Template.AddMultiTargetEffect(PhysicalDamageEffect);

	// Knockback and Stun
	// Lost don't get knockback or dazed
	UnitTypeCondition = new class'X2Condition_UnitType';
	UnitTypeCondition.ExcludeTypes.AddItem('TheLost');

	KnockbackEffect = new class'X2Effect_Knockback';
	KnockbackEffect.KnockbackDistance = default.HARBORWAVE_KNOCKBACK_DISTANCE;
	KnockbackEffect.OnlyOnDeath = false;
	KnockbackEffect.TargetConditions.AddItem(UnitTypeCondition);
	Template.AddMultiTargetEffect(KnockbackEffect);

	// Dazed effect if the unit is knocked back
	DazedEffect = class'X2StatusEffects_XPack'.static.CreateDazedStatusEffect(default.HARBORWAVE_DAZE_TURNS, 100);
	DazedEffect.bRemoveWhenSourceDies = true;
	DazedEffect.TargetConditions.AddItem(UnitTypeCondition);
	DazedEffect.VisualizationFn = HarborWave_DazedVisualization;
	Template.AddMultiTargetEffect(DazedEffect);

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	Template.BuildVisualizationFn = TypicalAbility_BuildVisualization;

	Template.CustomFireAnim = 'HL_HarborWave';
	Template.bShowActivation = true;
	Template.ActionFireClass = class'X2Action_Fire_Wave';

	Template.CinescriptCameraType = "ChosenAssassin_HarborWave";
//BEGIN AUTOGENERATED CODE: Template Overrides 'HarborWave'
	Template.bFrameEvenWhenUnitIsHidden = true;
//END AUTOGENERATED CODE: Template Overrides 'HarborWave'

	return Template;
}

static function HarborWave_DazedVisualization(XComGameState VisualizeGameState, out VisualizationActionMetadata ActionMetadata, const name EffectApplyResult)
{
	if( EffectApplyResult == 'AA_Success' )
	{
		class'X2StatusEffects_XPack'.static.DazedVisualization(VisualizeGameState, ActionMetadata, EffectApplyResult);
	}
}

static function X2AbilityTemplate CreateLostAndAbandonedChosenHealthThreshold()
{
	local X2AbilityTemplate Template;
	local X2AbilityTrigger_EventListener Trigger;
	local X2Condition_UnitValue UnitValue;
	local X2Effect_TriggerEvent TriggerEventEffect;
	local X2Effect_SetUnitValue SetUnitValue;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'LostAndAbandonedChosenHealthThreshold');

	Template.IconImage = "img:///UILibrary_PerkIcons.UIPerk_none";
	Template.bDontDisplayInAbilitySummary = true;
	Template.AbilitySourceName = 'eAbilitySource_Standard';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_NeverShow;
	Template.Hostility = eHostility_Neutral;
	Template.bIsPassive = true;

	Template.AdditionalAbilities.AddItem('LostAndAbandonedChosenInit');

	Template.AbilityToHitCalc = default.DeadEye;
	Template.AbilityTargetStyle = default.SelfTarget;

	// This ability fires can when the unit gets hit by a scan
	Trigger = new class'X2AbilityTrigger_EventListener';
	Trigger.ListenerData.Deferral = ELD_OnStateSubmitted;
	Trigger.ListenerData.EventID = 'UnitTakeEffectDamage';
	Trigger.ListenerData.EventFn = class'XComGameState_Ability'.static.LostAndAbandonedChosenHealthThresholdListener;
	Trigger.ListenerData.Filter = eFilter_Unit;
	Template.AbilityTriggers.AddItem(Trigger);

	// Do not trigger this ability if it has already triggered once
	UnitValue = new class'X2Condition_UnitValue';
	UnitValue.AddCheckValue('LostAndAbandonedAbilityTriggered', 1, eCheck_LessThan);

	TriggerEventEffect = new class'X2Effect_TriggerEvent';
	TriggerEventEffect.TriggerEventName = default.LostAndAbandonedHealthThresholdEventName;
	Template.AddTargetEffect(TriggerEventEffect);

	SetUnitValue = new class'X2Effect_SetUnitValue';
	SetUnitValue.UnitName = 'LostAndAbandonedAbilityTriggered';
	SetUnitValue.NewValueToSet = 2;
	SetUnitValue.CleanupType = eCleanup_BeginTactical;
	Template.AddTargetEffect(SetUnitValue);

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	// Note: no visualization on purpose!

	return Template;
}

static function X2AbilityTemplate CreateLostAndAbandonedChosenInit()
{
	local X2AbilityTemplate Template;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'LostAndAbandonedChosenInit');

	Template.IconImage = "img:///UILibrary_PerkIcons.UIPerk_none";
	Template.bDontDisplayInAbilitySummary = true;
	Template.AbilitySourceName = 'eAbilitySource_Standard';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_NeverShow;
	Template.Hostility = eHostility_Neutral;
	Template.bIsPassive = true;

	Template.AbilityToHitCalc = default.DeadEye;
	Template.AbilityTargetStyle = default.SelfTarget;
	Template.AbilityTriggers.AddItem(default.UnitPostBeginPlayTrigger);

	Template.AddShooterEffect(new class'X2Effect_Unkillable');

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	// Note: no visualization on purpose!

	return Template;
}

defaultproperties
{
	LostAndAbandonedHealthThresholdEventName="LostAndAbandonedHealthThresholdEvent"
}

//---------------------------------------------------------------------------------------
//  Copyright (c) 2016 Firaxis Games, Inc. All rights reserved.
//---------------------------------------------------------------------------------------
class X2Ability_ChosenAssassin extends X2Ability
	config(GameData_SoldierSkills);

var localized string HarborWave_Stun_Resisted;

var config int PARTINGSILK_PUSH_APPLY_CHANCE_PERCENT;
var config int PARTINGSILK_PUSH_APPLY_CHANCE_PERCENT_VANISHINGWIND;
var config int PARTINGSILK_DAZE_TURNS;
var config int VANISHINGWIND_ACTIONPOINTCOST;
var config int VANISHINGWIND_COOLDOWN_LOCAL;
var config int VANISHINGWIND_COOLDOWN_GLOBAL;
var config float VANISHINGWIND_MOBILITY_INCREASE;
var config float BENDINGREED_MOBILITY_INCREASE;
var config int HARBORWAVE_APPLY_CHANCE;
var config int HARBORWAVE_ACTIONPOINTCOST;
var config int HARBORWAVE_COOLDOWN_LOCAL;
var config int HARBORWAVE_COOLDOWN_GLOBAL;
var config int HARBORWAVE_LENGTH_TILES;
var config int HARBORWAVE_END_DIAMETER_TILES;
var config int HARBORWAVE_MAX_STUNS_ALLOWED;
var config int HARBORWAVE_KNOCKBACK_DISTANCE;
var config WeaponDamageValue HARBORWAVE_BASEDAMAGE;
var config int HARBORWAVE_DAZE_TURNS;
var config array<name> VANISHINGWIND_REVEAL_IGNORE_ABILITIES;
var config float LOSTANDABANDONED_HEALTH_THRESHOLD_PERCENT;

var privatewrite name LostAndAbandonedHealthThresholdEventName;

static function array<X2DataTemplate> CreateTemplates()
{
	local array<X2DataTemplate> Templates;

	Templates.AddItem(CreatePartingSilk());
	Templates.AddItem(CreateVanishingWind());
	Templates.AddItem(CreateVanishingWind_Scamper());
	Templates.AddItem(CreateVanishingWindReveal());
	Templates.AddItem(CreateBendingReed());
	Templates.AddItem(PurePassive('BendingReedPassive', "img:///UILibrary_XPACK_Common.PerkIcons.UIPerk_bendingreed"));
	Templates.AddItem(CreateHarborWave());

	// Special abilities for Lost and Abandonoed
	Templates.AddItem(CreateLostAndAbandonedChosenHealthThreshold());
	Templates.AddItem(CreateLostAndAbandonedChosenInit());

	return Templates;
}

static function X2DataTemplate CreatePartingSilk()
{
	local X2AbilityTemplate Template;
	local X2AbilityCost_ActionPoints ActionPointCost;
	local X2AbilityToHitCalc_StandardMelee StandardMelee;
	local array<name> SkipExclusions;
	local X2Effect_RemoveEffects RemoveEffects;
	local X2Effect_Knockback KnockbackEffect;
	local X2Effect_Dazed DazedEffect;
	local X2Effect_ApplyWeaponDamage WeaponDamageEffect;
	local X2AbilityCooldown_LocalAndGlobal Cooldown;
	local X2Condition_UnitProperty UnitPropertyCondition;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'PartingSilk');
	Template.IconImage = "img:///UILibrary_XPACK_Common.PerkIcons.UIPerk_partingsilk";
	Template.Hostility = eHostility_Offensive;
	Template.AbilitySourceName = 'eAbilitySource_Standard';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_AlwaysShow;
//BEGIN AUTOGENERATED CODE: Template Overrides 'PartingSilk'
	Template.bOverrideMeleeDeath = false;
	Template.bFrameEvenWhenUnitIsHidden = true;
//END AUTOGENERATED CODE: Template Overrides 'PartingSilk'

	ActionPointCost = new class'X2AbilityCost_ActionPoints';
	ActionPointCost.iNumPoints = 1;
	Template.AbilityCosts.AddItem(ActionPointCost);

	StandardMelee = new class'X2AbilityToHitCalc_StandardMelee';
	StandardMelee.bGuaranteedHit = true;
	Template.AbilityToHitCalc = StandardMelee;

	Template.AbilityTargetStyle = new class'X2AbilityTarget_MovingMelee';
	Template.TargetingMethod = class'X2TargetingMethod_MeleePath';

	Template.AbilityTriggers.AddItem(default.PlayerInputTrigger);
	Template.AbilityTriggers.AddItem(new class'X2AbilityTrigger_EndOfMove');

	Cooldown = new class'X2AbilityCooldown_LocalAndGlobal';
	Cooldown.iNumTurns = 1;
	Cooldown.NumGlobalTurns = 0;
	Template.AbilityCooldown = Cooldown;

	// Shooter Conditions
	//
	Template.AbilityShooterConditions.AddItem(default.LivingShooterProperty);
	SkipExclusions.AddItem(class'X2StatusEffects'.default.BurningName);
	SkipExclusions.AddItem(class'X2AbilityTemplateManager'.default.DisorientedName);
	Template.AddShooterEffectExclusions(SkipExclusions);

	RemoveEffects = new class'X2Effect_RemoveEffects';
	RemoveEffects.EffectNamesToRemove.AddItem(class'X2Effect_VanishingWind'.default.EffectName);
	RemoveEffects.bApplyOnMiss = true;
	Template.AddShooterEffect(RemoveEffects);

	// Target Conditions
	//
	Template.AbilityTargetConditions.AddItem(default.LivingHostileTargetProperty);
	Template.AbilityTargetConditions.AddItem(default.MeleeVisibilityCondition);

	// Exclude Turrets. Also only consider targets that are eligible for Extract/Kidnap.
	UnitPropertyCondition = new class'X2Condition_UnitProperty';
	UnitPropertyCondition.ExcludeTurret = true;
	UnitPropertyCondition.ExcludeRobotic = true;
	UnitPropertyCondition.ExcludeAlien = true;
	UnitPropertyCondition.ExcludeFriendlyToSource = true;
	UnitPropertyCondition.FailOnNonUnits = true;
	UnitPropertyCondition.RequireUnitSelectedFromHQ = true;
	Template.AbilityTargetConditions.AddItem(UnitPropertyCondition);

	WeaponDamageEffect = new class'X2Effect_ApplyWeaponDamage';
	WeaponDamageEffect.bIgnoreBaseDamage = true;
	WeaponDamageEffect.DamageTag = 'PartingSilk';
	Template.AddTargetEffect(WeaponDamageEffect);

	KnockbackEffect = new class'X2Effect_Knockback';
	KnockbackEffect.KnockbackDistance = 2;
	KnockbackEffect.ApplyChanceFn = ApplyChance_PartingSilk_Push;
	Template.AddTargetEffect(KnockbackEffect);

	//  Stunned effect if the unit is knocked back
	DazedEffect = class'X2StatusEffects_XPack'.static.CreateDazedStatusEffect(default.PARTINGSILK_DAZE_TURNS, 100);
	DazedEffect.bRemoveWhenSourceDies = true;
	DazedEffect.ApplyChanceFn = ApplyChance_PartingSilk_Daze;
	Template.AddTargetEffect(DazedEffect);

	Template.bAllowBonusWeaponEffects = true;
	Template.bSkipMoveStop = true;

	Template.BuildNewGameStateFn = PartingSilk_BuildGameState;
	Template.BuildVisualizationFn = TypicalAbility_BuildVisualization;
	Template.BuildInterruptGameStateFn = TypicalMoveEndAbility_BuildInterruptGameState;

	Template.CinescriptCameraType = "ChosenAssassin_PartingSilk";

	Template.PostActivationEvents.AddItem('PartingSilkActivated');

	Template.LostSpawnIncreasePerUse = class'X2AbilityTemplateManager'.default.MeleeLostSpawnIncreasePerUse;

	return Template;
}

static protected function XComGameState PartingSilk_BuildGameState(XComGameStateContext Context)
{
	local XComGameState GameState;
	local XComGameStateContext_Ability AbilityContext;
	local XComGameState_Unit AssassinUnitState;
	local int NumTilesToHide;
	local int TileIndex;

	// start with the normal movement game state
	GameState = TypicalMoveEndAbility_BuildGameState(Context);

	// and then truncate the movement so that the assassin teleports to the location
	// she will reveal from
	AbilityContext = XComGameStateContext_Ability(GameState.GetContext());

	AssassinUnitState = XComGameState_Unit(`XCOMHISTORY.GetGameStateForObjectID(AbilityContext.InputContext.SourceObject.ObjectID));
	if(AbilityContext.InputContext.MovementPaths.Length > 0 && (AssassinUnitState.AffectedByEffectNames.Find(class'X2Effect_VanishingWind'.default.EffectName) != INDEX_NONE))
	{
		// remove any local viewers before the point at which the assassin becomes visible. This behaves
		// as fog, where we want to begin visualizing the move to the local player at the point where
		// the assassin materializes
		NumTilesToHide = AbilityContext.ResultContext.PathResults[0].PathTileData.Length - class'X2Effect_VanishingWind'.default.PARTINGSILKREVEAL_MIN_TILE_DISTANCE;
		for(TileIndex = 0; TileIndex < NumTilesToHide; TileIndex++)
		{
			AbilityContext.ResultContext.PathResults[0].PathTileData[TileIndex].NumLocalViewers = 0;
		}
	}

	return GameState;
}

static function name ApplyChance_PartingSilk_Push(const out EffectAppliedData ApplyEffectParameters, XComGameState_BaseObject kNewTargetState, XComGameState NewGameState)
{
	local int RandRoll;
	local float ApplyChance;
	local XComGameState_Unit SourceUnit;

	SourceUnit = XComGameState_Unit(NewGameState.GetGameStateForObjectID(ApplyEffectParameters.SourceStateObjectRef.ObjectID));
	if( SourceUnit == none )
	{
		SourceUnit = XComGameState_Unit(`XCOMHISTORY.GetGameStateForObjectID(ApplyEffectParameters.SourceStateObjectRef.ObjectID));
	}

	ApplyChance = default.PARTINGSILK_PUSH_APPLY_CHANCE_PERCENT;

	if( SourceUnit.AffectedByEffectNames.Find(class'X2Effect_VanishingWind'.default.EffectName) != INDEX_NONE )
	{
		ApplyChance = default.PARTINGSILK_PUSH_APPLY_CHANCE_PERCENT_VANISHINGWIND;
	}

	RandRoll = `SYNC_RAND_STATIC(100);

	`log("ApplyChance_PartingSilk_Push check chance" @ ApplyChance @ "rolled" @ RandRoll);
	if (RandRoll <= ApplyChance)
	{
		`log("Success!");
		return 'AA_Success';
	}
	`log("Failed.");

	return 'AA_EffectChanceFailed';
}

static function name ApplyChance_PartingSilk_Daze(const out EffectAppliedData ApplyEffectParameters, XComGameState_BaseObject kNewTargetState, XComGameState NewGameState)
{
	local X2AbilityTemplate AbilityTemplate;
	local XComGameStateContext_Ability AbilityContext;
	local X2Effect TestEffect;
	local int EffectIndex;

	AbilityTemplate = class'XComGameState_Ability'.static.GetMyTemplateManager().FindAbilityTemplate(ApplyEffectParameters.AbilityInputContext.AbilityTemplateName);
	AbilityContext = XComGameStateContext_Ability(NewGameState.GetContext());

	// Check to see if Knockback was applied by the ability
	for (EffectIndex = 0; EffectIndex < AbilityTemplate.AbilityTargetEffects.Length; ++EffectIndex)
	{
		TestEffect = AbilityTemplate.AbilityTargetEffects[EffectIndex];
		if (X2Effect_Knockback(TestEffect) != None)
		{
			if (AbilityContext.FindTargetEffectApplyResult(TestEffect) == 'AA_Success')
			{
				return 'AA_Success';
			}

			break;
		}
	}

	return 'AA_EffectChanceFailed';
}

static function X2AbilityTemplate CreateVanishingWind(optional name TemplateName = 'VanishingWind')
{
	local X2AbilityTemplate Template;
	local X2AbilityCost_ActionPoints ActionPointCost;
	local X2AbilityCooldown_LocalAndGlobal Cooldown;
	local X2Effect_RemoveEffects RemoveEffects;
	local X2Effect_VanishingWind VanishingWindEffect;

	`CREATE_X2ABILITY_TEMPLATE(Template, TemplateName);
	Template.IconImage = "img:///UILibrary_XPACK_Common.PerkIcons.UIPerk_vanishingwind";
	Template.Hostility = eHostility_Neutral;
	Template.AbilitySourceName = 'eAbilitySource_Standard';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_AlwaysShow;

	Template.AdditionalAbilities.AddItem('VanishingWindReveal');
	Template.AdditionalAbilities.AddItem('VanishingWind_Scamper');

	ActionPointCost = new class'X2AbilityCost_ActionPoints';
	ActionPointCost.iNumPoints = default.VANISHINGWIND_ACTIONPOINTCOST;
	Template.AbilityCosts.AddItem(ActionPointCost);

	Cooldown = new class'X2AbilityCooldown_LocalAndGlobal';
	Cooldown.iNumTurns = default.VANISHINGWIND_COOLDOWN_LOCAL;
	Cooldown.NumGlobalTurns = default.VANISHINGWIND_COOLDOWN_GLOBAL;
	Template.AbilityCooldown = Cooldown;

	Template.AbilityToHitCalc = default.DeadEye;
	Template.AbilityTargetStyle = default.SelfTarget;
	Template.AbilityTriggers.AddItem(default.PlayerInputTrigger);

	Template.AbilityShooterConditions.AddItem(default.LivingShooterProperty);
	Template.AbilityShooterConditions.AddItem(class'X2Effect_Vanish'.static.VanishShooterEffectsCondition());

	// Add remove suppression
	RemoveEffects = new class'X2Effect_RemoveEffects';
	RemoveEffects.EffectNamesToRemove.AddItem(class'X2Effect_Suppression'.default.EffectName);
	RemoveEffects.EffectNamesToRemove.AddItem(class'X2Effect_TargetDefinition'.default.EffectName);
	Template.AddTargetEffect(RemoveEffects);

	VanishingWindEffect = new class'X2Effect_VanishingWind';
	VanishingWindEffect.BuildPersistentEffect(1, true, false, true);
	VanishingWindEffect.AddPersistentStatChange(eStat_Mobility, default.VANISHINGWIND_MOBILITY_INCREASE, MODOP_Multiplication);
	VanishingWindEffect.VanishSyncAnimName = 'ADD_HL_VanishingWindBase_Immediate';
	Template.AddTargetEffect(VanishingWindEffect);

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	Template.BuildVisualizationFn = TypicalAbility_BuildVisualization;

	Template.CustomFireAnim = 'HL_VanishingWind';
	Template.bSkipExitCoverWhenFiring = true;
	Template.bShowActivation = true;

	Template.CinescriptCameraType = "ChosenAssassin_VanishingWind";

	return Template;
}

static function X2DataTemplate CreateVanishingWind_Scamper()
{
	local X2AbilityTemplate Template;

	Template = CreateVanishingWind('VanishingWind_Scamper');

	// Clear the AdditionalAbilities
	Template.AdditionalAbilities.Length = 0;

	Template.BuildVisualizationFn = CreateVanishingWind_Scamper_BuildVisualization;
	Template.MergeVisualizationFn = CreateVanishingWind_Scamper_MergeVisualization;

	Template.bShowActivation = false;
	Template.bSkipFireAction = true;
	Template.bFrameEvenWhenUnitIsHidden = false;
	Template.FrameAbilityCameraType = eCameraFraming_Never;
	Template.CinescriptCameraType = "";

	return Template;
}

simulated function CreateVanishingWind_Scamper_BuildVisualization(XComGameState VisualizeGameState)
{

	local XComGameStateHistory History;
	local VisualizationActionMetadata ActionMetadata;
	local XComGameStateContext_Ability Context;
	local X2Action_PlayAnimation PlayAnimAction;
	local XComGameState_Ability Ability;
	local X2AbilityTemplate AbilityTemplate;
	local int EffectIndex;
	local X2Effect_Persistent TestEffect;

	History = `XCOMHISTORY;

	Context = XComGameStateContext_Ability(VisualizeGameState.GetContext());
	Ability = XComGameState_Ability(History.GetGameStateForObjectID(Context.InputContext.AbilityRef.ObjectID));
	AbilityTemplate = Ability.GetMyTemplate();

	//Configure the visualization track for the shooter
	//****************************************************************************************
	ActionMetadata.StateObject_OldState = History.GetGameStateForObjectID(Context.InputContext.SourceObject.ObjectID, eReturnType_Reference, VisualizeGameState.HistoryIndex - 1);
	ActionMetadata.StateObject_NewState = VisualizeGameState.GetGameStateForObjectID(Context.InputContext.SourceObject.ObjectID);
	ActionMetadata.VisualizeActor = History.GetVisualizer(Context.InputContext.SourceObject.ObjectID);

	// Play the immediate animation
	PlayAnimAction = X2Action_PlayAnimation(class'X2Action_PlayAnimation'.static.AddToVisualizationTree(ActionMetadata, Context));
	PlayAnimAction.Params.AnimName = 'ADD_HL_VanishingWindBase_Immediate';
	PlayAnimAction.Params.BlendTime = 0.0f;
	PlayAnimAction.Params.Additive = true;

	// Do the usual VanishingWind effect visuals
	for (EffectIndex = 0; EffectIndex < AbilityTemplate.AbilityTargetEffects.Length; ++EffectIndex)
	{
		TestEffect = X2Effect_Persistent(AbilityTemplate.AbilityTargetEffects[EffectIndex]);
		if( (TestEffect != none) &&
			(TestEffect.EffectName == 'VanishingWind') )
		{
			AbilityTemplate.AbilityTargetEffects[EffectIndex].AddX2ActionsForVisualization(VisualizeGameState, ActionMetadata, Context.FindShooterEffectApplyResult(AbilityTemplate.AbilityTargetEffects[EffectIndex]));
			break;
		}
	}
}

function CreateVanishingWind_Scamper_MergeVisualization(X2Action BuildTree, out X2Action VisualizationTree)
{
	local XComGameStateVisualizationMgr VisMgr;
	local XComGameStateContext_Ability Context;
	local X2Action_MarkerTreeInsertBegin MarkerStart;
	local X2Action_MarkerNamed RemoveShowSpawnedUnit;
	local Array<X2Action> FoundActions;
	local X2Action ShowUnitAction;
	local int i;

	VisMgr = `XCOMVISUALIZATIONMGR;

	MarkerStart = X2Action_MarkerTreeInsertBegin(VisMgr.GetNodeOfType(BuildTree, class'X2Action_MarkerTreeInsertBegin'));
	Context = XComGameStateContext_Ability(MarkerStart.StateChangeContext);

	Context.SuperMergeIntoVisualizationTree(BuildTree, VisualizationTree);

	VisMgr.GetNodesOfType(VisualizationTree, class'X2Action_ShowSpawnedUnit', FoundActions, BuildTree.Metadata.VisualizeActor);
	for( i = 0; i < FoundActions.Length; ++i )
	{
		ShowUnitAction = FoundActions[i];
		if( !ShowUnitAction.bCompleted )
		{
			RemoveShowSpawnedUnit = X2Action_MarkerNamed(class'X2Action'.static.CreateVisualizationActionClass(class'X2Action_MarkerNamed', ShowUnitAction.StateChangeContext));
			RemoveShowSpawnedUnit.SetName("RemoveShowSpawnedUnitStub");
			VisMgr.ReplaceNode(RemoveShowSpawnedUnit, ShowUnitAction);
		}
	}
}
static function X2DataTemplate CreateVanishingWindReveal()
{
	local X2AbilityTemplate Template;
	local X2Condition_UnitEffects UnitEffectsCondition;
	local X2Effect_RemoveEffects RemoveEffects;
	local X2AbilityTrigger_EventListener Trigger;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'VanishingWindReveal');
	Template.IconImage = "img:///UILibrary_XPACK_Common.PerkIcons.UIPerk_vanishingwind";
	Template.Hostility = eHostility_Neutral;
	Template.AbilitySourceName = 'eAbilitySource_Standard';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_ShowIfAvailable;

	Template.AbilityToHitCalc = default.DeadEye;
	Template.AbilityTargetStyle = default.SelfTarget;

	Template.AbilityTriggers.AddItem(default.PlayerInputTrigger);

	// This ability fires can when the unit gets hit by a scan
	Trigger = new class'X2AbilityTrigger_EventListener';
	Trigger.ListenerData.Deferral = ELD_OnStateSubmitted;
	Trigger.ListenerData.EventID = class'X2Effect_ScanningProtocol'.default.ScanningProtocolTriggeredEventName;
	Trigger.ListenerData.EventFn = class'XComGameState_Ability'.static.AbilityTriggerEventListener_Self;
	Trigger.ListenerData.Filter = eFilter_Unit;
	Template.AbilityTriggers.AddItem(Trigger);

	// This ability fires when the unit is flanked by an enemy
	Trigger = new class'X2AbilityTrigger_EventListener';
	Trigger.ListenerData.Deferral = ELD_OnStateSubmitted;
	Trigger.ListenerData.EventFn = class'XComGameState_Ability'.static.AbilityTriggerEventListener_AssassinIsFlankedByMovedUnit;
	Trigger.ListenerData.EventID = 'UnitMoveFinished';
	Template.AbilityTriggers.AddItem(Trigger);

	// This ability fires when the unit is flanked by an enemy
	Trigger = new class'X2AbilityTrigger_EventListener';
	Trigger.ListenerData.Deferral = ELD_OnStateSubmitted;
	Trigger.ListenerData.EventFn = class'XComGameState_Ability'.static.AbilityTriggerEventListener_UnitIsFlankedByMovedUnit;
	Trigger.ListenerData.EventID = 'TileDataChanged';
	Template.AbilityTriggers.AddItem(Trigger);

	// This ability fires when the unit is damaged
	Trigger = new class'X2AbilityTrigger_EventListener';
	Trigger.ListenerData.Deferral = ELD_OnStateSubmitted;
	Trigger.ListenerData.EventID = 'UnitTakeEffectDamage';
	Trigger.ListenerData.EventFn = class'XComGameState_Ability'.static.AbilityTriggerEventListener_Self;
	Trigger.ListenerData.Filter = eFilter_Unit;
	Template.AbilityTriggers.AddItem(Trigger);

	// This ability fires when the unit gets a certain effect added to it
	Trigger = new class'X2AbilityTrigger_EventListener';
	Trigger.ListenerData.Deferral = ELD_OnStateSubmitted;
	Trigger.ListenerData.EventFn = class'XComGameState_Ability'.static.AbilityTriggerEventListener_VanishedUnitPersistentEffectAdded;
	Trigger.ListenerData.EventID = 'PersistentEffectAdded';
	Trigger.ListenerData.Filter = eFilter_Unit;
	Template.AbilityTriggers.AddItem(Trigger);

	// The shooter must have the VanishingWind Effect
	UnitEffectsCondition = new class'X2Condition_UnitEffects';
	UnitEffectsCondition.AddRequireEffect(class'X2Effect_VanishingWind'.default.EffectName, 'AA_MissingRequiredEffect');
	Template.AbilityShooterConditions.AddItem(UnitEffectsCondition);

	RemoveEffects = new class'X2Effect_RemoveEffects';
	RemoveEffects.EffectNamesToRemove.AddItem(class'X2Effect_VanishingWind'.default.EffectName);
	Template.AddShooterEffect(RemoveEffects);

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	Template.BuildVisualizationFn = TypicalAbility_BuildVisualization;
	Template.MergeVisualizationFn = VanishingWindReveal_MergeVisualization;

	Template.bSkipFireAction = true;
	Template.bShowPostActivation = true;

	Template.CinescriptCameraType = "ChosenAssassin_VanishingWindReveal";
//BEGIN AUTOGENERATED CODE: Template Overrides 'VanishingWindReveal'
	Template.bFrameEvenWhenUnitIsHidden = true;
//END AUTOGENERATED CODE: Template Overrides 'VanishingWindReveal'

	Template.AssociatedPlayTiming = SPT_AfterSequential;

	return Template;
}

function VanishingWindReveal_MergeVisualization(X2Action BuildTree, out X2Action VisualizationTree)
{
	local XComGameStateVisualizationMgr VisMgr;
	local X2Action_MarkerTreeInsertBegin MarkerStart;
	local X2Action_RevealArea RevealAction;
	local X2Action_CameraLookAt CameraAction;
	local XComGameStateContext_Ability Context;
	local Array<X2Action> FoundActions;
	local XComGameState_Unit GameStateUnit;
	local XComWorldData WorldData;
	local XComGameStateHistory History;
	local int i;
	local vector NewTargetLoc;

	VisMgr = `XCOMVISUALIZATIONMGR;
	History = `XCOMHISTORY;

	MarkerStart = X2Action_MarkerTreeInsertBegin(VisMgr.GetNodeOfType(BuildTree, class'X2Action_MarkerTreeInsertBegin'));
	Context = XComGameStateContext_Ability(MarkerStart.StateChangeContext);

	GameStateUnit = XComGameState_Unit(History.GetGameStateForObjectID(Context.InputContext.PrimaryTarget.ObjectID, , Context.AssociatedState.HistoryIndex));

	if( GameStateUnit != none )
	{
		WorldData = `XWORLD;
		NewTargetLoc = WorldData.GetPositionFromTileCoordinates(GameStateUnit.TileLocation);

		VisMgr.GetNodesOfType(BuildTree, class'X2Action_RevealArea', FoundActions, , Context.InputContext.PrimaryTarget.ObjectID);
		for( i = 0; i < FoundActions.Length; ++i )
		{
			RevealAction = X2Action_RevealArea(FoundActions[i]);
			if( (RevealAction != none) &&
				!RevealAction.bDestroyViewer )
			{
				RevealAction.bUseCurrentVisualizerLoc = false;
				RevealAction.TargetLocation = NewTargetLoc;
			}
		}

		FoundActions.Length = 0;
		VisMgr.GetNodesOfType(BuildTree, class'X2Action_CameraLookAt', FoundActions, , Context.InputContext.PrimaryTarget.ObjectID);

		for( i = 0; i < FoundActions.Length; ++i )
		{
			CameraAction = X2Action_CameraLookAt(FoundActions[i]);
			if( CameraAction != none )
			{
				CameraAction.LookAtActor = none;
				CameraAction.LookAtLocation = NewTargetLoc;
			}
		}
	}

	Context.SuperMergeIntoVisualizationTree(BuildTree, VisualizationTree);
}

static function X2AbilityTemplate CreateBendingReed(name TemplateName = 'BendingReed')
{
	local X2AbilityTemplate Template;
	local X2Effect_GrantActionPoints ActionPointEffect;
	local X2AbilityTrigger_EventListener EventListener;
	local X2Effect_PersistentStatChange MobilityIncrease;

	`CREATE_X2ABILITY_TEMPLATE(Template, TemplateName);
	Template.IconImage = "img:///UILibrary_XPACK_Common.PerkIcons.UIPerk_bendingreed";
	Template.Hostility = eHostility_Neutral;
	Template.AbilitySourceName = 'eAbilitySource_Standard';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_NeverShow;

	Template.AdditionalAbilities.AddItem('BendingReedPassive');

	Template.AbilityToHitCalc = default.DeadEye;
	Template.AbilityTargetStyle = default.SelfTarget;

	EventListener = new class'X2AbilityTrigger_EventListener';
	EventListener.ListenerData.Deferral = ELD_OnStateSubmitted;
	EventListener.ListenerData.EventFn = class'XComGameState_Ability'.static.AbilityTriggerEventListener_Self;
	EventListener.ListenerData.EventID = 'PartingSilkActivated';
	EventListener.ListenerData.Filter = eFilter_Unit;
	Template.AbilityTriggers.AddItem(EventListener);

	Template.AbilityShooterConditions.AddItem(default.LivingShooterProperty);

	ActionPointEffect = new class'X2Effect_GrantActionPoints';
	ActionPointEffect.NumActionPoints = 1;
	ActionPointEffect.PointType = class'X2CharacterTemplateManager'.default.MoveActionPoint;
	Template.AddShooterEffect(ActionPointEffect);

	MobilityIncrease = new class'X2Effect_PersistentStatChange';
	MobilityIncrease.BuildPersistentEffect(1, false, true);
	MobilityIncrease.AddPersistentStatChange(eStat_Mobility, default.BENDINGREED_MOBILITY_INCREASE, MODOP_Multiplication);
	Template.AddShooterEffect(MobilityIncrease);

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	Template.BuildVisualizationFn = TypicalAbility_BuildVisualization;

	Template.bSkipFireAction = true;
	Template.bShowActivation = true;
	Template.bFrameEvenWhenUnitIsHidden = true;

	return Template;
}

static function X2DataTemplate CreateHarborWave()
{
	local X2AbilityTemplate Template;
	local X2AbilityCost_ActionPoints ActionPointCost;
	local X2AbilityCooldown_LocalAndGlobal Cooldown;
	local X2AbilityTarget_Cursor CursorTarget;
	local X2AbilityMultiTarget_Cone ConeMultiTarget;
	local X2Effect_Dazed DazedEffect;
	local X2Effect_ApplyWeaponDamage PhysicalDamageEffect;
	local X2Condition_UnitType UnitTypeCondition;
	local X2Effect_Knockback KnockbackEffect;
	local X2AbilityToHitCalc_PercentChance ApplyChance;
	local array<name> SkipExclusions;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'HarborWave');
	Template.IconImage = "img:///UILibrary_XPACK_Common.PerkIcons.UIPerk_harborwave";

	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_AlwaysShow;
	Template.AbilitySourceName = 'eAbilitySource_Standard';
	Template.Hostility = eHostility_Offensive;

	// This ability is a free action
	ActionPointCost = new class'X2AbilityCost_ActionPoints';
	ActionPointCost.iNumPoints = default.HARBORWAVE_ACTIONPOINTCOST;
	Template.AbilityCosts.AddItem(ActionPointCost);

	Cooldown = new class'X2AbilityCooldown_LocalAndGlobal';
	Cooldown.iNumTurns = default.HARBORWAVE_COOLDOWN_LOCAL;
	Cooldown.NumGlobalTurns = default.HARBORWAVE_COOLDOWN_GLOBAL;
	Template.AbilityCooldown = Cooldown;

	//Can't use while dead
	Template.AbilityShooterConditions.AddItem(default.LivingShooterProperty);

	Template.AbilityShooterConditions.AddItem(default.LivingShooterProperty);

	SkipExclusions.AddItem(class'X2StatusEffects'.default.BurningName);
	SkipExclusions.AddItem(class'X2AbilityTemplateManager'.default.DisorientedName);
	Template.AddShooterEffectExclusions(SkipExclusions);

	ApplyChance = new class'X2AbilityToHitCalc_PercentChance';
	ApplyChance.PercentToHit = default.HARBORWAVE_APPLY_CHANCE;
	Template.AbilityToHitCalc = ApplyChance;
	Template.AbilityTriggers.AddItem(default.PlayerInputTrigger);

	Template.TargetingMethod = class'X2TargetingMethod_Cone';

	CursorTarget = new class'X2AbilityTarget_Cursor';
	CursorTarget.bRestrictToWeaponRange = false;
	CursorTarget.FixedAbilityRange = default.HARBORWAVE_LENGTH_TILES * class'XComWorldData'.const.WORLD_StepSize;
	Template.AbilityTargetStyle = CursorTarget;

	ConeMultiTarget = new class'X2AbilityMultiTarget_Cone';
	ConeMultiTarget.ConeEndDiameter = default.HARBORWAVE_END_DIAMETER_TILES * class'XComWorldData'.const.WORLD_StepSize;
	ConeMultiTarget.ConeLength = default.HARBORWAVE_LENGTH_TILES * class'XComWorldData'.const.WORLD_StepSize;
	ConeMultiTarget.fTargetRadius = Sqrt(Square(ConeMultiTarget.ConeEndDiameter / 2) + Square(ConeMultiTarget.ConeLength)) * class'XComWorldData'.const.WORLD_UNITS_TO_METERS_MULTIPLIER;
	ConeMultiTarget.bExcludeSelfAsTargetIfWithinRadius = true;
	ConeMultiTarget.bLockShooterZ = true;
	Template.AbilityMultiTargetStyle = ConeMultiTarget;

	Template.AbilityMultiTargetConditions.AddItem(default.LivingHostileUnitOnlyProperty);

	// Damage from Harbor Wave
	PhysicalDamageEffect = new class'X2Effect_ApplyWeaponDamage';
	PhysicalDamageEffect.EffectDamageValue = default.HARBORWAVE_BASEDAMAGE;
	PhysicalDamageEffect.EffectDamageValue.DamageType = 'HarborWave';
	PhysicalDamageEffect.bApplyOnMiss = true;
	PhysicalDamageEffect.OverrideMissMessage = default.HarborWave_Stun_Resisted;

	// Only The Lost get damaged (for now)
	UnitTypeCondition = new class'X2Condition_UnitType';
	UnitTypeCondition.IncludeTypes.AddItem('TheLost');
	PhysicalDamageEffect.TargetConditions.AddItem(UnitTypeCondition);

	Template.AddMultiTargetEffect(PhysicalDamageEffect);

	// Knockback and Stun
	// Lost don't get knockback or dazed
	UnitTypeCondition = new class'X2Condition_UnitType';
	UnitTypeCondition.ExcludeTypes.AddItem('TheLost');

	KnockbackEffect = new class'X2Effect_Knockback';
	KnockbackEffect.KnockbackDistance = default.HARBORWAVE_KNOCKBACK_DISTANCE;
	KnockbackEffect.OnlyOnDeath = false;
	KnockbackEffect.TargetConditions.AddItem(UnitTypeCondition);
	Template.AddMultiTargetEffect(KnockbackEffect);

	// Dazed effect if the unit is knocked back
	DazedEffect = class'X2StatusEffects_XPack'.static.CreateDazedStatusEffect(default.HARBORWAVE_DAZE_TURNS, 100);
	DazedEffect.bRemoveWhenSourceDies = true;
	DazedEffect.TargetConditions.AddItem(UnitTypeCondition);
	DazedEffect.VisualizationFn = HarborWave_DazedVisualization;
	Template.AddMultiTargetEffect(DazedEffect);

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	Template.BuildVisualizationFn = TypicalAbility_BuildVisualization;

	Template.CustomFireAnim = 'HL_HarborWave';
	Template.bShowActivation = true;
	Template.ActionFireClass = class'X2Action_Fire_Wave';

	Template.CinescriptCameraType = "ChosenAssassin_HarborWave";
//BEGIN AUTOGENERATED CODE: Template Overrides 'HarborWave'
	Template.bFrameEvenWhenUnitIsHidden = true;
//END AUTOGENERATED CODE: Template Overrides 'HarborWave'

	return Template;
}

static function HarborWave_DazedVisualization(XComGameState VisualizeGameState, out VisualizationActionMetadata ActionMetadata, const name EffectApplyResult)
{
	if( EffectApplyResult == 'AA_Success' )
	{
		class'X2StatusEffects_XPack'.static.DazedVisualization(VisualizeGameState, ActionMetadata, EffectApplyResult);
	}
}

static function X2AbilityTemplate CreateLostAndAbandonedChosenHealthThreshold()
{
	local X2AbilityTemplate Template;
	local X2AbilityTrigger_EventListener Trigger;
	local X2Condition_UnitValue UnitValue;
	local X2Effect_TriggerEvent TriggerEventEffect;
	local X2Effect_SetUnitValue SetUnitValue;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'LostAndAbandonedChosenHealthThreshold');

	Template.IconImage = "img:///UILibrary_PerkIcons.UIPerk_none";
	Template.bDontDisplayInAbilitySummary = true;
	Template.AbilitySourceName = 'eAbilitySource_Standard';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_NeverShow;
	Template.Hostility = eHostility_Neutral;
	Template.bIsPassive = true;

	Template.AdditionalAbilities.AddItem('LostAndAbandonedChosenInit');

	Template.AbilityToHitCalc = default.DeadEye;
	Template.AbilityTargetStyle = default.SelfTarget;

	// This ability fires can when the unit gets hit by a scan
	Trigger = new class'X2AbilityTrigger_EventListener';
	Trigger.ListenerData.Deferral = ELD_OnStateSubmitted;
	Trigger.ListenerData.EventID = 'UnitTakeEffectDamage';
	Trigger.ListenerData.EventFn = class'XComGameState_Ability'.static.LostAndAbandonedChosenHealthThresholdListener;
	Trigger.ListenerData.Filter = eFilter_Unit;
	Template.AbilityTriggers.AddItem(Trigger);

	// Do not trigger this ability if it has already triggered once
	UnitValue = new class'X2Condition_UnitValue';
	UnitValue.AddCheckValue('LostAndAbandonedAbilityTriggered', 1, eCheck_LessThan);

	TriggerEventEffect = new class'X2Effect_TriggerEvent';
	TriggerEventEffect.TriggerEventName = default.LostAndAbandonedHealthThresholdEventName;
	Template.AddTargetEffect(TriggerEventEffect);

	SetUnitValue = new class'X2Effect_SetUnitValue';
	SetUnitValue.UnitName = 'LostAndAbandonedAbilityTriggered';
	SetUnitValue.NewValueToSet = 2;
	SetUnitValue.CleanupType = eCleanup_BeginTactical;
	Template.AddTargetEffect(SetUnitValue);

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	// Note: no visualization on purpose!

	return Template;
}

static function X2AbilityTemplate CreateLostAndAbandonedChosenInit()
{
	local X2AbilityTemplate Template;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'LostAndAbandonedChosenInit');

	Template.IconImage = "img:///UILibrary_PerkIcons.UIPerk_none";
	Template.bDontDisplayInAbilitySummary = true;
	Template.AbilitySourceName = 'eAbilitySource_Standard';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_NeverShow;
	Template.Hostility = eHostility_Neutral;
	Template.bIsPassive = true;

	Template.AbilityToHitCalc = default.DeadEye;
	Template.AbilityTargetStyle = default.SelfTarget;
	Template.AbilityTriggers.AddItem(default.UnitPostBeginPlayTrigger);

	Template.AddShooterEffect(new class'X2Effect_Unkillable');

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	// Note: no visualization on purpose!

	return Template;
}

defaultproperties
{
	LostAndAbandonedHealthThresholdEventName="LostAndAbandonedHealthThresholdEvent"
}