Create X2Ability_GrenadierAbilitySet.uc (#46)

Fixes suppression visualization so guns with no dedicated suppression animation will play default fire animation instead. (MM note, will rework to match check source weapon before releasing)

//---------------------------------------------------------------------------------------
//  FILE:    X2Ability_GrenadierAbilitySet.uc
//  AUTHOR:  Joshua Bouscher
//  DATE:    18 Jul 2014
//  PURPOSE: Defines abilities used by the Grenadier class.
//
//---------------------------------------------------------------------------------------
//  Copyright (c) 2016 Firaxis Games, Inc. All rights reserved.
//---------------------------------------------------------------------------------------

class X2Ability_GrenadierAbilitySet extends X2Ability
	config(GameData_SoldierSkills);

var localized string SuppressionTargetEffectDesc;
var localized string SuppressionSourceEffectDesc;

var localized string HoloTargetEffectName;
var localized string HoloTargetEffectDesc;

var config int BULLET_SHRED;
var config int VOLATILE_DAMAGE;
var deprecated config float VOLATILE_RADIUS;
var config int DEMO_HIT_BONUS;

var config int SATURATION_TILE_WIDTH, SATURATION_DESTRUCTION_CHANCE;

var config float BLAST_PADDING_DMG_ADJUST;
var config int CHAINSHOT_HIT_MOD;
var config int ORDNANCE_BONUS;
var config name FreeGrenadeForPocket;
var config int HAILOFBULLETS_COOLDOWN;
var config int BULLETSHRED_COOLDOWN;
var config int SATURATION_FIRE_COOLDOWN;
var config int CHAINSHOT_COOLDOWN;
var config int DEMOLITION_COOLDOWN;
var config int HOLOTARGET_BONUS;

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

	Templates.AddItem(HeavyOrdnance());
	Templates.AddItem(BiggestBooms());
	Templates.AddItem(Suppression());
	Templates.AddItem(SuppressionShot());
	Templates.AddItem(HoloTargeting());
	Templates.AddItem(BlastPadding());
	Templates.AddItem(BulletShred());
	Templates.AddItem(PurePassive('Salvo', "img:///UILibrary_PerkIcons.UIPerk_salvo", true));
	Templates.AddItem(VolatileMix());
	Templates.AddItem(HailOfBullets());
	Templates.AddItem(SaturationFire());
	Templates.AddItem(PurePassive('Shredder', "img:///UILibrary_PerkIcons.UIPerk_shredder", true));
	Templates.AddItem(ChainShot());
	Templates.AddItem(ChainShot2());
	Templates.AddItem(Demolition());

	return Templates;
}

static function X2AbilityTemplate HailOfBullets()
{
	local X2AbilityTemplate					Template;
	local X2AbilityCost_Ammo				AmmoCost;
	local X2AbilityToHitCalc_StandardAim    ToHitCalc;
	local X2AbilityCooldown                 Cooldown;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'HailOfBullets');

	Template.AbilityCosts.AddItem(default.WeaponActionTurnEnding);

	AmmoCost = new class'X2AbilityCost_Ammo';
	AmmoCost.iAmmo = 3;
	Template.AbilityCosts.AddItem(AmmoCost);

	Cooldown = new class'X2AbilityCooldown';
	Cooldown.iNumTurns = default.HAILOFBULLETS_COOLDOWN;
	Template.AbilityCooldown = Cooldown;

	ToHitCalc = new class'X2AbilityToHitCalc_StandardAim';
	ToHitCalc.bGuaranteedHit = true;
	ToHitCalc.bAllowCrit = false;
	Template.AbilityToHitCalc = ToHitCalc;
	Template.AbilityToHitOwnerOnMissCalc = ToHitCalc;

	Template.AbilityTargetStyle = default.SimpleSingleTarget;

	Template.AbilityShooterConditions.AddItem(default.LivingShooterProperty);
	Template.AddShooterEffectExclusions();

	Template.AbilityTargetConditions.AddItem(default.LivingHostileTargetProperty);
	Template.AbilityTargetConditions.AddItem(default.GameplayVisibilityCondition);

	Template.AddTargetEffect(HoloTargetEffect());
	Template.AssociatedPassives.AddItem( 'HoloTargeting' );
	Template.AddTargetEffect(ShredderDamageEffect());
	Template.bAllowAmmoEffects = true;
	Template.bAllowBonusWeaponEffects = true;

	Template.AbilityTriggers.AddItem(default.PlayerInputTrigger);

	Template.ShotHUDPriority = class'UIUtilities_Tactical'.const.CLASS_MAJOR_PRIORITY;
	Template.AbilitySourceName = 'eAbilitySource_Perk';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_AlwaysShow;
	Template.IconImage = "img:///UILibrary_PerkIcons.UIPerk_hailofbullets";
	Template.AbilityConfirmSound = "TacticalUI_ActivateAbility";

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

	Template.bCrossClassEligible = true;
	Template.CinescriptCameraType = "StandardGunFiring";

	Template.SuperConcealmentLoss = class'X2AbilityTemplateManager'.default.SuperConcealmentStandardShotLoss;
	Template.ChosenActivationIncreasePerUse = class'X2AbilityTemplateManager'.default.StandardShotChosenActivationIncreasePerUse;
	Template.LostSpawnIncreasePerUse = class'X2AbilityTemplateManager'.default.StandardShotLostSpawnIncreasePerUse;
//BEGIN AUTOGENERATED CODE: Template Overrides 'HailOfBullets'
	Template.bFrameEvenWhenUnitIsHidden = true;
//END AUTOGENERATED CODE: Template Overrides 'HailOfBullets'

	return Template;
}

static function X2AbilityTemplate HeavyOrdnance()
{
	local X2AbilityTemplate         Template;

	Template = PurePassive('HeavyOrdnance', "img:///UILibrary_PerkIcons.UIPerk_aceinthehole");

	Template.bCrossClassEligible = false;
	Template.GetBonusWeaponAmmoFn = HeavyOrdnance_BonusWeaponAmmo;

	return Template;
}

function int HeavyOrdnance_BonusWeaponAmmo(XComGameState_Unit UnitState, XComGameState_Item ItemState)
{
	if (ItemState.InventorySlot == eInvSlot_GrenadePocket)
		return default.ORDNANCE_BONUS;

	return 0;
}

function GrenadePocketPurchased(XComGameState NewGameState, XComGameState_Unit UnitState)
{
	local X2ItemTemplate FreeItem;
	local XComGameState_Item ItemState;

	if (UnitState.IsMPCharacter())
		return;

	if (!UnitState.HasGrenadePocket())
	{
		`RedScreen("GrenadePocketPurchased called but the unit doesn't have one? -jbouscher / @gameplay" @ UnitState.ToString());
		return;
	}

	FreeItem = class'X2ItemTemplateManager'.static.GetItemTemplateManager().FindItemTemplate(default.FreeGrenadeForPocket);
	if (FreeItem == none)
	{
		`RedScreen("Free grenade '" $ default.FreeGrenadeForPocket $ "' is not a valid item template.");
		return;
	}
	ItemState = FreeItem.CreateInstanceFromTemplate(NewGameState);
	if (!UnitState.AddItemToInventory(ItemState, eInvSlot_GrenadePocket, NewGameState))
	{
		`RedScreen("Unable to add free grenade to unit's inventory. Sadness." @ UnitState.ToString());
		return;
	}
}

static function X2AbilityTemplate BlastPadding()
{
	local X2AbilityTemplate						Template;
	local X2AbilityTargetStyle                  TargetStyle;
	local X2AbilityTrigger						Trigger;
	local X2Effect_BlastPadding                 PaddingEffect;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'BlastPadding');

	Template.AbilitySourceName = 'eAbilitySource_Perk';
	Template.eAbilityIconBehaviorHUD = EAbilityIconBehavior_NeverShow;
	Template.Hostility = eHostility_Neutral;
	Template.IconImage = "img:///UILibrary_PerkIcons.UIPerk_extrapadding";

	Template.AbilityToHitCalc = default.DeadEye;

	TargetStyle = new class'X2AbilityTarget_Self';
	Template.AbilityTargetStyle = TargetStyle;

	Trigger = new class'X2AbilityTrigger_UnitPostBeginPlay';
	Template.AbilityTriggers.AddItem(Trigger);

	PaddingEffect = new class'X2Effect_BlastPadding';
	PaddingEffect.ExplosiveDamageReduction = default.BLAST_PADDING_DMG_ADJUST;
	PaddingEffect.BuildPersistentEffect(1, true, false);
	PaddingEffect.SetDisplayInfo(ePerkBuff_Passive, Template.LocFriendlyName, Template.GetMyHelpText(), Template.IconImage,,,Template.AbilitySourceName);
	Template.AddTargetEffect(PaddingEffect);

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	//  NOTE: No visualization on purpose!

	Template.bCrossClassEligible = true;

	Template.SetUIStatMarkup(class'XLocalizedData'.default.ArmorLabel, eStat_ArmorMitigation, PaddingEffect.ARMOR_MITIGATION);

	return Template;
}

static function X2AbilityTemplate BiggestBooms()
{
	local X2AbilityTemplate						Template;
	local X2AbilityTargetStyle                  TargetStyle;
	local X2AbilityTrigger						Trigger;
	local X2Effect_BiggestBooms                 BiggestBoomsEffect;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'BiggestBooms');

	// Icon Properties
	Template.IconImage = "img:///UILibrary_PerkIcons.UIPerk_biggestbooms";

	Template.AbilitySourceName = 'eAbilitySource_Perk';
	Template.eAbilityIconBehaviorHUD = EAbilityIconBehavior_NeverShow;
	Template.Hostility = eHostility_Neutral;

	Template.AbilityToHitCalc = default.DeadEye;

	TargetStyle = new class'X2AbilityTarget_Self';
	Template.AbilityTargetStyle = TargetStyle;

	Trigger = new class'X2AbilityTrigger_UnitPostBeginPlay';
	Template.AbilityTriggers.AddItem(Trigger);

	BiggestBoomsEffect = new class'X2Effect_BiggestBooms';
	BiggestBoomsEffect.BuildPersistentEffect(1, true, true, true);
	BiggestBoomsEffect.SetDisplayInfo(ePerkBuff_Passive, Template.LocFriendlyName, Template.GetMyLongDescription(), Template.IconImage,,,Template.AbilitySourceName);
	Template.AddTargetEffect(BiggestBoomsEffect);

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	//  NOTE: No visualization on purpose!

	return Template;
}

static function X2AbilityTemplate Suppression()
{
	local X2AbilityTemplate                 Template;
	local X2AbilityCost_Ammo                AmmoCost;
	local X2AbilityCost_ActionPoints        ActionPointCost;
	local X2Effect_ReserveActionPoints      ReserveActionPointsEffect;
	local X2Effect_Suppression              SuppressionEffect;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'Suppression');

	Template.IconImage = "img:///UILibrary_PerkIcons.UIPerk_supression";

	AmmoCost = new class'X2AbilityCost_Ammo';
	AmmoCost.iAmmo = 2;
	Template.AbilityCosts.AddItem(AmmoCost);

	ActionPointCost = new class'X2AbilityCost_ActionPoints';
	ActionPointCost.bConsumeAllPoints = true;   //  this will guarantee the unit has at least 1 action point
	ActionPointCost.bFreeCost = true;           //  ReserveActionPoints effect will take all action points away
	Template.AbilityCosts.AddItem(ActionPointCost);

	Template.AbilityShooterConditions.AddItem(default.LivingShooterProperty);

	Template.AddShooterEffectExclusions();

	ReserveActionPointsEffect = new class'X2Effect_ReserveActionPoints';
	ReserveActionPointsEffect.ReserveType = 'Suppression';
	Template.AddShooterEffect(ReserveActionPointsEffect);

	Template.AbilityToHitCalc = default.DeadEye;
	Template.AbilityTargetConditions.AddItem(default.LivingHostileUnitDisallowMindControlProperty);
	Template.AbilityTargetConditions.AddItem(default.GameplayVisibilityCondition);
	Template.AbilityTargetStyle = default.SimpleSingleTarget;
	Template.AbilityTriggers.AddItem(default.PlayerInputTrigger);

	SuppressionEffect = new class'X2Effect_Suppression';
	SuppressionEffect.BuildPersistentEffect(1, false, true, false, eGameRule_PlayerTurnBegin);
	SuppressionEffect.bRemoveWhenTargetDies = true;
	SuppressionEffect.bRemoveWhenSourceDamaged = true;
	SuppressionEffect.bBringRemoveVisualizationForward = true;
	SuppressionEffect.SetDisplayInfo(ePerkBuff_Penalty, Template.LocFriendlyName, default.SuppressionTargetEffectDesc, Template.IconImage);
	SuppressionEffect.SetSourceDisplayInfo(ePerkBuff_Bonus, Template.LocFriendlyName, default.SuppressionSourceEffectDesc, Template.IconImage);
	Template.AddTargetEffect(SuppressionEffect);
	Template.AddTargetEffect(HoloTargetEffect());

	Template.AbilitySourceName = 'eAbilitySource_Perk';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_AlwaysShow;
	Template.ShotHUDPriority = class'UIUtilities_Tactical'.const.CLASS_LIEUTENANT_PRIORITY;
	Template.bDisplayInUITooltip = false;
	Template.AdditionalAbilities.AddItem('SuppressionShot');
	Template.bIsASuppressionEffect = true;
	Template.AbilityConfirmSound = "TacticalUI_ActivateAbility";
	Template.TargetingMethod = class'X2TargetingMethod_OverTheShoulder';

	Template.AssociatedPassives.AddItem('HoloTargeting');

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	Template.BuildVisualizationFn = SuppressionBuildVisualization;
	Template.BuildAppliedVisualizationSyncFn = SuppressionBuildVisualizationSync;
	Template.CinescriptCameraType = "StandardSuppression";

	Template.Hostility = eHostility_Offensive;

	Template.SuperConcealmentLoss = class'X2AbilityTemplateManager'.default.SuperConcealmentStandardShotLoss;
	Template.ChosenActivationIncreasePerUse = class'X2AbilityTemplateManager'.default.StandardShotChosenActivationIncreasePerUse;
	Template.LostSpawnIncreasePerUse = class'X2AbilityTemplateManager'.default.StandardShotLostSpawnIncreasePerUse;
//BEGIN AUTOGENERATED CODE: Template Overrides 'Suppression'
	Template.bFrameEvenWhenUnitIsHidden = true;
//END AUTOGENERATED CODE: Template Overrides 'Suppression'

	return Template;
}

simulated function SuppressionBuildVisualization(XComGameState VisualizeGameState)
{
	local XComGameStateHistory History;
	local XComGameStateContext_Ability  Context;
	local StateObjectReference          InteractingUnitRef;

	local VisualizationActionMetadata        EmptyTrack;
	local VisualizationActionMetadata        ActionMetadata;

	local XComGameState_Ability         Ability;
	local X2Action_PlaySoundAndFlyOver SoundAndFlyOver;

  //new variables for issue #45
  local XComUnitPawn					UnitPawn;
	local XComWeapon					Weapon;

	History = `XCOMHISTORY;

	Context = XComGameStateContext_Ability(VisualizeGameState.GetContext());
	InteractingUnitRef = Context.InputContext.SourceObject;

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

  // Check the actor's pawn and weapon, see if they can play the suppression effect
	UnitPawn = XGUnit(ActionMetadata.VisualizeActor).GetPawn();
	Weapon = XComWeapon(UnitPawn.Weapon);
	if (Weapon != None &&
		!UnitPawn.GetAnimTreeController().CanPlayAnimation(Weapon.WeaponSuppressionFireAnimSequenceName) &&
		!UnitPawn.GetAnimTreeController().CanPlayAnimation(class'XComWeapon'.default.WeaponSuppressionFireAnimSequenceName))
	{
		// The unit can't play their weapon's suppression effect. Replace it with the normal fire effect so at least they'll look like they're shooting
		Weapon.WeaponSuppressionFireAnimSequenceName = Weapon.WeaponFireAnimSequenceName;
	}

  // End issue #45

	class'X2Action_ExitCover'.static.AddToVisualizationTree(ActionMetadata, Context, false, ActionMetadata.LastActionAdded);
	class'X2Action_StartSuppression'.static.AddToVisualizationTree(ActionMetadata, Context, false, ActionMetadata.LastActionAdded);
		//****************************************************************************************
	//Configure the visualization track for the target
	InteractingUnitRef = Context.InputContext.PrimaryTarget;
	Ability = XComGameState_Ability(History.GetGameStateForObjectID(Context.InputContext.AbilityRef.ObjectID, eReturnType_Reference, VisualizeGameState.HistoryIndex - 1));
	ActionMetadata = EmptyTrack;
	ActionMetadata.StateObject_OldState = History.GetGameStateForObjectID(InteractingUnitRef.ObjectID, eReturnType_Reference, VisualizeGameState.HistoryIndex - 1);
	ActionMetadata.StateObject_NewState = VisualizeGameState.GetGameStateForObjectID(InteractingUnitRef.ObjectID);
	ActionMetadata.VisualizeActor = History.GetVisualizer(InteractingUnitRef.ObjectID);
	SoundAndFlyOver = X2Action_PlaySoundAndFlyOver(class'X2Action_PlaySoundAndFlyOver'.static.AddToVisualizationTree(ActionMetadata, Context, false, ActionMetadata.LastActionAdded));
	SoundAndFlyOver.SetSoundAndFlyOverParameters(None, Ability.GetMyTemplate().LocFlyOverText, '', eColor_Good);
	if (XComGameState_Unit(ActionMetadata.StateObject_OldState).ReserveActionPoints.Length != 0 && XComGameState_Unit(ActionMetadata.StateObject_NewState).ReserveActionPoints.Length == 0)
	{
		SoundAndFlyOver = X2Action_PlaySoundAndFlyOver(class'X2Action_PlaySoundAndFlyOver'.static.AddToVisualizationTree(ActionMetadata, Context, false, ActionMetadata.LastActionAdded));
		SoundAndFlyOver.SetSoundAndFlyOverParameters(none, class'XLocalizedData'.default.OverwatchRemovedMsg, '', eColor_Good);
	}
	}

simulated function SuppressionBuildVisualizationSync(name EffectName, XComGameState VisualizeGameState, out VisualizationActionMetadata ActionMetadata)
{
	local X2Action_ExitCover ExitCover;

	if (EffectName == class'X2Effect_Suppression'.default.EffectName)
	{
		ExitCover = X2Action_ExitCover(class'X2Action_ExitCover'.static.AddToVisualizationTree( ActionMetadata, VisualizeGameState.GetContext() ));
		ExitCover.bIsForSuppression = true;

		class'X2Action_StartSuppression'.static.AddToVisualizationTree( ActionMetadata, VisualizeGameState.GetContext() );
	}
}

static function X2AbilityTemplate SuppressionShot()
{
	local X2AbilityTemplate                 Template;
	local X2AbilityCost_ReserveActionPoints ReserveActionPointCost;
	local X2AbilityToHitCalc_StandardAim    StandardAim;
	local X2Condition_Visibility            TargetVisibilityCondition;
	local X2AbilityTrigger_EventListener	Trigger;
	local array<name>                       SkipExclusions;
	local X2Condition_UnitEffectsWithAbilitySource TargetEffectCondition;
	local X2Effect_RemoveEffects            RemoveSuppression;
	local X2Effect                          ShotEffect;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'SuppressionShot');

	Template.bDontDisplayInAbilitySummary = true;
	ReserveActionPointCost = new class'X2AbilityCost_ReserveActionPoints';
	ReserveActionPointCost.iNumPoints = 1;
	ReserveActionPointCost.AllowedTypes.AddItem('Suppression');
	Template.AbilityCosts.AddItem(ReserveActionPointCost);

	StandardAim = new class'X2AbilityToHitCalc_StandardAim';
	StandardAim.bReactionFire = true;
	Template.AbilityToHitCalc = StandardAim;
	Template.AbilityToHitOwnerOnMissCalc = StandardAim;

	Template.AbilityTargetConditions.AddItem(default.LivingHostileTargetProperty);

	TargetEffectCondition = new class'X2Condition_UnitEffectsWithAbilitySource';
	TargetEffectCondition.AddRequireEffect(class'X2Effect_Suppression'.default.EffectName, 'AA_UnitIsNotSuppressed');
	Template.AbilityTargetConditions.AddItem(TargetEffectCondition);

	TargetVisibilityCondition = new class'X2Condition_Visibility';
	TargetVisibilityCondition.bRequireGameplayVisible = true;
	Template.AbilityTargetConditions.AddItem(TargetVisibilityCondition);

	Template.AbilityShooterConditions.AddItem(default.LivingShooterProperty);

	SkipExclusions.AddItem(class'X2AbilityTemplateManager'.default.DisorientedName);
	Template.AddShooterEffectExclusions(SkipExclusions);
	Template.bAllowAmmoEffects = true;

	RemoveSuppression = new class'X2Effect_RemoveEffects';
	RemoveSuppression.EffectNamesToRemove.AddItem(class'X2Effect_Suppression'.default.EffectName);
	RemoveSuppression.bCheckSource = true;
	RemoveSuppression.SetupEffectOnShotContextResult(true, true);
	Template.AddShooterEffect(RemoveSuppression);

	Template.AbilityTargetStyle = default.SimpleSingleTarget;

	//Trigger on movement - interrupt the move
	Trigger = new class'X2AbilityTrigger_EventListener';
	Trigger.ListenerData.EventID = 'ObjectMoved';
	Trigger.ListenerData.Deferral = ELD_OnStateSubmitted;
	Trigger.ListenerData.Filter = eFilter_None;
	Trigger.ListenerData.EventFn = class'XComGameState_Ability'.static.TypicalOverwatchListener;
	Template.AbilityTriggers.AddItem(Trigger);

	Template.AbilitySourceName = 'eAbilitySource_Standard';
	Template.eAbilityIconBehaviorHUD = EAbilityIconBehavior_NeverShow;
	Template.IconImage = "img:///UILibrary_PerkIcons.UIPerk_supression";
	Template.ShotHUDPriority = class'UIUtilities_Tactical'.const.CLASS_LIEUTENANT_PRIORITY;
	Template.bDisplayInUITooltip = false;
	Template.bDisplayInUITacticalText = false;

	//don't want to exit cover, we are already in suppression/alert mode.
	Template.bSkipExitCoverWhenFiring = true;

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

	//  Put holo target effect first because if the target dies from this shot, it will be too late to notify the effect.
	ShotEffect = class'X2Ability_GrenadierAbilitySet'.static.HoloTargetEffect();
	ShotEffect.TargetConditions.AddItem(class'X2Ability_DefaultAbilitySet'.static.OverwatchTargetEffectsCondition());
	Template.AddTargetEffect(ShotEffect);
	//  Various Soldier ability specific effects - effects check for the ability before applying
	ShotEffect = class'X2Ability_GrenadierAbilitySet'.static.ShredderDamageEffect();
	ShotEffect.TargetConditions.AddItem(class'X2Ability_DefaultAbilitySet'.static.OverwatchTargetEffectsCondition());
	Template.AddTargetEffect(ShotEffect);

	Template.SuperConcealmentLoss = class'X2AbilityTemplateManager'.default.SuperConcealmentStandardShotLoss;
	Template.LostSpawnIncreasePerUse = class'X2AbilityTemplateManager'.default.StandardShotLostSpawnIncreasePerUse;
//BEGIN AUTOGENERATED CODE: Template Overrides 'SuppressionShot'
	Template.bFrameEvenWhenUnitIsHidden = true;
//END AUTOGENERATED CODE: Template Overrides 'SuppressionShot'

	return Template;
}

static function X2AbilityTemplate HoloTargeting()
{
	local X2AbilityTemplate             Template;
	local X2Effect_Persistent           PersistentEffect;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'HoloTargeting');

	Template.IconImage = "img:///UILibrary_PerkIcons.UIPerk_holotargeting";
	Template.AbilitySourceName = 'eAbilitySource_Perk';
	Template.eAbilityIconBehaviorHUD = EAbilityIconBehavior_NeverShow;
	Template.Hostility = eHostility_Neutral;
	Template.bIsPassive = true;

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

	//  This is a dummy effect so that an icon shows up in the UI.
	//  Shot and Suppression abilities make use of HoloTargetEffect().
	PersistentEffect = new class'X2Effect_Persistent';
	PersistentEffect.BuildPersistentEffect(1, true, true);
	PersistentEffect.SetDisplayInfo(ePerkBuff_Passive, Template.LocFriendlyName, Template.LocLongDescription, Template.IconImage, true,,Template.AbilitySourceName);
	Template.AddTargetEffect(PersistentEffect);

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

	Template.bCrossClassEligible = true;

	return Template;
}

static function X2Effect_HoloTarget HoloTargetEffect()
{
	local X2Effect_HoloTarget           Effect;
	local X2Condition_AbilityProperty   AbilityCondition;
	local X2AbilityTag                  AbilityTag;

	Effect = new class'X2Effect_HoloTarget';
	Effect.HitMod = default.HOLOTARGET_BONUS;
	Effect.BuildPersistentEffect(1, false, false, false, eGameRule_PlayerTurnBegin);
	Effect.bRemoveWhenTargetDies = true;
	Effect.bUseSourcePlayerState = true;

	AbilityTag = X2AbilityTag(`XEXPANDCONTEXT.FindTag("Ability"));
	AbilityTag.ParseObj = Effect;

	Effect.SetDisplayInfo(ePerkBuff_Penalty, default.HoloTargetEffectName, `XEXPAND.ExpandString(default.HoloTargetEffectDesc), "img:///UILibrary_PerkIcons.UIPerk_holotargeting", true);

	AbilityCondition = new class'X2Condition_AbilityProperty';
	AbilityCondition.OwnerHasSoldierAbilities.AddItem('HoloTargeting');
	Effect.TargetConditions.AddItem(AbilityCondition);

	// bsg-dforrest (7.27.17): need to clear out ParseObject
	AbilityTag.ParseObj = none;
	// bsg-dforrest (7.27.17): end

	return Effect;
}

static function X2AbilityTemplate BulletShred()
{
	local X2AbilityTemplate                 Template;
	local X2AbilityCost_Ammo                AmmoCost;
	local X2Effect_ApplyWeaponDamage        WeaponDamageEffect;
	local array<name>                       SkipExclusions;
	local X2AbilityToHitCalc_StandardAim    StandardAim;
	local X2AbilityCooldown                 Cooldown;
	local X2Condition_Visibility            VisibilityCondition;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'BulletShred');

	// Icon Properties
	Template.IconImage = "img:///UILibrary_PerkIcons.UIPerk_bulletshred";
	Template.ShotHUDPriority = class'UIUtilities_Tactical'.const.CLASS_COLONEL_PRIORITY;
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_AlwaysShow;
	Template.AbilitySourceName = 'eAbilitySource_Perk';
	Template.DisplayTargetHitChance = true;
	Template.AbilityConfirmSound = "TacticalUI_ActivateAbility";

	// Activated by a button press; additionally, tells the AI this is an activatable
	Template.AbilityTriggers.AddItem(default.PlayerInputTrigger);

	// *** VALIDITY CHECKS *** //
	//  Normal effect restrictions (except disoriented)
	SkipExclusions.AddItem(class'X2AbilityTemplateManager'.default.DisorientedName);
	Template.AddShooterEffectExclusions(SkipExclusions);

	// Targeting Details
	// Can only shoot visible enemies
	VisibilityCondition = new class'X2Condition_Visibility';
	VisibilityCondition.bRequireGameplayVisible = true;
	VisibilityCondition.bAllowSquadsight = true;
	Template.AbilityTargetConditions.AddItem(VisibilityCondition);
	// Can't target dead; Can't target friendlies
	Template.AbilityTargetConditions.AddItem(default.LivingHostileTargetProperty);
	// Can't shoot while dead
	Template.AbilityShooterConditions.AddItem(default.LivingShooterProperty);
	// Only at single targets that are in range.
	Template.AbilityTargetStyle = default.SimpleSingleTarget;

	// Action Point
	Template.AbilityCosts.AddItem(default.WeaponActionTurnEnding);

	// Ammo
	AmmoCost = new class'X2AbilityCost_Ammo';
	AmmoCost.iAmmo = 3;
	Template.AbilityCosts.AddItem(AmmoCost);
	Template.bAllowAmmoEffects = true;

	Cooldown = new class'X2AbilityCooldown';
	Cooldown.iNumTurns = default.BULLETSHRED_COOLDOWN;
	Template.AbilityCooldown = Cooldown;

	// Weapon Upgrade Compatibility
	Template.bAllowFreeFireWeaponUpgrade = true;                                            // Flag that permits action to become 'free action' via 'Hair Trigger' or similar upgrade / effects

	WeaponDamageEffect = ShredderDamageEffect();
	WeaponDamageEffect.EffectDamageValue.Rupture = default.BULLET_SHRED;
	Template.AddTargetEffect(WeaponDamageEffect);
	Template.bAllowBonusWeaponEffects = true;

	Template.AddTargetEffect(HoloTargetEffect());
	Template.AssociatedPassives.AddItem('HoloTargeting');

	StandardAim = new class'X2AbilityToHitCalc_StandardAim';
	StandardAim.bHitsAreCrits = true;
	Template.AbilityToHitCalc = StandardAim;
	Template.AbilityToHitOwnerOnMissCalc = StandardAim;

	// Targeting Method
	Template.TargetingMethod = class'X2TargetingMethod_OverTheShoulder';
	Template.bUsesFiringCamera = true;
	Template.CinescriptCameraType = "StandardGunFiring";

	// Voice events
	Template.ActivationSpeech = 'BulletShred';

	// MAKE IT LIVE!
	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	Template.BuildVisualizationFn = TypicalAbility_BuildVisualization;

	Template.bCrossClassEligible = true;

	Template.SuperConcealmentLoss = class'X2AbilityTemplateManager'.default.SuperConcealmentStandardShotLoss;
	Template.ChosenActivationIncreasePerUse = class'X2AbilityTemplateManager'.default.StandardShotChosenActivationIncreasePerUse;
	Template.LostSpawnIncreasePerUse = class'X2AbilityTemplateManager'.default.StandardShotLostSpawnIncreasePerUse;
//BEGIN AUTOGENERATED CODE: Template Overrides 'BulletShred'
	Template.bFrameEvenWhenUnitIsHidden = true;
//END AUTOGENERATED CODE: Template Overrides 'BulletShred'

	return Template;
}

static function X2AbilityTemplate VolatileMix()
{
	local X2AbilityTemplate						Template;
	local X2AbilityTargetStyle                  TargetStyle;
	local X2AbilityTrigger						Trigger;
	local X2Effect_VolatileMix                  MixEffect;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'VolatileMix');

	// Icon Properties
	Template.IconImage = "img:///UILibrary_PerkIcons.UIPerk_volatilemix";

	Template.AbilitySourceName = 'eAbilitySource_Perk';
	Template.eAbilityIconBehaviorHUD = EAbilityIconBehavior_NeverShow;
	Template.Hostility = eHostility_Neutral;

	Template.AbilityToHitCalc = default.DeadEye;

	TargetStyle = new class'X2AbilityTarget_Self';
	Template.AbilityTargetStyle = TargetStyle;

	Trigger = new class'X2AbilityTrigger_UnitPostBeginPlay';
	Template.AbilityTriggers.AddItem(Trigger);

	MixEffect = new class'X2Effect_VolatileMix';
	MixEffect.BuildPersistentEffect(1, true, true, true);
	MixEffect.SetDisplayInfo(ePerkBuff_Passive, Template.LocFriendlyName, Template.GetMyLongDescription(), Template.IconImage,,,Template.AbilitySourceName);
	MixEffect.BonusDamage = default.VOLATILE_DAMAGE;
	Template.AddTargetEffect(MixEffect);

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	//  NOTE: No visualization on purpose!

	Template.bCrossClassEligible = true;

	return Template;
}

static function X2Effect_ApplyWeaponDamage ShredderDamageEffect()
{
	local X2Effect_ApplyWeaponDamage    DamageEffect;

	DamageEffect = new class'X2Effect_Shredder';

	return DamageEffect;
}

static function X2AbilityTemplate SaturationFire()
{
	local X2AbilityTemplate                 Template;
	local X2AbilityCost_Ammo                AmmoCost;
	local X2AbilityTarget_Cursor            CursorTarget;
	local X2AbilityMultiTarget_Cone         ConeMultiTarget;
	local X2Condition_UnitProperty          UnitPropertyCondition;
	local X2AbilityToHitCalc_StandardAim    StandardAim;
	local X2AbilityCooldown                 Cooldown;
	local X2Effect_ApplyDirectionalWorldDamage WorldDamage;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'SaturationFire');

	AmmoCost = new class'X2AbilityCost_Ammo';
	AmmoCost.iAmmo = 3;
	Template.AbilityCosts.AddItem(AmmoCost);

	Template.AbilityCosts.AddItem(default.WeaponActionTurnEnding);

	Cooldown = new class'X2AbilityCooldown';
	Cooldown.iNumTurns = default.SATURATION_FIRE_COOLDOWN;
	Template.AbilityCooldown = Cooldown;

	StandardAim = new class'X2AbilityToHitCalc_StandardAim';
	StandardAim.bMultiTargetOnly = true;
	Template.AbilityToHitCalc = StandardAim;

	Template.AddMultiTargetEffect(ShredderDamageEffect());
	Template.bOverrideAim = true;

	WorldDamage = new class'X2Effect_ApplyDirectionalWorldDamage';
	WorldDamage.bUseWeaponDamageType = true;
	WorldDamage.bUseWeaponEnvironmentalDamage = false;
	WorldDamage.EnvironmentalDamageAmount = 30;
	WorldDamage.bApplyOnHit = true;
	WorldDamage.bApplyOnMiss = true;
	WorldDamage.bApplyToWorldOnHit = true;
	WorldDamage.bApplyToWorldOnMiss = true;
	WorldDamage.bHitAdjacentDestructibles = true;
	WorldDamage.PlusNumZTiles = 1;
	WorldDamage.bHitTargetTile = true;
	WorldDamage.ApplyChance = default.SATURATION_DESTRUCTION_CHANCE;
	Template.AddMultiTargetEffect(WorldDamage);

	CursorTarget = new class'X2AbilityTarget_Cursor';
	Template.AbilityTargetStyle = CursorTarget;

	ConeMultiTarget = new class'X2AbilityMultiTarget_Cone';
	ConeMultiTarget.bExcludeSelfAsTargetIfWithinRadius = true;
	ConeMultiTarget.ConeEndDiameter = default.SATURATION_TILE_WIDTH * class'XComWorldData'.const.WORLD_StepSize;
	ConeMultiTarget.bUseWeaponRangeForLength = true;
	ConeMultiTarget.fTargetRadius = 99;     //  large number to handle weapon range - targets will get filtered according to cone constraints
	ConeMultiTarget.bIgnoreBlockingCover = true;
	Template.AbilityMultiTargetStyle = ConeMultiTarget;

	UnitPropertyCondition = new class'X2Condition_UnitProperty';
	UnitPropertyCondition.ExcludeDead = true;
	UnitPropertyCondition.ExcludeFriendlyToSource = false;
	Template.AbilityShooterConditions.AddItem(UnitPropertyCondition);
	Template.AbilityTargetConditions.AddItem(UnitPropertyCondition);

	Template.AddShooterEffectExclusions();

	Template.AbilityTriggers.AddItem(default.PlayerInputTrigger);

	Template.ShotHUDPriority = class'UIUtilities_Tactical'.const.CLASS_COLONEL_PRIORITY;
	Template.AbilitySourceName = 'eAbilitySource_Perk';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_AlwaysShow;
	Template.IconImage = "img:///UILibrary_PerkIcons.UIPerk_saturationfire";
	Template.AbilityConfirmSound = "TacticalUI_ActivateAbility";

	Template.ActionFireClass = class'X2Action_Fire_SaturationFire';

	Template.TargetingMethod = class'X2TargetingMethod_Cone';

	Template.ActivationSpeech = 'SaturationFire';
	Template.CinescriptCameraType = "Grenadier_SaturationFire";
	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	Template.BuildVisualizationFn = TypicalAbility_BuildVisualization;

	Template.SuperConcealmentLoss = class'X2AbilityTemplateManager'.default.SuperConcealmentStandardShotLoss;
	Template.ChosenActivationIncreasePerUse = class'X2AbilityTemplateManager'.default.StandardShotChosenActivationIncreasePerUse;
	Template.LostSpawnIncreasePerUse = class'X2AbilityTemplateManager'.default.StandardShotLostSpawnIncreasePerUse;
//BEGIN AUTOGENERATED CODE: Template Overrides 'SaturationFire'
	Template.bFrameEvenWhenUnitIsHidden = true;
//END AUTOGENERATED CODE: Template Overrides 'SaturationFire'

	return Template;
}

static function X2AbilityTemplate ChainShot()
{
	local X2AbilityTemplate					Template;
	local X2AbilityCost_Ammo				AmmoCost;
	local X2AbilityToHitCalc_StandardAim    ToHitCalc;
	local X2AbilityCooldown                 Cooldown;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'ChainShot');

	Template.AbilityCosts.AddItem(default.WeaponActionTurnEnding);

	Cooldown = new class'X2AbilityCooldown';
	Cooldown.iNumTurns = default.CHAINSHOT_COOLDOWN;
	Template.AbilityCooldown = Cooldown;

	//  require 2 ammo to be present so that both shots can be taken
	AmmoCost = new class'X2AbilityCost_Ammo';
	AmmoCost.iAmmo = 2;
	AmmoCost.bFreeCost = true;
	Template.AbilityCosts.AddItem(AmmoCost);
	//  actually charge 1 ammo for this shot. the 2nd shot will charge the extra ammo.
	AmmoCost = new class'X2AbilityCost_Ammo';
	AmmoCost.iAmmo = 1;
	Template.AbilityCosts.AddItem(AmmoCost);

	ToHitCalc = new class'X2AbilityToHitCalc_StandardAim';
	ToHitCalc.BuiltInHitMod = default.CHAINSHOT_HIT_MOD;
	Template.AbilityToHitCalc = ToHitCalc;
	Template.AbilityToHitOwnerOnMissCalc = ToHitCalc;

	Template.AbilityTargetStyle = default.SimpleSingleTarget;

	Template.AbilityShooterConditions.AddItem(default.LivingShooterProperty);
	Template.AddShooterEffectExclusions();

	Template.AbilityTargetConditions.AddItem(default.LivingHostileTargetProperty);
	Template.AbilityTargetConditions.AddItem(default.GameplayVisibilityCondition);

	Template.AddTargetEffect(HoloTargetEffect());
	Template.AssociatedPassives.AddItem('HoloTargeting');
	Template.AddTargetEffect(ShredderDamageEffect());
	Template.AddTargetEffect(class'X2Ability'.default.WeaponUpgradeMissDamage);
	Template.bAllowAmmoEffects = true;
	Template.bAllowBonusWeaponEffects = true;

	Template.AbilityTriggers.AddItem(default.PlayerInputTrigger);

	Template.ShotHUDPriority = class'UIUtilities_Tactical'.const.CLASS_CAPTAIN_PRIORITY;
	Template.AbilitySourceName = 'eAbilitySource_Perk';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_AlwaysShow;
	Template.IconImage = "img:///UILibrary_PerkIcons.UIPerk_chainshot";
	Template.AbilityConfirmSound = "TacticalUI_ActivateAbility";

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

	Template.AdditionalAbilities.AddItem('ChainShot2');
	Template.PostActivationEvents.AddItem('ChainShot2');

	Template.DamagePreviewFn = ChainShotDamagePreview;
	Template.bCrossClassEligible = true;

	Template.SuperConcealmentLoss = class'X2AbilityTemplateManager'.default.SuperConcealmentStandardShotLoss;
	Template.ChosenActivationIncreasePerUse = class'X2AbilityTemplateManager'.default.StandardShotChosenActivationIncreasePerUse;
	Template.LostSpawnIncreasePerUse = class'X2AbilityTemplateManager'.default.StandardShotLostSpawnIncreasePerUse;
//BEGIN AUTOGENERATED CODE: Template Overrides 'ChainShot'
	Template.bFrameEvenWhenUnitIsHidden = true;
//END AUTOGENERATED CODE: Template Overrides 'ChainShot'

	return Template;
}

function bool ChainShotDamagePreview(XComGameState_Ability AbilityState, StateObjectReference TargetRef, out WeaponDamageValue MinDamagePreview, out WeaponDamageValue MaxDamagePreview, out int AllowsShield)
{
	local XComGameState_Unit AbilityOwner;
	local StateObjectReference ChainShot2Ref;
	local XComGameState_Ability ChainShot2Ability;
	local XComGameStateHistory History;

	AbilityState.NormalDamagePreview(TargetRef, MinDamagePreview, MaxDamagePreview, AllowsShield);

	History = `XCOMHISTORY;
	AbilityOwner = XComGameState_Unit(History.GetGameStateForObjectID(AbilityState.OwnerStateObject.ObjectID));
	ChainShot2Ref = AbilityOwner.FindAbility('ChainShot2');
	ChainShot2Ability = XComGameState_Ability(History.GetGameStateForObjectID(ChainShot2Ref.ObjectID));
	if (ChainShot2Ability == none)
	{
		`RedScreenOnce("Unit has ChainShot but is missing ChainShot2. Not good. -jbouscher @gameplay");
	}
	else
	{
		ChainShot2Ability.NormalDamagePreview(TargetRef, MinDamagePreview, MaxDamagePreview, AllowsShield);
	}
	return true;
}

static function X2AbilityTemplate ChainShot2()
{
	local X2AbilityTemplate					Template;
	local X2AbilityCost_Ammo				AmmoCost;
	local X2AbilityToHitCalc_StandardAim    ToHitCalc;
	local X2AbilityTrigger_EventListener    Trigger;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'ChainShot2');

	AmmoCost = new class'X2AbilityCost_Ammo';
	AmmoCost.iAmmo = 1;
	Template.AbilityCosts.AddItem(AmmoCost);

	ToHitCalc = new class'X2AbilityToHitCalc_StandardAim';
	ToHitCalc.BuiltInHitMod = default.CHAINSHOT_HIT_MOD;
	Template.AbilityToHitCalc = ToHitCalc;
	Template.AbilityToHitOwnerOnMissCalc = ToHitCalc;

	Template.AbilityTargetStyle = default.SimpleSingleTarget;

	Template.AbilityShooterConditions.AddItem(default.LivingShooterProperty);
	Template.AddShooterEffectExclusions();

	Template.AbilityTargetConditions.AddItem(default.LivingHostileTargetProperty);

	Template.AddTargetEffect(HoloTargetEffect());
	Template.AssociatedPassives.AddItem('HoloTargeting');
	Template.AddTargetEffect(ShredderDamageEffect());
	Template.AddTargetEffect(class'X2Ability'.default.WeaponUpgradeMissDamage);
	Template.bAllowAmmoEffects = true;
	Template.bAllowBonusWeaponEffects = true;

	Trigger = new class'X2AbilityTrigger_EventListener';
	Trigger.ListenerData.Deferral = ELD_OnStateSubmitted;
	Trigger.ListenerData.EventID = 'ChainShot2';
	Trigger.ListenerData.Filter = eFilter_Unit;
	Trigger.ListenerData.EventFn = class'XComGameState_Ability'.static.ChainShotListener;
	Template.AbilityTriggers.AddItem(Trigger);

	Template.ShotHUDPriority = class'UIUtilities_Tactical'.const.CLASS_CAPTAIN_PRIORITY;
	Template.AbilitySourceName = 'eAbilitySource_Perk';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_NeverShow;
	Template.IconImage = "img:///UILibrary_PerkIcons.UIPerk_chainshot";

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	Template.BuildVisualizationFn = TypicalAbility_BuildVisualization;
	Template.MergeVisualizationFn = SequentialShot_MergeVisualization;
	Template.bShowActivation = true;

	Template.SuperConcealmentLoss = class'X2AbilityTemplateManager'.default.SuperConcealmentStandardShotLoss;
	Template.ChosenActivationIncreasePerUse = class'X2AbilityTemplateManager'.default.StandardShotChosenActivationIncreasePerUse;
	Template.LostSpawnIncreasePerUse = class'X2AbilityTemplateManager'.default.StandardShotLostSpawnIncreasePerUse;

	//BEGIN AUTOGENERATED CODE: Template Overrides 'ChainShot2'
	Template.bFrameEvenWhenUnitIsHidden = true;
	//END AUTOGENERATED CODE: Template Overrides 'ChainShot2'

	return Template;
}

static function X2AbilityTemplate Demolition()
{
	local X2AbilityTemplate						Template;
	local X2AbilityCost_Ammo					AmmoCost;
	local X2Effect_ApplyDirectionalWorldDamage  WorldDamage;
	local X2AbilityCooldown						Cooldown;
	local X2Condition_UnitProperty              TargetCondition;
	local X2AbilityToHitCalc_RollStat           RollStat;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'Demolition');

	Template.ShotHUDPriority = class'UIUtilities_Tactical'.const.CLASS_SERGEANT_PRIORITY;
	Template.AbilitySourceName = 'eAbilitySource_Perk';
	Template.eAbilityIconBehaviorHUD = eAbilityIconBehavior_AlwaysShow;
	Template.IconImage = "img:///UILibrary_PerkIcons.UIPerk_demolition";
	Template.AbilityConfirmSound = "TacticalUI_ActivateAbility";
	Template.bLimitTargetIcons = true;

	Template.AbilityCosts.AddItem(default.WeaponActionTurnEnding);

	Cooldown = new class'X2AbilityCooldown';
	Cooldown.iNumTurns = default.DEMOLITION_COOLDOWN;
	Template.AbilityCooldown = Cooldown;

	AmmoCost = new class'X2AbilityCost_Ammo';
	AmmoCost.iAmmo = 2;
	Template.AbilityCosts.AddItem(AmmoCost);

	RollStat = new class'X2AbilityToHitCalc_RollStat';
	RollStat.BaseChance = default.DEMO_HIT_BONUS;
	Template.AbilityToHitCalc = RollStat;
	Template.AbilityTargetStyle = default.SimpleSingleTarget;
	Template.AbilityTriggers.AddItem(default.PlayerInputTrigger);

	Template.AbilityShooterConditions.AddItem(default.LivingShooterProperty);
	Template.AddShooterEffectExclusions();

	TargetCondition = new class'X2Condition_UnitProperty';
	TargetCondition.ExcludeAlive=false;
	TargetCondition.ExcludeDead=true;
	TargetCondition.ExcludeFriendlyToSource=true;
	TargetCondition.ExcludeHostileToSource=false;
	TargetCondition.TreatMindControlledSquadmateAsHostile=true;
	TargetCondition.ExcludeNoCover=true;
	TargetCondition.ExcludeNoCoverToSource=true;
	TargetCondition.FailOnNonUnits = true;
	Template.AbilityTargetConditions.AddItem(TargetCondition);
	Template.AbilityTargetConditions.AddItem(default.GameplayVisibilityCondition);

	WorldDamage = new class'X2Effect_ApplyDirectionalWorldDamage';
	WorldDamage.bUseWeaponDamageType = true;
	WorldDamage.bUseWeaponEnvironmentalDamage = false;
	WorldDamage.EnvironmentalDamageAmount = 30;
	WorldDamage.bApplyOnHit = true;
	WorldDamage.bApplyOnMiss = false;
	WorldDamage.bApplyToWorldOnHit = true;
	WorldDamage.bApplyToWorldOnMiss = false;
	WorldDamage.bHitAdjacentDestructibles = true;
	WorldDamage.PlusNumZTiles = 1;
	WorldDamage.bHitTargetTile = true;
	Template.AddTargetEffect(WorldDamage);

	//  visually always appear as a miss so the target unit doesn't look like it's being damaged
	Template.bOverrideVisualResult = true;
	Template.OverrideVisualResult = eHit_Miss;

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

	Template.SuperConcealmentLoss = class'X2AbilityTemplateManager'.default.SuperConcealmentStandardShotLoss;
	Template.ChosenActivationIncreasePerUse = class'X2AbilityTemplateManager'.default.StandardShotChosenActivationIncreasePerUse;
	Template.LostSpawnIncreasePerUse = class'X2AbilityTemplateManager'.default.StandardShotLostSpawnIncreasePerUse;
//BEGIN AUTOGENERATED CODE: Template Overrides 'Demolition'
	Template.bFrameEvenWhenUnitIsHidden = true;
//END AUTOGENERATED CODE: Template Overrides 'Demolition'

	return Template;
}

error: pathspec 'X2WOTCCommunityHighlander/Src/XComGame/Classes/X2Ability_GrenadierAbilitySet.uc' did not match any file(s) known to git


Implement Issue #1090 - prevent log warnings and redscreens caused by equipping Alien Hunters armor in the Shell.

//---------------------------------------------------------------------------------------
//  FILE:    X2Item_DLC_Day60Armors.uc
//  AUTHOR:  Joe Weinhoffer
//
//---------------------------------------------------------------------------------------
//  Copyright (c) 2016 Firaxis Games, Inc. All rights reserved.
//---------------------------------------------------------------------------------------
class X2Item_DLC_Day60Armors extends X2Item;

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

	Armors.AddItem(CreateMediumAlienArmor());
	Armors.AddItem(CreateHeavyAlienArmor());
	Armors.AddItem(CreateHeavyAlienArmorMk2());
	Armors.AddItem(CreateLightAlienArmor());
	Armors.AddItem(CreateLightAlienArmorMk2());
	return Armors;
}

static function X2DataTemplate CreateMediumAlienArmor()
{
	local X2ArmorTemplate Template;

	`CREATE_X2TEMPLATE(class'X2ArmorTemplate', Template, 'MediumAlienArmor');
	Template.strImage = "img:///UILibrary_DLC2Images.Inv_IcarusArmor";
	Template.ItemCat = 'armor';
	Template.bAddsUtilitySlot = true;
	Template.StartingItem = false;
	Template.CanBeBuilt = false;
	Template.PointsToComplete = 0;
	Template.Abilities.AddItem('MediumAlienArmorStats');
	Template.Abilities.AddItem('VaultAbility');
	Template.Abilities.AddItem('VaultAbilityPassive');
	Template.Abilities.AddItem('IcarusPanic');
	Template.Abilities.AddItem('IcarusJump');
	Template.ArmorTechCat = 'powered';
	Template.Tier = 5;
	Template.AkAudioSoldierArmorSwitch = 'Icarus_Suit';
	Template.EquipNarrative = "DLC_60_NarrativeMoments.CIN_ArmorIntro_AlienMedium";
	Template.EquipSound = "StrategyUI_Armor_Equip_Powered";

	Template.SetUIStatMarkup(class'XLocalizedData'.default.HealthLabel, eStat_HP, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.MEDIUM_ALIEN_HEALTH_BONUS, true);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.MobilityLabel, eStat_Mobility, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.MEDIUM_ALIEN_MOBILITY_BONUS);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.ArmorLabel, eStat_ArmorMitigation, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.MEDIUM_ALIEN_MITIGATION_AMOUNT);

	Template.OnEquippedFn = SetIcarusSuitArmorTint;
	Template.OnUnequippedFn = ClearHelmet;

	return Template;
}

static function SetIcarusSuitArmorTint(XComGameState_Item ItemState, XComGameState_Unit UnitState, XComGameState NewGameState)
{
	local XComGameState_HeadquartersXCom XComHQ;
	local X2ArmorTemplate ArmorTemplate;
	local XComNarrativeMoment EquipNarrativeMoment;

	ArmorTemplate = X2ArmorTemplate(ItemState.GetMyTemplate());

	if (ArmorTemplate != none)
	{
		/// HL-Docs: ref:Bugfixes; issue:1090
		/// Prevent log warnings and redscreens when Alien Hunters armor is equipped in the Shell, e.g. Character Pool.
		/// Alien Hunters armor uses OnEquippedFn delegates to alter soldier appearance when the player equips them for the first time.
		/// The "is first time" check is done using XComHQ, which doesn't exist in the Shell.
		XComHQ = XComGameState_HeadquartersXCom(`XCOMHISTORY.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersXCom', true)); // Issue #1090 - Allow XComHQ to be 'none'
		if (XComHQ != none) // Issue #1090 - 'none' check XComHQ before accessing it.
		{
			EquipNarrativeMoment = XComNarrativeMoment(`CONTENT.RequestGameArchetype(ArmorTemplate.EquipNarrative));

			// If the armor intro for this armor hasn't been played yet, set the appearance for this armor
			if (XComHQ.CanPlayArmorIntroNarrativeMoment(EquipNarrativeMoment))
			{
				UnitState.kAppearance.iArmorTint = 72;
				UnitState.kAppearance.iArmorTintSecondary = 85;
				UnitState.kAppearance.nmPatterns = 'Pat_Nothing';
			}
		}
	}
}

static function X2DataTemplate CreateHeavyAlienArmor()
{
	local X2ArmorTemplate Template;

	`CREATE_X2TEMPLATE(class'X2ArmorTemplate', Template, 'HeavyAlienArmor');
	Template.strImage = "img:///UILibrary_DLC2Images.Inv_RageSuit";
	Template.ItemCat = 'armor';
	Template.StartingItem = false;
	Template.CanBeBuilt = false;
	Template.PointsToComplete = 0;
	Template.bHeavyWeapon = true;
	Template.Abilities.AddItem('HeavyAlienArmorStats');
	Template.Abilities.AddItem('Ragestrike');
	Template.Abilities.AddItem('RagePanic');
	Template.ArmorTechCat = 'plated';
	Template.Tier = 3;
	Template.AkAudioSoldierArmorSwitch = 'RAGE_Suit';
	Template.EquipNarrative = "DLC_60_NarrativeMoments.CIN_ArmorIntro_AlienHeavy";
	Template.EquipSound = "StrategyUI_Armor_Equip_Plated";

	Template.SetUIStatMarkup(class'XLocalizedData'.default.HealthLabel, eStat_HP, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.HEAVY_ALIEN_HEALTH_BONUS, true);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.MobilityLabel, eStat_Mobility, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.HEAVY_ALIEN_MOBILITY_BONUS);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.ArmorLabel, eStat_ArmorMitigation, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.HEAVY_ALIEN_MITIGATION_AMOUNT);

	Template.OnEquippedFn = SetRageSuitArmorTint;

	return Template;
}

static function X2DataTemplate CreateHeavyAlienArmorMk2()
{
	local X2ArmorTemplate Template;

	`CREATE_X2TEMPLATE(class'X2ArmorTemplate', Template, 'HeavyAlienArmorMk2');
	Template.strImage = "img:///UILibrary_DLC2Images.Inv_RageSuit";
	Template.ItemCat = 'armor';
	Template.StartingItem = false;
	Template.CanBeBuilt = false;
	Template.PointsToComplete = 0;
	Template.bHeavyWeapon = true;
	Template.Abilities.AddItem('HeavyAlienArmorMk2Stats');
	Template.Abilities.AddItem('Ragestrike');
	Template.Abilities.AddItem('RagePanic');
	Template.ArmorTechCat = 'plated';
	Template.Tier = 5;
	Template.AkAudioSoldierArmorSwitch = 'RAGE_Suit';
	Template.EquipNarrative = "DLC_60_NarrativeMoments.CIN_ArmorIntro_AlienHeavy";
	Template.EquipSound = "StrategyUI_Armor_Equip_Powered";

	Template.CreatorTemplateName = 'HeavyAlienArmorMk2_Schematic'; // The schematic which creates this item
	Template.BaseItem = 'HeavyAlienArmor'; // Which item this will be upgraded from

	Template.SetUIStatMarkup(class'XLocalizedData'.default.HealthLabel, eStat_HP, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.HEAVY_ALIEN_MK2_HEALTH_BONUS, true);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.MobilityLabel, eStat_Mobility, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.HEAVY_ALIEN_MK2_MOBILITY_BONUS);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.ArmorLabel, eStat_ArmorMitigation, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.HEAVY_ALIEN_MK2_MITIGATION_AMOUNT);

	Template.OnEquippedFn = SetRageSuitArmorTint;

	return Template;
}

static function SetRageSuitArmorTint(XComGameState_Item ItemState, XComGameState_Unit UnitState, XComGameState NewGameState)
{
	local XComGameState_HeadquartersXCom XComHQ;
	local X2ArmorTemplate ArmorTemplate;
	local XComNarrativeMoment EquipNarrativeMoment;

	ArmorTemplate = X2ArmorTemplate(ItemState.GetMyTemplate());

	if (ArmorTemplate != none)
	{
		XComHQ = XComGameState_HeadquartersXCom(`XCOMHISTORY.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersXCom', true)); // Issue #1090 - Allow XComHQ to be 'none'
		if (XComHQ != none) // Issue #1090 - 'none' check XComHQ before accessing it.
		{
			EquipNarrativeMoment = XComNarrativeMoment(`CONTENT.RequestGameArchetype(ArmorTemplate.EquipNarrative));

			// If the armor intro for this armor hasn't been played yet, set the appearance for this armor
			if (XComHQ.CanPlayArmorIntroNarrativeMoment(EquipNarrativeMoment))
			{
				UnitState.kAppearance.iArmorTint = 72;
				UnitState.kAppearance.iArmorTintSecondary = 95;
				UnitState.kAppearance.nmPatterns = 'Pat_Nothing';
			}
		}
	}
}

static function X2DataTemplate CreateLightAlienArmor()
{
	local X2ArmorTemplate Template;

	`CREATE_X2TEMPLATE(class'X2ArmorTemplate', Template, 'LightAlienArmor');
	Template.strImage = "img:///UILibrary_DLC2Images.Inv_SerpentArmor";
	Template.ItemCat = 'armor';
	Template.StartingItem = false;
	Template.CanBeBuilt = false;
	Template.PointsToComplete = 0;
	Template.Abilities.AddItem('LightAlienArmorStats');
	Template.Abilities.AddItem('Grapple');
	Template.Abilities.AddItem('FreezingLash');
	Template.Abilities.AddItem('SerpentPanic');
	Template.ArmorTechCat = 'plated';
	Template.Tier = 3;
	Template.AkAudioSoldierArmorSwitch = 'Serpent_Suit';
	Template.EquipNarrative = "DLC_60_NarrativeMoments.CIN_ArmorIntro_AlienLight";
	Template.EquipSound = "StrategyUI_Armor_Equip_Plated";

	Template.SetUIStatMarkup(class'XLocalizedData'.default.HealthLabel, eStat_HP, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.LIGHT_ALIEN_HEALTH_BONUS, true);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.MobilityLabel, eStat_Mobility, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.LIGHT_ALIEN_MOBILITY_BONUS);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.DodgeLabel, eStat_Dodge, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.LIGHT_ALIEN_DODGE_BONUS);

	Template.OnEquippedFn = SetSerpentSuitArmorTint;
	Template.OnUnequippedFn = ClearHelmet;

	return Template;
}

static function X2DataTemplate CreateLightAlienArmorMk2()
{
	local X2ArmorTemplate Template;

	`CREATE_X2TEMPLATE(class'X2ArmorTemplate', Template, 'LightAlienArmorMk2');
	Template.strImage = "img:///UILibrary_DLC2Images.Inv_SerpentArmor";
	Template.ItemCat = 'armor';
	Template.StartingItem = false;
	Template.CanBeBuilt = false;
	Template.PointsToComplete = 0;
	Template.Abilities.AddItem('LightAlienArmorMk2Stats');
	Template.Abilities.AddItem('GrapplePowered');
	Template.Abilities.AddItem('FreezingLash');
	Template.Abilities.AddItem('SerpentPanic');
	Template.ArmorTechCat = 'powered';
	Template.Tier = 5;
	Template.AkAudioSoldierArmorSwitch = 'Serpent_Suit';
	Template.EquipNarrative = "DLC_60_NarrativeMoments.CIN_ArmorIntro_AlienLight";
	Template.EquipSound = "StrategyUI_Armor_Equip_Powered";

	Template.CreatorTemplateName = 'LightAlienArmorMk2_Schematic'; // The schematic which creates this item
	Template.BaseItem = 'LightAlienArmor'; // Which item this will be upgraded from

	Template.SetUIStatMarkup(class'XLocalizedData'.default.HealthLabel, eStat_HP, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.LIGHT_ALIEN_MK2_HEALTH_BONUS, true);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.MobilityLabel, eStat_Mobility, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.LIGHT_ALIEN_MK2_MOBILITY_BONUS);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.DodgeLabel, eStat_Dodge, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.LIGHT_ALIEN_MK2_DODGE_BONUS);

	Template.OnEquippedFn = SetSerpentSuitArmorTint;
	Template.OnUnequippedFn = ClearHelmet;

	return Template;
}

static function SetSerpentSuitArmorTint(XComGameState_Item ItemState, XComGameState_Unit UnitState, XComGameState NewGameState)
{
	local XComGameState_HeadquartersXCom XComHQ;
	local X2ArmorTemplate ArmorTemplate;
	local XComNarrativeMoment EquipNarrativeMoment;

	ArmorTemplate = X2ArmorTemplate(ItemState.GetMyTemplate());

	if (ArmorTemplate != none)
	{
		XComHQ = XComGameState_HeadquartersXCom(`XCOMHISTORY.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersXCom', true)); // Issue #1090 - Allow XComHQ to be 'none'
		if (XComHQ != none) // Issue #1090 - 'none' check XComHQ before accessing it.
		{
			EquipNarrativeMoment = XComNarrativeMoment(`CONTENT.RequestGameArchetype(ArmorTemplate.EquipNarrative));

			// If the armor intro for this armor hasn't been played yet, set the appearance for this armor
			if (XComHQ.CanPlayArmorIntroNarrativeMoment(EquipNarrativeMoment))
			{
				UnitState.kAppearance.iArmorTint = 84;
				UnitState.kAppearance.iArmorTintSecondary = 96;
				UnitState.kAppearance.nmPatterns = 'DLC_60_Patterns_E';
			}
		}
	}
}

static function ClearHelmet(XComGameState_Item ItemState, XComGameState_Unit UnitState, XComGameState NewGameState)
{
	UnitState.kAppearance.nmHelmet = '';
}

//---------------------------------------------------------------------------------------
//  FILE:    X2Item_DLC_Day60Armors.uc
//  AUTHOR:  Joe Weinhoffer
//
//---------------------------------------------------------------------------------------
//  Copyright (c) 2016 Firaxis Games, Inc. All rights reserved.
//---------------------------------------------------------------------------------------
class X2Item_DLC_Day60Armors extends X2Item;

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

	Armors.AddItem(CreateMediumAlienArmor());
	Armors.AddItem(CreateHeavyAlienArmor());
	Armors.AddItem(CreateHeavyAlienArmorMk2());
	Armors.AddItem(CreateLightAlienArmor());
	Armors.AddItem(CreateLightAlienArmorMk2());
	return Armors;
}

static function X2DataTemplate CreateMediumAlienArmor()
{
	local X2ArmorTemplate Template;

	`CREATE_X2TEMPLATE(class'X2ArmorTemplate', Template, 'MediumAlienArmor');
	Template.strImage = "img:///UILibrary_DLC2Images.Inv_IcarusArmor";
	Template.ItemCat = 'armor';
	Template.bAddsUtilitySlot = true;
	Template.StartingItem = false;
	Template.CanBeBuilt = false;
	Template.PointsToComplete = 0;
	Template.Abilities.AddItem('MediumAlienArmorStats');
	Template.Abilities.AddItem('VaultAbility');
	Template.Abilities.AddItem('VaultAbilityPassive');
	Template.Abilities.AddItem('IcarusPanic');
	Template.Abilities.AddItem('IcarusJump');
	Template.ArmorTechCat = 'powered';
	Template.Tier = 5;
	Template.AkAudioSoldierArmorSwitch = 'Icarus_Suit';
	Template.EquipNarrative = "DLC_60_NarrativeMoments.CIN_ArmorIntro_AlienMedium";
	Template.EquipSound = "StrategyUI_Armor_Equip_Powered";

	Template.SetUIStatMarkup(class'XLocalizedData'.default.HealthLabel, eStat_HP, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.MEDIUM_ALIEN_HEALTH_BONUS, true);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.MobilityLabel, eStat_Mobility, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.MEDIUM_ALIEN_MOBILITY_BONUS);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.ArmorLabel, eStat_ArmorMitigation, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.MEDIUM_ALIEN_MITIGATION_AMOUNT);

	Template.OnEquippedFn = SetIcarusSuitArmorTint;
	Template.OnUnequippedFn = ClearHelmet;

	return Template;
}

static function SetIcarusSuitArmorTint(XComGameState_Item ItemState, XComGameState_Unit UnitState, XComGameState NewGameState)
{
	local XComGameState_HeadquartersXCom XComHQ;
	local X2ArmorTemplate ArmorTemplate;
	local XComNarrativeMoment EquipNarrativeMoment;

	ArmorTemplate = X2ArmorTemplate(ItemState.GetMyTemplate());

	if (ArmorTemplate != none)
	{
		XComHQ = XComGameState_HeadquartersXCom(`XCOMHISTORY.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersXCom'));
		EquipNarrativeMoment = XComNarrativeMoment(`CONTENT.RequestGameArchetype(ArmorTemplate.EquipNarrative));

		// If the armor intro for this armor hasn't been played yet, set the appearance for this armor
		if (XComHQ.CanPlayArmorIntroNarrativeMoment(EquipNarrativeMoment))
		{
			UnitState.kAppearance.iArmorTint = 72;
			UnitState.kAppearance.iArmorTintSecondary = 85;
			UnitState.kAppearance.nmPatterns = 'Pat_Nothing';
		}
	}
}

static function X2DataTemplate CreateHeavyAlienArmor()
{
	local X2ArmorTemplate Template;

	`CREATE_X2TEMPLATE(class'X2ArmorTemplate', Template, 'HeavyAlienArmor');
	Template.strImage = "img:///UILibrary_DLC2Images.Inv_RageSuit";
	Template.ItemCat = 'armor';
	Template.StartingItem = false;
	Template.CanBeBuilt = false;
	Template.PointsToComplete = 0;
	Template.bHeavyWeapon = true;
	Template.Abilities.AddItem('HeavyAlienArmorStats');
	Template.Abilities.AddItem('Ragestrike');
	Template.Abilities.AddItem('RagePanic');
	Template.ArmorTechCat = 'plated';
	Template.Tier = 3;
	Template.AkAudioSoldierArmorSwitch = 'RAGE_Suit';
	Template.EquipNarrative = "DLC_60_NarrativeMoments.CIN_ArmorIntro_AlienHeavy";
	Template.EquipSound = "StrategyUI_Armor_Equip_Plated";

	Template.SetUIStatMarkup(class'XLocalizedData'.default.HealthLabel, eStat_HP, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.HEAVY_ALIEN_HEALTH_BONUS, true);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.MobilityLabel, eStat_Mobility, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.HEAVY_ALIEN_MOBILITY_BONUS);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.ArmorLabel, eStat_ArmorMitigation, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.HEAVY_ALIEN_MITIGATION_AMOUNT);

	Template.OnEquippedFn = SetRageSuitArmorTint;

	return Template;
}

static function X2DataTemplate CreateHeavyAlienArmorMk2()
{
	local X2ArmorTemplate Template;

	`CREATE_X2TEMPLATE(class'X2ArmorTemplate', Template, 'HeavyAlienArmorMk2');
	Template.strImage = "img:///UILibrary_DLC2Images.Inv_RageSuit";
	Template.ItemCat = 'armor';
	Template.StartingItem = false;
	Template.CanBeBuilt = false;
	Template.PointsToComplete = 0;
	Template.bHeavyWeapon = true;
	Template.Abilities.AddItem('HeavyAlienArmorMk2Stats');
	Template.Abilities.AddItem('Ragestrike');
	Template.Abilities.AddItem('RagePanic');
	Template.ArmorTechCat = 'plated';
	Template.Tier = 5;
	Template.AkAudioSoldierArmorSwitch = 'RAGE_Suit';
	Template.EquipNarrative = "DLC_60_NarrativeMoments.CIN_ArmorIntro_AlienHeavy";
	Template.EquipSound = "StrategyUI_Armor_Equip_Powered";

	Template.CreatorTemplateName = 'HeavyAlienArmorMk2_Schematic'; // The schematic which creates this item
	Template.BaseItem = 'HeavyAlienArmor'; // Which item this will be upgraded from

	Template.SetUIStatMarkup(class'XLocalizedData'.default.HealthLabel, eStat_HP, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.HEAVY_ALIEN_MK2_HEALTH_BONUS, true);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.MobilityLabel, eStat_Mobility, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.HEAVY_ALIEN_MK2_MOBILITY_BONUS);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.ArmorLabel, eStat_ArmorMitigation, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.HEAVY_ALIEN_MK2_MITIGATION_AMOUNT);

	Template.OnEquippedFn = SetRageSuitArmorTint;

	return Template;
}

static function SetRageSuitArmorTint(XComGameState_Item ItemState, XComGameState_Unit UnitState, XComGameState NewGameState)
{
	local XComGameState_HeadquartersXCom XComHQ;
	local X2ArmorTemplate ArmorTemplate;
	local XComNarrativeMoment EquipNarrativeMoment;

	ArmorTemplate = X2ArmorTemplate(ItemState.GetMyTemplate());

	if (ArmorTemplate != none)
	{
		XComHQ = XComGameState_HeadquartersXCom(`XCOMHISTORY.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersXCom'));
		EquipNarrativeMoment = XComNarrativeMoment(`CONTENT.RequestGameArchetype(ArmorTemplate.EquipNarrative));

		// If the armor intro for this armor hasn't been played yet, set the appearance for this armor
		if (XComHQ.CanPlayArmorIntroNarrativeMoment(EquipNarrativeMoment))
		{
			UnitState.kAppearance.iArmorTint = 72;
			UnitState.kAppearance.iArmorTintSecondary = 95;
			UnitState.kAppearance.nmPatterns = 'Pat_Nothing';
		}
	}
}

static function X2DataTemplate CreateLightAlienArmor()
{
	local X2ArmorTemplate Template;

	`CREATE_X2TEMPLATE(class'X2ArmorTemplate', Template, 'LightAlienArmor');
	Template.strImage = "img:///UILibrary_DLC2Images.Inv_SerpentArmor";
	Template.ItemCat = 'armor';
	Template.StartingItem = false;
	Template.CanBeBuilt = false;
	Template.PointsToComplete = 0;
	Template.Abilities.AddItem('LightAlienArmorStats');
	Template.Abilities.AddItem('Grapple');
	Template.Abilities.AddItem('FreezingLash');
	Template.Abilities.AddItem('SerpentPanic');
	Template.ArmorTechCat = 'plated';
	Template.Tier = 3;
	Template.AkAudioSoldierArmorSwitch = 'Serpent_Suit';
	Template.EquipNarrative = "DLC_60_NarrativeMoments.CIN_ArmorIntro_AlienLight";
	Template.EquipSound = "StrategyUI_Armor_Equip_Plated";

	Template.SetUIStatMarkup(class'XLocalizedData'.default.HealthLabel, eStat_HP, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.LIGHT_ALIEN_HEALTH_BONUS, true);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.MobilityLabel, eStat_Mobility, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.LIGHT_ALIEN_MOBILITY_BONUS);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.DodgeLabel, eStat_Dodge, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.LIGHT_ALIEN_DODGE_BONUS);

	Template.OnEquippedFn = SetSerpentSuitArmorTint;
	Template.OnUnequippedFn = ClearHelmet;

	return Template;
}

static function X2DataTemplate CreateLightAlienArmorMk2()
{
	local X2ArmorTemplate Template;

	`CREATE_X2TEMPLATE(class'X2ArmorTemplate', Template, 'LightAlienArmorMk2');
	Template.strImage = "img:///UILibrary_DLC2Images.Inv_SerpentArmor";
	Template.ItemCat = 'armor';
	Template.StartingItem = false;
	Template.CanBeBuilt = false;
	Template.PointsToComplete = 0;
	Template.Abilities.AddItem('LightAlienArmorMk2Stats');
	Template.Abilities.AddItem('GrapplePowered');
	Template.Abilities.AddItem('FreezingLash');
	Template.Abilities.AddItem('SerpentPanic');
	Template.ArmorTechCat = 'powered';
	Template.Tier = 5;
	Template.AkAudioSoldierArmorSwitch = 'Serpent_Suit';
	Template.EquipNarrative = "DLC_60_NarrativeMoments.CIN_ArmorIntro_AlienLight";
	Template.EquipSound = "StrategyUI_Armor_Equip_Powered";

	Template.CreatorTemplateName = 'LightAlienArmorMk2_Schematic'; // The schematic which creates this item
	Template.BaseItem = 'LightAlienArmor'; // Which item this will be upgraded from

	Template.SetUIStatMarkup(class'XLocalizedData'.default.HealthLabel, eStat_HP, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.LIGHT_ALIEN_MK2_HEALTH_BONUS, true);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.MobilityLabel, eStat_Mobility, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.LIGHT_ALIEN_MK2_MOBILITY_BONUS);
	Template.SetUIStatMarkup(class'XLocalizedData'.default.DodgeLabel, eStat_Dodge, class'X2Ability_DLC_Day60ItemGrantedAbilitySet'.default.LIGHT_ALIEN_MK2_DODGE_BONUS);

	Template.OnEquippedFn = SetSerpentSuitArmorTint;
	Template.OnUnequippedFn = ClearHelmet;

	return Template;
}

static function SetSerpentSuitArmorTint(XComGameState_Item ItemState, XComGameState_Unit UnitState, XComGameState NewGameState)
{
	local XComGameState_HeadquartersXCom XComHQ;
	local X2ArmorTemplate ArmorTemplate;
	local XComNarrativeMoment EquipNarrativeMoment;

	ArmorTemplate = X2ArmorTemplate(ItemState.GetMyTemplate());

	if (ArmorTemplate != none)
	{
		XComHQ = XComGameState_HeadquartersXCom(`XCOMHISTORY.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersXCom'));
		EquipNarrativeMoment = XComNarrativeMoment(`CONTENT.RequestGameArchetype(ArmorTemplate.EquipNarrative));

		// If the armor intro for this armor hasn't been played yet, set the appearance for this armor
		if (XComHQ.CanPlayArmorIntroNarrativeMoment(EquipNarrativeMoment))
		{
			UnitState.kAppearance.iArmorTint = 84;
			UnitState.kAppearance.iArmorTintSecondary = 96;
			UnitState.kAppearance.nmPatterns = 'DLC_60_Patterns_E';
		}
	}
}

static function ClearHelmet(XComGameState_Item ItemState, XComGameState_Unit UnitState, XComGameState NewGameState)
{
	UnitState.kAppearance.nmHelmet = '';
}