2024 lines
65 KiB
Ucode
2024 lines
65 KiB
Ucode
//=============================================================================
|
|
// KFPawn_ZedMatriarch
|
|
//=============================================================================
|
|
// Pawn class for the matriarch.
|
|
//=============================================================================
|
|
// Killing Floor 2
|
|
// Copyright (C) 2016 Tripwire Interactive LLC
|
|
// - Dan Weiss
|
|
//=============================================================================
|
|
|
|
class KFPawn_ZedMatriarch extends KFPawn_MonsterBoss;
|
|
|
|
const HEAD_ARMOR_IDX = 0;
|
|
const CLAW_ARMOR_IDX = 1;
|
|
|
|
const BATTLE_PHASE_SHIELD = 0;
|
|
const BATTLE_PHASE_ARMOR = 1;
|
|
const BATTLE_PHASE_FLESH = 2;
|
|
const BATTLE_PHASE_CLOAK = 3;
|
|
|
|
//=============================================================================
|
|
// @name Battle Phases
|
|
//=============================================================================
|
|
|
|
struct BattleDamageFXInfo
|
|
{
|
|
var ParticleSystem Template;
|
|
var array<name> Sockets;
|
|
};
|
|
|
|
struct BattleDamageInfo
|
|
{
|
|
var array<BattleDamageFXInfo> FXInfo;
|
|
var transient array<ParticleSystemComponent> FXComponents;
|
|
};
|
|
|
|
/** Info for patriarch battle phases */
|
|
struct MatriarchBattlePhaseInfo
|
|
{
|
|
var float NextPhaseHealthPctThreshold;
|
|
|
|
// sweeping melee attack
|
|
var bool bCanUseSweepingClaw;
|
|
|
|
// instant ranged attack that jumps between players
|
|
var bool bCanUseTeslaBlast;
|
|
|
|
// sweeping ranged beam attack
|
|
var bool bCanUsePlasmaCannon;
|
|
|
|
// aoe attack around Matriarch
|
|
var bool bCanUseLightningStorm;
|
|
|
|
// shield against explosives
|
|
var bool bCanUseWarningSiren;
|
|
|
|
// ranged grapple attack
|
|
var bool bCanUseScorpionWhip;
|
|
|
|
/** Damage done by tentacle attack this battle phase */
|
|
var int TentacleDamage;
|
|
|
|
/** Base damage done by Melee Helper (this will replace the melee helper's BaseDamage) */
|
|
var float MeleeBaseDamage;
|
|
var float MeleeDamageScale;
|
|
|
|
var float GroundSpeedScale;
|
|
var float SprintSpeedScale;
|
|
|
|
var bool bCanCloak;
|
|
|
|
var bool bUseAltSprintAnim;
|
|
|
|
var bool bShouldTaunt;
|
|
|
|
var array<IncapSettingsInfo> IncapSettings;
|
|
|
|
var BattleDamageInfo DamageFX;
|
|
};
|
|
|
|
var array<MatriarchBattlePhaseInfo> BattlePhases;
|
|
var int TentacleDamage;
|
|
var class<KFDamageType> TentacleDamageType;
|
|
var bool bUseAltSprintAnim;
|
|
var bool bShouldTaunt;
|
|
|
|
//=============================================================================
|
|
// @name Dialog
|
|
//=============================================================================
|
|
|
|
/** Restricts how often tickdialog can be called */
|
|
var float TickDialogInterval;
|
|
|
|
//=============================================================================
|
|
// @name FX
|
|
//=============================================================================
|
|
|
|
/** Component used by the beam special move to play a hit location sound effect */
|
|
var AkComponent BeamHitAC;
|
|
|
|
var name LightSocketFront;
|
|
var name LightSocketBack;
|
|
|
|
var transient PointLightComponent LightTemplate_Phase1;
|
|
var transient PointLightComponent LightTemplate_Phase2;
|
|
var transient PointLightComponent LightTemplate_Phase3;
|
|
var transient PointLightComponent LightTemplate_Phase4;
|
|
|
|
var transient PointLightComponent BattlePhaseLightFront;
|
|
var transient PointLightComponent BattlePhaseLightBack;
|
|
|
|
var LinearColor GlowColor_Phase1;
|
|
var LinearColor GlowColor_Phase2;
|
|
var LinearColor GlowColor_Phase3;
|
|
var LinearColor GlowColor_Phase4;
|
|
|
|
//=============================================================================
|
|
// @name Gun tracking
|
|
//=============================================================================
|
|
|
|
/** Skel control for gun arm tracking */
|
|
var SkelControlLookAt GunTrackingSkelCtrl;
|
|
|
|
/** Allows gun tracking on the server if server aim precision is necessary (player-controlled, etc) */
|
|
var protected const bool bUseServerSideGunTracking;
|
|
|
|
/** Turns gun tracking on and off */
|
|
var bool bGunTracking;
|
|
|
|
/** The target to use for tracking */
|
|
var repnotify Pawn GunTarget;
|
|
|
|
var name GunTargetBoneName;
|
|
|
|
var Pawn BeamTarget;
|
|
|
|
//=============================================================================
|
|
// @name Shield
|
|
//=============================================================================
|
|
|
|
/** Shield Vars */
|
|
/** Amount of health shield has remaining */
|
|
var repnotify bool bShieldUp;
|
|
var bool bShieldBroken;
|
|
var float ShieldHealth;
|
|
var float ShieldHealthMax;
|
|
var const array<float> ShieldHealthMaxDefaults;
|
|
var float ShieldHealthScale;
|
|
|
|
var float ShieldBreakPawnHealthPct;
|
|
|
|
/** Replicated shield health percentage */
|
|
var repnotify byte ShieldHealthPctByte;
|
|
|
|
var float LastShieldHealthPct;
|
|
|
|
var ParticleSystem InvulnerableShieldFX;
|
|
var ParticleSystemComponent InvulnerableShieldPSC;
|
|
var name ShieldSocketName;
|
|
|
|
var KFSkinTypeEffects ShieldImpactEffects;
|
|
var KFGameExplosion ShieldShatterExplosionTemplate;
|
|
|
|
var const color ShieldColorGreen;
|
|
var const color ShieldCoreColorGreen;
|
|
var const color ShieldColorYellow;
|
|
var const color ShieldCoreColorYellow;
|
|
var const color ShieldColorOrange;
|
|
var const color ShieldCoreColorOrange;
|
|
var const color ShieldColorRed;
|
|
var const color ShieldCoreColorRed;
|
|
|
|
//=============================================================================
|
|
// @name Cloaking
|
|
//=============================================================================
|
|
|
|
/** Effect played upon cloaking/uncloaking */
|
|
var ParticleSystem CloakFX;
|
|
var Name CloakFXSocketName;
|
|
|
|
/** Gameplay-driven Ak objects, instanced at runtime */
|
|
var AkComponent CloakedAkComponent;
|
|
var AkEvent CloakedLoop;
|
|
var AkEvent CloakedLoopEnd;
|
|
|
|
/** Percent cloaked [0-1.0] */
|
|
var float CloakPercent;
|
|
|
|
/** Cloak speeds */
|
|
var float CloakSpeed;
|
|
var float DeCloakSpeed;
|
|
|
|
/** Cloak damage shimmer */
|
|
var float CloakShimmerAmount;
|
|
var float LastCloakShimmerTime;
|
|
|
|
//=============================================================================
|
|
// @name Minions
|
|
//=============================================================================
|
|
|
|
var float MinionSpawnDuration;
|
|
|
|
//=============================================================================
|
|
// @name Bump
|
|
//=============================================================================
|
|
|
|
/** The damage type to use when sprinting and bumping zeds */
|
|
var class<KFDamageType> HeavyBumpDamageType;
|
|
|
|
//=============================================================================
|
|
// @name Code
|
|
//=============================================================================
|
|
|
|
replication
|
|
{
|
|
if (bNetDirty)
|
|
bShieldUp, ShieldHealthPctByte, GunTarget, bUseAltSprintAnim, BeamTarget;
|
|
}
|
|
|
|
simulated event ReplicatedEvent(name VarName)
|
|
{
|
|
switch (VarName)
|
|
{
|
|
case nameof(ShieldHealthPctByte):
|
|
UpdateShield();
|
|
break;
|
|
|
|
case nameOf(bIsCloakingSpottedByTeam):
|
|
UpdateGameplayMICParams();
|
|
break;
|
|
|
|
case nameof(bShieldUp):
|
|
SetShieldUp(bShieldUp);
|
|
break;
|
|
|
|
case nameOf(bIsCloaking):
|
|
ClientCloakingStateUpdated();
|
|
break;
|
|
|
|
case nameOf(GunTarget):
|
|
SetGunTracking(GunTarget != none);
|
|
break;
|
|
|
|
case nameof(ArmorZoneStatus):
|
|
super.ReplicatedEvent(VarName);
|
|
OnArmorZoneStatusUpdated();
|
|
break;
|
|
|
|
default:
|
|
super.ReplicatedEvent(VarName);
|
|
}
|
|
}
|
|
|
|
simulated event PostBeginPlay()
|
|
{
|
|
super.PostBeginPlay();
|
|
|
|
// Give Matriarch his weapon
|
|
AddDefaultInventory();
|
|
|
|
// Set weapon state to active
|
|
if (Weapon != none)
|
|
{
|
|
Weapon.GotoState('Active');
|
|
}
|
|
|
|
`if(`notdefined(ShippingPC))
|
|
if (KFPC != none)
|
|
{
|
|
KFPC.MyGFxHUD.bossHealthBar.SetVisible(true);
|
|
}
|
|
`endif
|
|
|
|
// Start the dialog timer
|
|
if( WorldInfo.NetMode != NM_Client )
|
|
{
|
|
SetTimer(2.f, false, nameOf(Timer_TickDialog));
|
|
}
|
|
}
|
|
|
|
/** Cache skel controls */
|
|
simulated event PostInitAnimTree(SkeletalMeshComponent SkelComp)
|
|
{
|
|
Super.PostInitAnimTree(SkelComp);
|
|
|
|
if (WorldInfo.NetMode != NM_DedicatedServer || bUseServerSideGunTracking)
|
|
{
|
|
GunTrackingSkelCtrl = SkelControlLookAt(SkelComp.FindSkelControl('GunTracking'));
|
|
GunTrackingSkelCtrl.SetSkelControlActive( false );
|
|
}
|
|
}
|
|
|
|
/** Called from Possessed event when this controller has taken control of a Pawn */
|
|
function PossessedBy(Controller C, bool bVehicleTransition)
|
|
{
|
|
Super.PossessedBy(C, bVehicleTransition);
|
|
InitializeCurrentBattlePhase();
|
|
}
|
|
|
|
event TakeDamage(int Damage, Controller InstigatedBy, vector HitLocation, vector Momentum, class<DamageType> DamageType, optional TraceHitInfo HitInfo, optional Actor DamageCauser)
|
|
{
|
|
local float HealthPct;
|
|
|
|
super.TakeDamage(Damage, InstigatedBy, HitLocation, Momentum, DamageType, HitInfo, DamageCauser);
|
|
|
|
HealthPct = float(Health) / float(HealthMax);
|
|
if (HealthPct <= BattlePhases[CurrentBattlePhase].NextPhaseHealthPctThreshold)
|
|
{
|
|
IncrementBattlePhase();
|
|
}
|
|
}
|
|
|
|
function AdjustDamage(out int InDamage, out vector Momentum, Controller InstigatedBy, vector HitLocation, class<DamageType> DamageType, TraceHitInfo HitInfo, Actor DamageCauser)
|
|
{
|
|
// let the shield absorb unadjusted damage...
|
|
if (bShieldUp && ShieldHealth > 0)
|
|
{
|
|
ShieldHealth -= InDamage;
|
|
|
|
if (ShieldHealth < 0)
|
|
{
|
|
InDamage = Abs(ShieldHealth);
|
|
ShieldHealth = 0;
|
|
}
|
|
else
|
|
{
|
|
InDamage = 0;
|
|
}
|
|
|
|
ShieldHealthPctByte = FloatToByte(FClamp(ShieldHealth / ShieldHealthMax, 0.f, 1.f));
|
|
UpdateShield();
|
|
}
|
|
|
|
// then let the pawn adjust the remaining damage (if any)
|
|
super.AdjustDamage(InDamage, Momentum, InstigatedBy, HitLocation, DamageType, HitInfo, DamageCauser);
|
|
}
|
|
|
|
simulated event Tick(float DeltaTime)
|
|
{
|
|
local int i;
|
|
local float MinCloakPct;
|
|
local KFCharacterInfo_Monster MonsterInfo;
|
|
|
|
super.Tick(DeltaTime);
|
|
UpdateGunTrackingSkelCtrl(DeltaTime);
|
|
|
|
if (WorldInfo.NetMode != NM_DedicatedServer)
|
|
{
|
|
MonsterInfo = GetCharacterMonsterInfo();
|
|
if (CharacterMICs[0].Parent != MonsterInfo.SpottedSkins[0])
|
|
{
|
|
MinCloakPct = GetMinCloakPct();
|
|
|
|
if (!bIsCloaking)
|
|
{
|
|
if (CloakPercent < 1.0f)
|
|
{
|
|
CloakPercent = fMin(CloakPercent + DeltaTime*DeCloakSpeed, 1.f);
|
|
|
|
if (CloakPercent == 1.0f)
|
|
{
|
|
UpdateGameplayMICParams();
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < CharacterMICs.Length; ++i)
|
|
{
|
|
CharacterMICs[i].SetScalarParameterValue('Transparency', CloakPercent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (CloakPercent > MinCloakPct)
|
|
{
|
|
CloakPercent = fMax(CloakPercent - DeltaTime*CloakSpeed, MinCloakPct);
|
|
for (i = 0; i < CharacterMICs.Length; ++i)
|
|
{
|
|
CharacterMICs[i].SetScalarParameterValue('Transparency', CloakPercent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Gets the minimum cloaked amount based on the viewer */
|
|
simulated protected function float GetMinCloakPct()
|
|
{
|
|
return 0.f;
|
|
}
|
|
|
|
//=============================================================================
|
|
// @name Shield
|
|
//=============================================================================
|
|
|
|
simulated function SetShieldUp(bool bUp)
|
|
{
|
|
if (bShieldBroken)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (Role == ROLE_Authority && ShieldHealth > 0)
|
|
{
|
|
bShieldUp = bUp;
|
|
|
|
if (Role == Role_Authority)
|
|
{
|
|
`DialogManager.PlayMatriarchShieldUpEvent(self);
|
|
}
|
|
}
|
|
|
|
if (WorldInfo.NetMode != NM_DedicatedServer)
|
|
{
|
|
if (bShieldUp)
|
|
{
|
|
// this creates a new component instead of reactivating the old one because reactivating
|
|
// doesn't work at the moment or maybe ever?
|
|
ActivateShieldFX();
|
|
}
|
|
else
|
|
{
|
|
InvulnerableShieldPSC.DeactivateSystem();
|
|
InvulnerableShieldPSC = none;
|
|
}
|
|
}
|
|
}
|
|
|
|
function ActivateShield()
|
|
{
|
|
local KFGameInfo KFGI;
|
|
local float HealthMod;
|
|
local float HeadHealthMod;
|
|
|
|
KFGI = KFGameInfo(WorldInfo.Game);
|
|
if (KFGI != None)
|
|
{
|
|
HealthMod = 1.f;
|
|
KFGI.DifficultyInfo.GetAIHealthModifier(self, KFGI.GetModifiedGameDifficulty(), KFGI.GetLivingPlayerCount(), HealthMod, HeadHealthMod);
|
|
|
|
ShieldHealth = ShieldHealthMaxDefaults[KFGI.GetModifiedGameDifficulty()] * HealthMod * ShieldHealthScale;
|
|
|
|
if (KFGI.OutbreakEvent != none && KFGi.OutbreakEvent.ActiveEvent.bBossRushMode)
|
|
{
|
|
ShieldHealth = ShieldHealth * ArmorInfo.ArmorScale;
|
|
}
|
|
|
|
|
|
ShieldHealthMax = ShieldHealth;
|
|
ShieldHealthPctByte = FloatToByte( fClamp(ShieldHealth / ShieldHealthMax, 0.f, 1.f) );
|
|
|
|
UpdateShield();
|
|
}
|
|
}
|
|
|
|
simulated function ActivateShieldFX()
|
|
{
|
|
if (InvulnerableShieldPSC == none)
|
|
{
|
|
InvulnerableShieldPSC = WorldInfo.MyEmitterPool.SpawnEmitterMeshAttachment(InvulnerableShieldFX, Mesh, ShieldSocketName, true);
|
|
InvulnerableShieldPSC.SetAbsolute(false, true, true);
|
|
}
|
|
}
|
|
|
|
simulated function UpdateShield()
|
|
{
|
|
local float ShieldHealthPct;
|
|
|
|
if (bShieldBroken)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ShieldHealthPct = ByteToFloat(ShieldHealthPctByte);
|
|
if (ShieldHealthPctByte == 0)
|
|
{
|
|
BreakShield();
|
|
}
|
|
|
|
if (WorldInfo.NetMode == NM_DedicatedServer)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (ShieldHealthPct > 0.f && LastShieldHealthPct <= 0.f)
|
|
{
|
|
ActivateShieldFX();
|
|
}
|
|
|
|
if (InvulnerableShieldPSC != none)
|
|
{
|
|
if (ShieldHealthPct >= 0.75f) // Green
|
|
{
|
|
if (LastShieldHealthPct < 0.75f)
|
|
{
|
|
InvulnerableShieldPSC.SetVectorParameter('Shield_Color', MakeVectorFromColor(ShieldColorGreen));
|
|
InvulnerableShieldPSC.SetVectorParameter('Shield_CoreColor', MakeVectorFromColor(ShieldCoreColorGreen));
|
|
}
|
|
}
|
|
else if (ShieldHealthPct >= 0.5f) // Yellow
|
|
{
|
|
if (LastShieldHealthPct >= 0.75f || LastShieldHealthPct < 0.5f)
|
|
{
|
|
InvulnerableShieldPSC.SetVectorParameter('Shield_Color', MakeVectorFromColor(ShieldColorYellow));
|
|
InvulnerableShieldPSC.SetVectorParameter('Shield_CoreColor', MakeVectorFromColor(ShieldCoreColorYellow));
|
|
}
|
|
}
|
|
else if (ShieldHealthPct >= 0.25f) // Orange
|
|
{
|
|
if (LastShieldHealthPct >= 0.5f || LastShieldHealthPct < 0.25f)
|
|
{
|
|
InvulnerableShieldPSC.SetVectorParameter('Shield_Color', MakeVectorFromColor(ShieldColorOrange));
|
|
InvulnerableShieldPSC.SetVectorParameter('Shield_CoreColor', MakeVectorFromColor(ShieldCoreColorOrange));
|
|
}
|
|
}
|
|
else if (LastShieldHealthPct >= 0.25f) // Red
|
|
{
|
|
InvulnerableShieldPSC.SetVectorParameter('Shield_Color', MakeVectorFromColor(ShieldColorRed));
|
|
InvulnerableShieldPSC.SetVectorParameter('Shield_CoreColor', MakeVectorFromColor(ShieldCoreColorRed));
|
|
}
|
|
}
|
|
|
|
//// Scale the invulnerable material param
|
|
//TorsoMIC.SetScalarParameterValue('Scalar_DamageResist', ShieldHealthPct);
|
|
|
|
// Cache off so we know whether the material params need to change
|
|
LastShieldHealthPct = ShieldHealthPct;
|
|
UpdateShieldUI();
|
|
}
|
|
|
|
/** Creates a vector parameter from a standard color */
|
|
simulated function vector MakeVectorFromColor(color InColor)
|
|
{
|
|
local LinearColor LinColor;
|
|
local vector ColorVec;
|
|
|
|
LinColor = ColorToLinearColor(InColor);
|
|
ColorVec.X = LinColor.R;
|
|
ColorVec.Y = LinColor.G;
|
|
ColorVec.Z = LinColor.B;
|
|
|
|
return ColorVec;
|
|
}
|
|
|
|
/** Breaks the shield */
|
|
simulated function BreakShield()
|
|
{
|
|
local KFExplosionActor ExplosionActor;
|
|
|
|
if (bShieldBroken)
|
|
{
|
|
return;
|
|
}
|
|
|
|
bShieldBroken = true;
|
|
bShieldUp = false;
|
|
|
|
// Spawn a shatter explosion
|
|
// Spawn on server (to actually do damage) and client (to actually produce visuals)
|
|
// (why doesn't the actor replicate its explosion?)
|
|
ExplosionActor = Spawn(class'KFExplosionActor', self, , Location, rotator(vect(0, 0, 1)));
|
|
if (ExplosionActor != None)
|
|
{
|
|
ExplosionActor.Explode(ShieldShatterExplosionTemplate);
|
|
}
|
|
|
|
if (WorldInfo.NetMode != NM_DedicatedServer)
|
|
{
|
|
// Detach shield and zero out material params
|
|
DetachShieldFX();
|
|
//TorsoMIC.SetScalarParameterValue('Scalar_DamageResist', 0.0);
|
|
}
|
|
|
|
if (Role == ROLE_Authority)
|
|
{
|
|
SetBattlePhase(BATTLE_PHASE_ARMOR);
|
|
}
|
|
}
|
|
|
|
simulated function DetachShieldFX()
|
|
{
|
|
LastShieldHealthPct = 0.f;
|
|
DetachEmitter(InvulnerableShieldPSC);
|
|
UpdateShieldUI();
|
|
}
|
|
|
|
simulated function UpdateShieldUI()
|
|
{
|
|
if (KFPC != none && KFPC.IsLocalController())
|
|
{
|
|
if (KFPC.MyGFxHUD != none && KFPC.MyGFxHUD.bossHealthBar != none)
|
|
{
|
|
KFPC.MyGFxHUD.bossHealthBar.UpdateBossShield(LastShieldHealthPct);
|
|
}
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
// @name Gun tracking
|
|
//=============================================================================
|
|
|
|
/** Toggles gun tracking on and off */
|
|
simulated function SetGunTracking(bool bEnableTracking)
|
|
{
|
|
if (WorldInfo.NetMode != NM_DedicatedServer || bUseServerSideGunTracking)
|
|
{
|
|
bGunTracking = bEnableTracking;
|
|
GunTrackingSkelCtrl.SetSkelControlActive( bEnableTracking );
|
|
}
|
|
|
|
if (Role == ROLE_Authority)
|
|
{
|
|
if (bEnableTracking && Controller != None && Controller.Enemy != none)
|
|
{
|
|
GunTarget = Controller.Enemy;
|
|
}
|
|
else
|
|
{
|
|
GunTarget = none;
|
|
}
|
|
}
|
|
|
|
bForceNetUpdate = true;
|
|
}
|
|
|
|
/** Updates our gun tracking skeletal control */
|
|
simulated function UpdateGunTrackingSkelCtrl(float DeltaTime)
|
|
{
|
|
// Track the player with the gun arm
|
|
if (GunTrackingSkelCtrl != none)
|
|
{
|
|
if (bGunTracking && GunTarget != None)
|
|
{
|
|
GunTrackingSkelCtrl.DesiredTargetLocation = GunTarget.Mesh.GetBoneLocation(GunTargetBoneName);
|
|
GunTrackingSkelCtrl.InterpolateTargetLocation(DeltaTime);
|
|
}
|
|
else
|
|
{
|
|
GunTrackingSkelCtrl.SetSkelControlActive(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
// @name Phases
|
|
//=============================================================================
|
|
|
|
function bool CanUseSweepingClaw()
|
|
{
|
|
return BattlePhases[CurrentBattlePhase].bCanUseSweepingClaw &&
|
|
CanDoSpecialMove(SM_Custom1);
|
|
}
|
|
|
|
function bool CanUseTeslaBlast()
|
|
{
|
|
return BattlePhases[CurrentBattlePhase].bCanUseTeslaBlast &&
|
|
CanDoSpecialMove(SM_StandAndShootAttack) &&
|
|
PowerClawIsFunctional();
|
|
}
|
|
|
|
function bool CanUsePlasmaCannon()
|
|
{
|
|
return BattlePhases[CurrentBattlePhase].bCanUsePlasmaCannon &&
|
|
CanDoSpecialMove(SM_HoseWeaponAttack) &&
|
|
PowerClawIsFunctional();
|
|
}
|
|
|
|
function bool CanUseLightningStorm()
|
|
{
|
|
return BattlePhases[CurrentBattlePhase].bCanUseLightningStorm &&
|
|
CanDoSpecialMove(SM_Custom2);
|
|
}
|
|
|
|
function bool CanUseWarningSiren()
|
|
{
|
|
return BattlePhases[CurrentBattlePhase].bCanUseWarningSiren &&
|
|
CanDoSpecialMove(SM_SonicAttack);
|
|
}
|
|
|
|
function bool CanUseScorpionWhip()
|
|
{
|
|
return !PowerClawIsFunctional() &&
|
|
CanDoSpecialMove(SM_GrappleAttack);
|
|
}
|
|
|
|
function SetBattlePhase(int Phase)
|
|
{
|
|
if (Phase > CurrentBattlePhase && Phase < BattlePhases.Length)
|
|
{
|
|
CurrentBattlePhase = Phase;
|
|
|
|
if (CurrentBattlePhase > BATTLE_PHASE_SHIELD)
|
|
{
|
|
ShieldHealthPctByte = 0;
|
|
UpdateShield();
|
|
}
|
|
|
|
if (CurrentBattlePhase > BATTLE_PHASE_ARMOR)
|
|
{
|
|
ArmorInfo.ExplodeArmor(HEAD_ARMOR_IDX);
|
|
ArmorInfo.ExplodeArmor(CLAW_ARMOR_IDX);
|
|
ArmorInfo.UpdateArmorUI();
|
|
|
|
// Forcing armor to be updated.
|
|
OnArmorZoneStatusUpdated();
|
|
}
|
|
|
|
DoStumble();
|
|
SummonMinions();
|
|
InitializeCurrentBattlePhase();
|
|
OnBattlePhaseChanged();
|
|
bForceNetUpdate = true;
|
|
}
|
|
}
|
|
|
|
function IncrementBattlePhase()
|
|
{
|
|
SetBattlePhase(CurrentBattlePhase + 1);
|
|
}
|
|
|
|
function InitializeCurrentBattlePhase()
|
|
{
|
|
local int i;
|
|
|
|
TentacleDamage = BattlePhases[CurrentBattlePhase].TentacleDamage;
|
|
MeleeAttackHelper.BaseDamage = MeleeAttackHelper.default.BaseDamage * BattlePhases[CurrentBattlePhase].MeleeDamageScale;
|
|
InitialGroundSpeedModifier = BattlePhases[CurrentBattlePhase].GroundSpeedScale;
|
|
bCanCloak = BattlePhases[CurrentBattlePhase].bCanCloak;
|
|
bUseAltSprintAnim = BattlePhases[CurrentBattlePhase].bUseAltSprintAnim;
|
|
bShouldTaunt = BattlePhases[CurrentBattlePhase].bShouldTaunt;
|
|
IncapSettings = BattlePhases[CurrentBattlePhase].IncapSettings;
|
|
|
|
// re-init existing afflictions to account for new IncapSettings
|
|
for (i = 0; i < EAfflictionType_MAX; ++i)
|
|
{
|
|
if (i < AfflictionHandler.Afflictions.Length && AfflictionHandler.Afflictions[i] != none)
|
|
{
|
|
AfflictionHandler.Afflictions[i].Init(self, EAfflictionType(i), none);
|
|
}
|
|
}
|
|
|
|
if (bCanCloak)
|
|
{
|
|
SetCloaked(true);
|
|
}
|
|
|
|
`DialogManager.PlayMatriarchBattlePhaseDialog(self, CurrentBattlePhase);
|
|
|
|
bNetDirty = true;
|
|
}
|
|
|
|
function SummonMinions()
|
|
{
|
|
local KFAIWaveInfo MinionWave;
|
|
local KFGameInfo MyKFGameInfo;
|
|
local KFAIController_ZedBoss MyBossAIController;
|
|
|
|
MyKFGameInfo = KFGameInfo(WorldInfo.Game);
|
|
|
|
// Force frustration mode on
|
|
MyKFGameInfo.GetAIDirector().bForceFrustration = true;
|
|
|
|
// Select the correct batch of zeds to spawn during this battle phase
|
|
MinionWave = GetWaveInfo(CurrentBattlePhase, MyKFGameInfo.GetModifiedGameDifficulty());
|
|
if (MinionWave != none)
|
|
{
|
|
if (MyKFGameInfo.SpawnManager != none)
|
|
{
|
|
MyKFGameInfo.SpawnManager.LeftoverSpawnSquad.Length = 0;
|
|
MyKFGameInfo.SpawnManager.SummonBossMinions(MinionWave.Squads, GetNumMinionsToSpawn());
|
|
}
|
|
}
|
|
|
|
MyBossAIController = KFAIController_ZedBoss(Controller);
|
|
if (MyBossAIController != none)
|
|
{
|
|
MyBossAIController.SetTimer(MinionSpawnDuration, false, nameof(MyBossAIController.Timer_StopSummoningZeds));
|
|
}
|
|
}
|
|
|
|
/** Sets various material scalars and FX based on the phase of battle */
|
|
simulated function OnBattlePhaseChanged()
|
|
{
|
|
if (WorldInfo.NetMode == NM_DedicatedServer || Health <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
super.OnBattlePhaseChanged();
|
|
|
|
UpdateBattlePhaseLights();
|
|
UpdateBattlePhaseMaterials();
|
|
UpdateBattlePhaseParticles();
|
|
}
|
|
|
|
/** Updates dynamic lights based on battle phase */
|
|
simulated function UpdateBattlePhaseLights()
|
|
{
|
|
local PointLightComponent LightTemplate;
|
|
|
|
if (BattlePhaseLightFront != none)
|
|
{
|
|
BattlePhaseLightFront.DetachFromAny();
|
|
BattlePhaseLightFront = none;
|
|
}
|
|
|
|
if (BattlePhaseLightBack != none)
|
|
{
|
|
BattlePhaseLightBack.DetachFromAny();
|
|
BattlePhaseLightBack = none;
|
|
}
|
|
|
|
switch (CurrentBattlePhase)
|
|
{
|
|
case 0:
|
|
LightTemplate = LightTemplate_Phase1;
|
|
break;
|
|
|
|
case 1:
|
|
LightTemplate = LightTemplate_Phase2;
|
|
break;
|
|
|
|
case 2:
|
|
LightTemplate = LightTemplate_Phase3;
|
|
break;
|
|
|
|
case 3:
|
|
// don't activate lights after death
|
|
if (IsAliveAndWell())
|
|
{
|
|
LightTemplate = LightTemplate_Phase4;
|
|
}
|
|
break;
|
|
};
|
|
|
|
if (LightTemplate != none)
|
|
{
|
|
BattlePhaseLightFront = new(self) Class'PointLightComponent' (LightTemplate);
|
|
BattlePhaseLightBack = new(self) Class'PointLightComponent' (LightTemplate);
|
|
}
|
|
|
|
if (BattlePhaseLightFront != none)
|
|
{
|
|
Mesh.AttachComponentToSocket(BattlePhaseLightFront, LightSocketFront);
|
|
BattlePhaseLightFront.SetEnabled(true);
|
|
}
|
|
|
|
if (BattlePhaseLightBack != none)
|
|
{
|
|
Mesh.AttachComponentToSocket(BattlePhaseLightBack, LightSocketBack);
|
|
BattlePhaseLightBack.SetEnabled(true);
|
|
}
|
|
}
|
|
|
|
/** Updates battle damage on material instance based on battle phase */
|
|
simulated function UpdateBattlePhaseMaterials()
|
|
{
|
|
local MaterialInstanceConstant MIC;
|
|
|
|
foreach CharacterMICs(MIC)
|
|
{
|
|
switch (CurrentBattlePhase)
|
|
{
|
|
case 1:
|
|
MIC.SetScalarParameterValue('Scalar_BattleGrime', 0.0);
|
|
MIC.SetScalarParameterValue('Scalar_Damage_Blood_Contrast', 1.0);
|
|
MIC.SetScalarParameterValue('Scalar_GlowFlashing', 0.0);
|
|
MIC.SetVectorParameterValue('Vector_GlowColor', GlowColor_Phase1);
|
|
break;
|
|
|
|
case 2:
|
|
MIC.SetScalarParameterValue('Scalar_BattleGrime', 0.25);
|
|
MIC.SetScalarParameterValue('Scalar_Damage_Blood_Contrast', 1.48);
|
|
MIC.SetScalarParameterValue('Scalar_GlowFlashing', 0.0);
|
|
MIC.SetVectorParameterValue('Vector_GlowColor', GlowColor_Phase2);
|
|
break;
|
|
|
|
case 3:
|
|
MIC.SetScalarParameterValue('Scalar_BattleGrime', 0.25);
|
|
MIC.SetScalarParameterValue('Scalar_Damage_Blood_Contrast', 1.49);
|
|
MIC.SetScalarParameterValue('Scalar_GlowFlashing', 0.0);
|
|
MIC.SetVectorParameterValue('Vector_GlowColor', GlowColor_Phase3);
|
|
break;
|
|
|
|
case 4:
|
|
MIC.SetScalarParameterValue('Scalar_BattleGrime', 0.5);
|
|
MIC.SetScalarParameterValue('Scalar_Damage_Blood_Contrast', 1.6);
|
|
// don't activate blinking after death
|
|
MIC.SetScalarParameterValue('Scalar_GlowFlashing', IsAliveAndWell() ? 1.0 : 0.0);
|
|
MIC.SetVectorParameterValue('Vector_GlowColor', GlowColor_Phase4);
|
|
break;
|
|
};
|
|
}
|
|
}
|
|
|
|
simulated function UpdateBattlePhaseParticles()
|
|
{
|
|
local int i, j;
|
|
local ParticleSystem PS;
|
|
local name Socket;
|
|
local ParticleSystemComponent PSC;
|
|
|
|
if (CurrentBattlePhase > 0)
|
|
{
|
|
for (i = 0; i < BattlePhases[CurrentBattlePhase-1].DamageFX.FXComponents.Length; ++i)
|
|
{
|
|
BattlePhases[CurrentBattlePhase-1].DamageFX.FXComponents[i].DeactivateSystem();
|
|
}
|
|
BattlePhases[CurrentBattlePhase-1].DamageFX.FXComponents.Length = 0;
|
|
}
|
|
|
|
for (i = 0; i < BattlePhases[CurrentBattlePhase].DamageFX.FXInfo.Length; ++i)
|
|
{
|
|
PS = BattlePhases[CurrentBattlePhase].DamageFX.FXInfo[i].Template;
|
|
for (j = 0; j < BattlePhases[CurrentBattlePhase].DamageFX.FXInfo[i].Sockets.Length; ++j)
|
|
{
|
|
Socket = BattlePhases[CurrentBattlePhase].DamageFX.FXInfo[i].Sockets[j];
|
|
PSC = WorldInfo.MyEmitterPool.SpawnEmitterMeshAttachment(PS, Mesh, Socket, true);
|
|
BattlePhases[CurrentBattlePhase].DamageFX.FXComponents.AddItem(PSC);
|
|
}
|
|
}
|
|
}
|
|
|
|
simulated function DoStumble()
|
|
{
|
|
if (IsIncapacitated())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (IsDoingSpecialMove())
|
|
{
|
|
EndSpecialMove();
|
|
}
|
|
|
|
DoSpecialMove( SM_Stumble,,, class'KFSM_Stumble'.static.PackBodyHitSMFlags(self, -vector(Rotation)) );
|
|
}
|
|
|
|
//=============================================================================
|
|
// Cloaking
|
|
//=============================================================================
|
|
|
|
/** Toggle cloaking material */
|
|
function SetCloaked(bool bNewCloaking)
|
|
{
|
|
if( bCanCloak && bNewCloaking != bIsCloaking )
|
|
{
|
|
if( bNewCloaking && (IsImpaired() || IsIncapacitated()) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( MaxHeadChunkGoreWhileAlive == 0 && bIsCloaking != bNewCloaking && IsAliveAndWell() )
|
|
{
|
|
`DialogManager.PlaySpotCloakDialog( self, bNewCloaking );
|
|
}
|
|
|
|
bIsCloaking = bNewCloaking;
|
|
|
|
// Initial spotted callout should be slightly delayed
|
|
if( bIsCloaking )
|
|
{
|
|
bIsCloakingSpottedByLP = false;
|
|
bIsCloakingSpottedByTeam = false;
|
|
LastSpottedStatusUpdate = WorldInfo.TimeSeconds - 0.2f;
|
|
}
|
|
|
|
if( WorldInfo.NetMode != NM_DedicatedServer )
|
|
{
|
|
UpdateGameplayMICParams();
|
|
HideBattleDamageFX(bIsCloaking);
|
|
}
|
|
|
|
super.SetCloaked( bNewCloaking );
|
|
|
|
if (Role == ROLE_Authority && bIsCloaking)
|
|
{
|
|
`DialogManager.PlayMatriarchCloakedEvent(self);
|
|
}
|
|
}
|
|
}
|
|
|
|
simulated function HideBattleDamageFX(bool bHide)
|
|
{
|
|
local int i;
|
|
|
|
for (i = 0; i < BattlePhases[CurrentBattlePhase].DamageFX.FXComponents.Length; ++i)
|
|
{
|
|
BattlePhases[CurrentBattlePhase].DamageFX.FXComponents[i].SetHidden(bHide);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* bIsCloaking replicated state changed
|
|
* Network: Local and Remote Clients
|
|
*/
|
|
simulated function ClientCloakingStateUpdated()
|
|
{
|
|
if( bIsCloaking )
|
|
{
|
|
ClearBloodDecals();
|
|
|
|
// Initial spotted callout should be slightly delayed
|
|
bIsCloakingSpottedByLP = false;
|
|
bIsCloakingSpottedByTeam = false;
|
|
LastSpottedStatusUpdate = WorldInfo.TimeSeconds - 0.2f;
|
|
}
|
|
|
|
UpdateGameplayMICParams();
|
|
HideBattleDamageFX(bIsCloaking);
|
|
}
|
|
|
|
/**
|
|
* Called every 0.5f seconds to check if a cloaked zed has been spotted
|
|
* Network: All but dedicated server
|
|
*/
|
|
simulated event UpdateSpottedStatus()
|
|
{
|
|
local bool bOldSpottedByLP;
|
|
local KFPlayerController LocalPC;
|
|
local KFPerk LocalPerk;
|
|
local float DistanceSq, Range;
|
|
|
|
if( WorldInfo.NetMode == NM_DedicatedServer )
|
|
{
|
|
return;
|
|
}
|
|
|
|
bOldSpottedByLP = bIsCloakingSpottedByLP;
|
|
bIsCloakingSpottedByLP = false;
|
|
|
|
LocalPC = KFPlayerController(GetALocalPlayerController());
|
|
if( LocalPC != none )
|
|
{
|
|
LocalPerk = LocalPC.GetPerk();
|
|
}
|
|
|
|
if ( LocalPC != none && LocalPC.Pawn != None && LocalPC.Pawn.IsAliveAndWell() && LocalPerk != none &&
|
|
LocalPerk.bCanSeeCloakedZeds && `TimeSince( LastRenderTime ) < 1.f )
|
|
{
|
|
DistanceSq = VSizeSq(LocalPC.Pawn.Location - Location);
|
|
Range = LocalPerk.GetCloakDetectionRange();
|
|
|
|
if ( DistanceSq < Square(Range) )
|
|
{
|
|
bIsCloakingSpottedByLP = true;
|
|
if ( LocalPerk.IsCallOutActive() )
|
|
{
|
|
// Beware of server spam. This RPC is marked unreliable and UpdateSpottedStatus has it's own cooldown timer
|
|
LocalPC.ServerCallOutPawnCloaking(self);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If spotted by team already, there is no point in trying to update the MIC here
|
|
if ( !bIsCloakingSpottedByTeam )
|
|
{
|
|
if ( bIsCloakingSpottedByLP != bOldSpottedByLP )
|
|
{
|
|
UpdateGameplayMICParams();
|
|
}
|
|
}
|
|
}
|
|
|
|
/** notification from player with CallOut ability */
|
|
function CallOutCloaking( optional KFPlayerController CallOutController )
|
|
{
|
|
bIsCloakingSpottedByTeam = true;
|
|
UpdateGameplayMICParams();
|
|
SetTimer(2.f, false, nameof(CallOutCloakingExpired));
|
|
}
|
|
|
|
/** Call-out cloaking ability has timed out */
|
|
function CallOutCloakingExpired()
|
|
{
|
|
bIsCloakingSpottedByTeam = false;
|
|
UpdateGameplayMICParams();
|
|
}
|
|
|
|
/** Handle cloaking materials */
|
|
simulated function UpdateGameplayMICParams()
|
|
{
|
|
local int i;
|
|
local bool bIsSpotted;
|
|
local bool bWasCloaked;
|
|
local KFCharacterInfo_Monster MonsterInfo;
|
|
|
|
// skip KFPawn_MonsterBoss because it calls OnBattlePhaseChanged (?)
|
|
super(KFPawn_Monster).UpdateGameplayMICParams();
|
|
|
|
// Cannot cloak after patriarch has been gored
|
|
if (WorldInfo.NetMode != NM_DedicatedServer)
|
|
{
|
|
MonsterInfo = GetCharacterMonsterInfo();
|
|
|
|
// visible by local player or team (must go after ServerCallOutCloaking)
|
|
bIsSpotted = (bIsCloakingSpottedByLP || bIsCloakingSpottedByTeam);
|
|
if ((!bIsCloaking || IsImpaired()) && CharacterMICs[0].Parent != MonsterInfo.Skins[0])
|
|
{
|
|
for (i = 0; i < MonsterInfo.Skins.Length; ++i)
|
|
{
|
|
bWasCloaked = bWasCloaked ||
|
|
(CharacterMICs[i].Parent == MonsterInfo.CloakedSkins[i]) ||
|
|
(CharacterMICs[i].Parent == MonsterInfo.SpottedSkins[i]);
|
|
CharacterMICs[i].SetParent(MonsterInfo.Skins[i]);
|
|
}
|
|
|
|
Mesh.CastShadow = true;
|
|
Mesh.SetPerObjectShadows(true);
|
|
|
|
// Needed to avoid effects occurring on gore mesh swap
|
|
if (bWasCloaked)
|
|
{
|
|
//SetDamageFXActive( true );
|
|
PlayStealthSoundLoopEnd();
|
|
DoCloakFX();
|
|
}
|
|
|
|
//Update PAC meshes
|
|
for (i = 0; i < `MAX_COSMETIC_ATTACHMENTS; ++i)
|
|
{
|
|
if (ThirdPersonAttachments[i] != none)
|
|
{
|
|
ThirdPersonAttachments[i].SetHidden(false);
|
|
}
|
|
}
|
|
}
|
|
else if (bIsCloaking && bIsSpotted && CharacterMICs[0].Parent != MonsterInfo.SpottedSkins[0])
|
|
{
|
|
for (i = 0; i < MonsterInfo.SpottedSkins.Length; ++i)
|
|
{
|
|
CharacterMICs[i].SetParent(MonsterInfo.SpottedSkins[i]);
|
|
}
|
|
|
|
CloakPercent = 1.0f;
|
|
|
|
Mesh.CastShadow = false;
|
|
Mesh.SetPerObjectShadows(false);
|
|
//SetDamageFXActive( false );
|
|
|
|
//Update PAC meshes
|
|
for (i = 0; i < `MAX_COSMETIC_ATTACHMENTS; ++i)
|
|
{
|
|
if (ThirdPersonAttachments[i] != none)
|
|
{
|
|
ThirdPersonAttachments[i].SetHidden(true);
|
|
}
|
|
}
|
|
}
|
|
else if (bIsCloaking && !bIsSpotted && CharacterMICs[0].Parent != MonsterInfo.CloakedSkins[0])
|
|
{
|
|
for (i = 0; i < MonsterInfo.CloakedSkins.Length; ++i)
|
|
{
|
|
CharacterMICs[i].SetParent(MonsterInfo.CloakedSkins[i]);
|
|
}
|
|
|
|
PlayStealthSoundLoop();
|
|
DoCloakFX();
|
|
Mesh.CastShadow = false;
|
|
Mesh.SetPerObjectShadows(false);
|
|
//SetDamageFXActive( false );
|
|
|
|
//Update PAC meshes
|
|
for (i = 0; i < `MAX_COSMETIC_ATTACHMENTS; ++i)
|
|
{
|
|
if (ThirdPersonAttachments[i] != none)
|
|
{
|
|
ThirdPersonAttachments[i].SetHidden(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
simulated function DoCloakFX()
|
|
{
|
|
local ParticleSystemComponent CloakPSC;
|
|
|
|
CloakPSC = WorldInfo.MyEmitterPool.SpawnEmitterMeshAttachment( CloakFX, Mesh, CloakFXSocketName, true );
|
|
CloakPSC.SetAbsolute( false, true, false );
|
|
}
|
|
|
|
simulated function PlayStealthSoundLoop()
|
|
{
|
|
if( WorldInfo.NetMode != NM_DedicatedServer && !CloakedAkComponent.IsPlaying(CloakedLoop) )
|
|
{
|
|
CloakedAkComponent.PlayEvent( CloakedLoop, true, true );
|
|
}
|
|
}
|
|
|
|
simulated function PlayStealthSoundLoopEnd()
|
|
{
|
|
if( WorldInfo.NetMode != NM_DedicatedServer && CloakedAkComponent.IsPlaying(CloakedLoop) )
|
|
{
|
|
CloakedAkComponent.PlayEvent( CloakedLoopEnd, true, true );
|
|
}
|
|
}
|
|
|
|
simulated function PlayDying(class<DamageType> DamageType, vector HitLoc)
|
|
{
|
|
// Uncloak on death
|
|
SetCloaked(false);
|
|
bCanCloak = false;
|
|
|
|
Super.PlayDying(DamageType, HitLoc);
|
|
}
|
|
|
|
/*********************************************************************************************
|
|
* Dialog / Audio
|
|
**********************************************************************************************/
|
|
/** Returns (hardcoded) dialog event ID for when players kills this zed type */
|
|
function int GetKillerDialogID()
|
|
{
|
|
return 67;//KILL_Boss
|
|
}
|
|
|
|
/** Returns (hardcoded) dialog event ID for when players spots this zed type */
|
|
function int GetSpotterDialogID()
|
|
{
|
|
if( bIsCloaking && MaxHeadChunkGoreWhileAlive == 0 )
|
|
{
|
|
return 135;//SPOTZ_Cloaked
|
|
}
|
|
|
|
return 125;//SPOTZ_Generic
|
|
}
|
|
|
|
/** Players dialog such as taunts at regular intervals */
|
|
function Timer_TickDialog()
|
|
{
|
|
if (!IsAliveAndWell())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!IsDoingSpecialMove())
|
|
{
|
|
`DialogManager.PlayMatriarchTickDialog(self, ArmorZoneStatus, CurrentBattlePhase);
|
|
}
|
|
|
|
SetTimer(TickDialogInterval, false, nameOf(Timer_TickDialog));
|
|
}
|
|
|
|
function PlayPlasmaCannonDialog()
|
|
{
|
|
`DialogManager.PlayMatriarchPlasmaCannonEvent(self);
|
|
}
|
|
|
|
function PlaySweepingClawDialog()
|
|
{
|
|
`DialogManager.PlayMatriarchSweepingClawEvent(self);
|
|
}
|
|
|
|
function PlayTeslaBlastDialog()
|
|
{
|
|
`DialogManager.PlayMatriarchTeslaBlastEvent(self);
|
|
}
|
|
|
|
function PlayLightningStormDialog()
|
|
{
|
|
`DialogManager.PlayMatriarchLightningStormEvent(self);
|
|
}
|
|
|
|
function PlayScorpionWhipDialog()
|
|
{
|
|
`DialogManager.PlayMatriarchScorpionWhipEvent(self);
|
|
}
|
|
|
|
function PlayWarningSirenDialog()
|
|
{
|
|
`DialogManager.PlayMatriarchWarningSirenEvent(self);
|
|
}
|
|
|
|
/*********************************************************************************************
|
|
* @name Armor
|
|
**********************************************************************************************/
|
|
|
|
function ZedExplodeArmor(int ArmorZoneIdx, name ArmorZoneName)
|
|
{
|
|
super.ZedExplodeArmor(ArmorZoneIdx, ArmorZoneName);
|
|
OnArmorZoneStatusUpdated();
|
|
`DialogManager.PlayMatriarchExplodeArmorDialog(self, ArmorZoneName);
|
|
|
|
if (Role == ROLE_Authority)
|
|
{
|
|
if (ArmorZoneStatus == 0)
|
|
{
|
|
SetBattlePhase(BATTLE_PHASE_FLESH);
|
|
}
|
|
else
|
|
{
|
|
DoStumble();
|
|
}
|
|
}
|
|
}
|
|
|
|
function bool PowerClawIsFunctional()
|
|
{
|
|
return bool(ArmorZoneStatus & (1 << CLAW_ARMOR_IDX));
|
|
}
|
|
|
|
simulated function OnArmorZoneStatusUpdated()
|
|
{
|
|
local int Idx;
|
|
|
|
if ((ArmorZoneStatus & (1 << HEAD_ARMOR_IDX)) == 0)
|
|
{
|
|
Idx = HitZones.Find('BoneName', 'dome');
|
|
if (Idx != INDEX_NONE)
|
|
{
|
|
HitZones.Remove(Idx, 1);
|
|
}
|
|
}
|
|
|
|
if ((ArmorZoneStatus & (1 << CLAW_ARMOR_IDX)) == 0)
|
|
{
|
|
Idx = HitZones.Find('BoneName', 'LeftHandCap');
|
|
if (Idx != INDEX_NONE)
|
|
{
|
|
HitZones.Remove(Idx, 1);
|
|
}
|
|
}
|
|
|
|
DialogAkComponent.SetRTPCValue("Matriarch_Helmet", int(bool(ArmorZoneStatus & (1 << HEAD_ARMOR_IDX))));
|
|
}
|
|
|
|
/*********************************************************************************************
|
|
* @name Gore
|
|
**********************************************************************************************/
|
|
|
|
simulated function ApplyHeadChunkGore(class<KFDamageType> DmgType, vector HitLocation, vector HitDirection)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*********************************************************************************************
|
|
* @name KFSkinTypeEffects
|
|
**********************************************************************************************/
|
|
|
|
function int GetHitZoneIndex(name BoneName)
|
|
{
|
|
if (BoneName == 'KBArmor')
|
|
{
|
|
//Known arbitrary, hacking some things in place
|
|
return OverrideArmorFXIndex;
|
|
}
|
|
|
|
return super.GetHitZoneIndex(BoneName);
|
|
}
|
|
|
|
/** Gets skin effects associated with hit zone (allows pawns to override) */
|
|
simulated function KFSkinTypeEffects GetHitZoneSkinTypeEffects( int HitZoneIdx )
|
|
{
|
|
if (bShieldUp)
|
|
{
|
|
return ShieldImpactEffects; // InvulnerabilityShield
|
|
}
|
|
else if (bIsCloaking)
|
|
{
|
|
return CharacterArch.ImpactSkins[4]; // 4 = Patriarch_Cloaked
|
|
}
|
|
else if (HitZoneIdx == OverrideArmorFXIndex)
|
|
{
|
|
return CharacterArch.ImpactSkins[5];
|
|
}
|
|
else
|
|
{
|
|
return super.GetHitZoneSkinTypeEffects( HitZoneIdx );
|
|
}
|
|
}
|
|
|
|
/*********************************************************************************************
|
|
* @name Movement
|
|
**********************************************************************************************/
|
|
|
|
function AdjustMovementSpeed( float SpeedAdjust )
|
|
{
|
|
DesiredAdjustedGroundSpeed = default.GroundSpeed * SpeedAdjust * BattlePhases[CurrentBattlePhase].GroundSpeedScale;
|
|
|
|
DesiredAdjustedSprintSpeed = default.SprintSpeed * SpeedAdjust * BattlePhases[CurrentBattlePhase].SprintSpeedScale;
|
|
DesiredAdjustedSprintSpeed *= (IsDoingSpecialMove() ? SpecialMoves[SpecialMove].GetSprintSpeedModifier() : 1.f);
|
|
DesiredAdjustedSprintSpeed = fMax(DesiredAdjustedSprintSpeed, DesiredAdjustedGroundSpeed);
|
|
|
|
if (bPlayPanicked)
|
|
{
|
|
// Make sure groundspeed is in "walk" range so animtree can play correct panic anim
|
|
DesiredAdjustedGroundSpeed = Min(DesiredAdjustedGroundSpeed, MovementAnimNode.Constraints[1]);
|
|
}
|
|
|
|
NormalGroundSpeed = DesiredAdjustedGroundSpeed;
|
|
NormalSprintSpeed = DesiredAdjustedSprintSpeed;
|
|
}
|
|
|
|
//=============================================================================
|
|
// @name Bump
|
|
//=============================================================================
|
|
|
|
function class<KFDamageType> GetBumpAttackDamageType()
|
|
{
|
|
return HeavyBumpDamageType;
|
|
}
|
|
|
|
/** Play music for this boss (overridden for each boss) */
|
|
function PlayBossMusic()
|
|
{
|
|
if( KFGameInfo(WorldInfo.Game) != none )
|
|
{
|
|
KFGameInfo(WorldInfo.Game).ForceMatriarchMusicTrack();
|
|
}
|
|
}
|
|
|
|
defaultproperties
|
|
{
|
|
// Stats
|
|
XPValues(0)=1291
|
|
XPValues(1)=1694
|
|
XPValues(2)=1790
|
|
XPValues(3)=1843
|
|
|
|
// ---------------------------------------------
|
|
//Movement / Physics
|
|
Begin Object Name=CollisionCylinder
|
|
CollisionRadius=+0055.000000
|
|
End Object
|
|
|
|
RotationRate=(Pitch=50000,Yaw=50000,Roll=50000)
|
|
|
|
GroundSpeed=300.f
|
|
SprintSpeed=650.f
|
|
|
|
KnockdownImpulseScale=1.0f
|
|
|
|
|
|
// ---------------------------------------------
|
|
// Content
|
|
LocalizationKey=KFPawn_ZedMatriarch
|
|
MonsterArchPath = "ZED_ARCH.ZED_Matriarch_Archetype"
|
|
PawnAnimInfo=KFPawnAnimInfo'ZED_Matriarch_ANIM.Matriarch_AnimGroup'
|
|
|
|
Begin Object Name=KFPawnSkeletalMeshComponent
|
|
// Enabling kinematic for physics interaction while alive. (see also MinDistFactorForKinematicUpdate)
|
|
bUpdateKinematicBonesFromAnimation = true
|
|
|
|
// Enabling skel controls when not rendered (for guntracking on server)
|
|
bIgnoreControllersWhenNotRendered=false
|
|
|
|
// Beam weapons (microwave gun, flamey things, etc.) won't hit her hand armor without this
|
|
BlockNonZeroExtent=true
|
|
End Object
|
|
|
|
DefaultInventory(0) = class'KFWeap_PowerClaw_Matriarch'
|
|
|
|
// ---------------------------------------------
|
|
//Gameplay
|
|
Health=7000
|
|
Mass=200.f
|
|
DoshValue=500
|
|
ParryResistance=4
|
|
|
|
TentacleDamageType=class'KFDT_Slashing_MatriarchTentacle'
|
|
DifficultySettings=class'KFDifficulty_Matriarch'
|
|
|
|
Begin Object Name=MeleeHelper_0
|
|
BaseDamage=55.f
|
|
MaxHitRange=375.f
|
|
MomentumTransfer=40000.f
|
|
MyDamageType=class'KFDT_Bludgeon_Matriarch'
|
|
End Object
|
|
|
|
PenetrationResistance=4.0
|
|
|
|
TickDialogInterval=0.5
|
|
|
|
CloakPercent=1.0f
|
|
DeCloakSpeed=4.5f
|
|
CloakSpeed=3.f
|
|
CloakShimmerAmount=0.6f
|
|
|
|
bEnableAimOffset=true
|
|
|
|
// ---------------------------------------------
|
|
// Special Moves
|
|
Begin Object Name=SpecialMoveHandler_0
|
|
SpecialMoveClasses(SM_Custom1)=class'KFSM_Matriarch_SweepingClaw'
|
|
SpecialMoveClasses(SM_StandAndShootAttack)=class'KFSM_Matriarch_TeslaBlast'
|
|
SpecialMoveClasses(SM_HoseWeaponAttack)=class'KFSM_Matriarch_PlasmaCannon'
|
|
SpecialMoveClasses(SM_Custom2)=class'KFSM_Matriarch_LightningStorm'
|
|
SpecialMoveClasses(SM_GrappleAttack)=class'KFSM_Matriarch_ScorpionWhip'
|
|
SpecialMoveClasses(SM_SonicAttack)=class'KFSM_Matriarch_WarningSiren'
|
|
SpecialMoveClasses(SM_Taunt)=class'KFSM_Matriarch_Taunt'
|
|
End Object
|
|
|
|
// ---------------------------------------------
|
|
// AI / Nav
|
|
ControllerClass = class'KFGameContent.KFAIController_ZedMatriarch'
|
|
BumpDamageType=class'KFDT_NPCBump_Large'
|
|
DamageRecoveryTimeHeavy=0.65f
|
|
DamageRecoveryTimeMedium=0.85f
|
|
|
|
// ---------------------------------------------
|
|
// Battle Phases
|
|
|
|
BattlePhases(0)={(
|
|
NextPhaseHealthPctThreshold=0.75f,
|
|
bCanUseSweepingClaw=true, //Deprecated, Sweeping Claw is not a special move anymore.
|
|
bCanUseTeslaBlast=true,
|
|
bCanUsePlasmaCannon=true,
|
|
bCanUseLightningStorm=true,
|
|
bCanUseWarningSiren=false,
|
|
MeleeDamageScale=1.f,
|
|
GroundSpeedScale=1.f,
|
|
SprintSpeedScale=1.f,
|
|
bCanCloak=false,
|
|
bUseAltSprintAnim=false,
|
|
IncapSettings={(
|
|
// for reference: Vulnerability=(default, head, legs, arms, special)
|
|
/*AF_EMP*/ (Vulnerability=(1.0), Cooldown=10.0, Duration=2.5),
|
|
/*AF_FirePanic*/(Vulnerability=(0.0), Cooldown=15.0, Duration=1.2),
|
|
/*AF_MeleeHit*/ (Vulnerability=(0.0), Cooldown=2.0),
|
|
/*AF_GunHit*/ (Vulnerability=(0.0), Cooldown=2.0),
|
|
/*AF_Stumble*/ (Vulnerability=(0.0), Cooldown=10.0),
|
|
/*AF_Stun*/ (Vulnerability=(0.0), Cooldown=17.0, Duration=1.25),
|
|
/*AF_Poison*/ (Vulnerability=(0.0), Cooldown=15.0, Duration=1.2),
|
|
/*AF_Snare*/ (Vulnerability=(1.0, 2.0, 1.0, 1.0, 2.0), Cooldown=10.5, Duration=3.0),
|
|
/*AF_Knockdown*/(Vulnerability=(0.0), Cooldown=20.0),
|
|
/*AF_Freeze*/ (Vulnerability=(0.0), Cooldown=10.0, Duration=1.0),
|
|
/*AF_Microwave*/(Vulnerability=(0.08), Cooldown=10.0, Duration=3.0),
|
|
/*AF_Bleed*/ (Vulnerability=(0.15), Cooldown=10.0),
|
|
)}
|
|
)}
|
|
BattlePhases(1)={(
|
|
NextPhaseHealthPctThreshold=0.5f,
|
|
bCanUseSweepingClaw=true, //Deprecated, Sweeping Claw is not a special move anymore.
|
|
bCanUseTeslaBlast=true,
|
|
bCanUsePlasmaCannon=true,
|
|
bCanUseLightningStorm=true,
|
|
bCanUseWarningSiren=false,
|
|
MeleeDamageScale=1.f,
|
|
GroundSpeedScale=1.5f,
|
|
SprintSpeedScale=1.f,
|
|
bCanCloak=false,
|
|
bUseAltSprintAnim=false,
|
|
bShouldTaunt=true,
|
|
IncapSettings={(
|
|
// for reference: Vulnerability=(default, head, legs, arms, special)
|
|
/*AF_EMP*/ (Vulnerability=(1.0), Cooldown=10.0, Duration=2.5),
|
|
/*AF_FirePanic*/(Vulnerability=(0.0), Cooldown=15.0, Duration=1.2),
|
|
/*AF_MeleeHit*/ (Vulnerability=(0.1, 0.95, 0.1, 0.1, 0.75), Cooldown=2.0),
|
|
/*AF_GunHit*/ (Vulnerability=(0.1, 0.1, 0.1, 0.1, 0.5), Cooldown=2.0),
|
|
/*AF_Stumble*/ (Vulnerability=(0.1, 0.3, 0.1, 0.1, 0.4), Cooldown=10.0),
|
|
/*AF_Stun*/ (Vulnerability=(0.0), Cooldown=17.0, Duration=1.25),
|
|
/*AF_Poison*/ (Vulnerability=(0.0), Cooldown=15.0, Duration=1.2),
|
|
/*AF_Snare*/ (Vulnerability=(1.0, 2.0, 1.0, 1.0, 2.0), Cooldown=10.5, Duration=3.0),
|
|
/*AF_Knockdown*/(Vulnerability=(0.0), Cooldown=20.0),
|
|
/*AF_Freeze*/ (Vulnerability=(0.65), Cooldown=10.0, Duration=1.0),
|
|
/*AF_Microwave*/(Vulnerability=(0.08), Cooldown=10.0, Duration=3.0),
|
|
/*AF_Bleed*/ (Vulnerability=(0.15), Cooldown=10.0),
|
|
)},
|
|
DamageFX={(
|
|
FXInfo={(
|
|
{(
|
|
Template=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Low_Damage_01',
|
|
Sockets=(FX_LeftKnee,Hand_FX_Start_R,FX_RightHip)
|
|
)},
|
|
{(
|
|
Template=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Medium_Damage_01',
|
|
Sockets=(FX_LeftKnee)
|
|
)},
|
|
)}
|
|
)}
|
|
)}
|
|
BattlePhases(2)={(
|
|
NextPhaseHealthPctThreshold=0.25f,
|
|
bCanUseSweepingClaw=true, //Deprecated, Sweeping Claw is not a special move anymore.
|
|
bCanUseTeslaBlast=false,
|
|
bCanUsePlasmaCannon=false,
|
|
bCanUseLightningStorm=true,
|
|
bCanUseWarningSiren=true,
|
|
MeleeDamageScale=1.f,
|
|
GroundSpeedScale=2.25f,
|
|
SprintSpeedScale=1.05f,
|
|
bCanCloak=false,
|
|
bUseAltSprintAnim=true,
|
|
bShouldTaunt=true,
|
|
IncapSettings={(
|
|
// for reference: Vulnerability=(default, head, legs, arms, special)
|
|
/*AF_EMP*/ (Vulnerability=(1.0), Cooldown=10.0, Duration=2.5),
|
|
/*AF_FirePanic*/(Vulnerability=(0.65), Cooldown=15.0, Duration=1.2),
|
|
/*AF_MeleeHit*/ (Vulnerability=(0.1, 0.95, 0.1, 0.1, 0.75), Cooldown=2.0),
|
|
/*AF_GunHit*/ (Vulnerability=(0.1, 0.1, 0.1, 0.1, 0.5), Cooldown=2.0),
|
|
/*AF_Stumble*/ (Vulnerability=(0.1, 0.3, 0.1, 0.1, 0.4), Cooldown=10.0),
|
|
/*AF_Stun*/ (Vulnerability=(0.1, 0.55, 0.1, 0.1, 0.55), Cooldown=17.0, Duration=1.25),
|
|
/*AF_Poison*/ (Vulnerability=(0.0), Cooldown=15.0, Duration=1.2),
|
|
/*AF_Snare*/ (Vulnerability=(1.0, 2.0, 1.0, 1.0, 2.0), Cooldown=10.5, Duration=3.0),
|
|
/*AF_Knockdown*/(Vulnerability=(0.1, 0.4, 0.1, 0.1, 0.25), Cooldown=20.0),
|
|
/*AF_Freeze*/ (Vulnerability=(0.65), Cooldown=10.0, Duration=1.0),
|
|
/*AF_Microwave*/(Vulnerability=(0.08), Cooldown=10.0, Duration=3.0),
|
|
/*AF_Bleed*/ (Vulnerability=(0.15), Cooldown=10.0),
|
|
)},
|
|
DamageFX={(
|
|
FXInfo={(
|
|
{(
|
|
Template=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Low_Damage_01',
|
|
Sockets=(Hand_FX_Start_R,FX_RightHip)
|
|
)},
|
|
{(
|
|
Template=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Medium_Damage_01',
|
|
Sockets=(FX_LeftKnee)
|
|
)},
|
|
{(
|
|
Template=ParticleSystem'ZED_Patriarch_EMIT.FX_Patriarch_tentacle_LowD_01',
|
|
Sockets=(FX_Armor_Chest)
|
|
)},
|
|
{(
|
|
Template=ParticleSystem'ZED_Patriarch_EMIT.FX_Patriarch_tentacle_MidD_01',
|
|
Sockets=(FX_LeftForearm)
|
|
)},
|
|
{(
|
|
Template=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Damage_Shoulder_02',
|
|
Sockets=(Head_Attach)
|
|
)}
|
|
)}
|
|
)}
|
|
)}
|
|
BattlePhases(3)={(
|
|
NextPhaseHealthPctThreshold=0, // Set to 0, she doesn't have a phase after this one.
|
|
bCanUseSweepingClaw=true, //Deprecated, Sweeping Claw is not a special move anymore.
|
|
bCanUseTeslaBlast=false,
|
|
bCanUsePlasmaCannon=false,
|
|
bCanUseLightningStorm=false,
|
|
bCanUseWarningSiren=true,
|
|
MeleeDamageScale=1.2f,
|
|
GroundSpeedScale=2.5f,
|
|
SprintSpeedScale=1.15f,
|
|
bCanCloak=true,
|
|
bUseAltSprintAnim=true,
|
|
bShouldTaunt=true,
|
|
IncapSettings={(
|
|
// for reference: Vulnerability=(default, head, legs, arms, special)
|
|
/*AF_EMP*/ (Vulnerability=(1.0), Cooldown=10.0, Duration=2.5),
|
|
/*AF_FirePanic*/(Vulnerability=(0.65), Cooldown=15.0, Duration=1.2),
|
|
/*AF_MeleeHit*/ (Vulnerability=(0.1, 0.95, 0.1, 0.1, 0.75), Cooldown=2.0),
|
|
/*AF_GunHit*/ (Vulnerability=(0.1, 0.1, 0.1, 0.1, 0.5), Cooldown=2.0),
|
|
/*AF_Stumble*/ (Vulnerability=(0.1, 0.3, 0.1, 0.1, 0.4), Cooldown=10.0),
|
|
/*AF_Stun*/ (Vulnerability=(0.1, 0.55, 0.1, 0.1, 0.55), Cooldown=17.0, Duration=1.25),
|
|
/*AF_Poison*/ (Vulnerability=(0.0), Cooldown=15.0, Duration=1.2),
|
|
/*AF_Snare*/ (Vulnerability=(1.0, 2.0, 1.0, 1.0, 2.0), Cooldown=10.5, Duration=3.0),
|
|
/*AF_Knockdown*/(Vulnerability=(0.1, 0.4, 0.1, 0.1, 0.25), Cooldown=20.0),
|
|
/*AF_Freeze*/ (Vulnerability=(0.65), Cooldown=10.0, Duration=1.0),
|
|
/*AF_Microwave*/(Vulnerability=(0.08), Cooldown=10.0, Duration=3.0),
|
|
/*AF_Bleed*/ (Vulnerability=(0.15), Cooldown=10.0),
|
|
)},
|
|
DamageFX={(
|
|
FXInfo={(
|
|
{(
|
|
Template=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_High_Damage_01',
|
|
Sockets=(FX_LeftKnee,Hand_FX_Start_R,FX_RightHip)
|
|
)},
|
|
{(
|
|
Template=ParticleSystem'ZED_Patriarch_EMIT.FX_Patriarch_tentacle_HighD_01',
|
|
Sockets=(FX_Armor_Chest)
|
|
)},
|
|
{(
|
|
Template=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Low_Damage_01',
|
|
Sockets=(FX_Armor_Chest)
|
|
)},
|
|
{(
|
|
Template=ParticleSystem'ZED_Patriarch_EMIT.FX_Patriarch_tentacle_HighD_01',
|
|
Sockets=(FX_LeftForearm)
|
|
)},
|
|
{(
|
|
Template=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Damage_Shoulder_01',
|
|
Sockets=(Head_Attach)
|
|
)}
|
|
)}
|
|
)}
|
|
)}
|
|
|
|
// Summon squads by difficulty @TODO: Switch to Matriarch
|
|
SummonWaves(0)={(
|
|
PhaseOneWave=KFAIWaveInfo'GP_Spawning_ARCH.Matriarch.Mat_Minions_Normal_One',
|
|
PhaseTwoWave=KFAIWaveInfo'GP_Spawning_ARCH.Matriarch.Mat_Minions_Normal_Two',
|
|
PhaseThreeWave=KFAIWaveInfo'GP_Spawning_ARCH.Matriarch.Mat_Minions_Normal_Three'
|
|
)}
|
|
SummonWaves(1)={(
|
|
PhaseOneWave=KFAIWaveInfo'GP_Spawning_ARCH.Matriarch.Mat_Minions_Hard_One',
|
|
PhaseTwoWave=KFAIWaveInfo'GP_Spawning_ARCH.Matriarch.Mat_Minions_Hard_Two',
|
|
PhaseThreeWave=KFAIWaveInfo'GP_Spawning_ARCH.Matriarch.Mat_Minions_Hard_Three'
|
|
)}
|
|
SummonWaves(2)={(
|
|
PhaseOneWave=KFAIWaveInfo'GP_Spawning_ARCH.Matriarch.Mat_Minions_Suicidal_One',
|
|
PhaseTwoWave=KFAIWaveInfo'GP_Spawning_ARCH.Matriarch.Mat_Minions_Suicidal_Two',
|
|
PhaseThreeWave=KFAIWaveInfo'GP_Spawning_ARCH.Matriarch.Mat_Minions_Suicidal_Three'
|
|
)}
|
|
SummonWaves(3)={(
|
|
PhaseOneWave=KFAIWaveInfo'GP_Spawning_ARCH.Matriarch.Mat_Minions_HOE_One',
|
|
PhaseTwoWave=KFAIWaveInfo'GP_Spawning_ARCH.Matriarch.Mat_Minions_HOE_Two',
|
|
PhaseThreeWave=KFAIWaveInfo'GP_Spawning_ARCH.Matriarch.Mat_Minions_HOE_Three'
|
|
)}
|
|
NumMinionsToSpawn=(X=3, Y=5)
|
|
MinionSpawnDuration=30.f
|
|
|
|
// ---------------------------------------------
|
|
// Shield
|
|
|
|
bShieldUp=true
|
|
|
|
// invulnerable effects
|
|
Begin Object Class=KFSkinTypeEffects_InvulnerabilityShield Name=ShieldEffects
|
|
ImpactFXArray[0]={(
|
|
Type=FXG_Ballistic,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[1]={(
|
|
Type=FXG_Bludgeon,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[2]={(
|
|
Type=FXG_Piercing,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[3]={(
|
|
Type=FXG_Slashing,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[4]={(
|
|
Type=FXG_Fire,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[5]={(
|
|
Type=FXG_Toxic,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[6]={(
|
|
Type=FXG_Healing,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[7]={(
|
|
Type=FXG_Sawblade,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[8]={(
|
|
Type=FXG_DrainLife,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[9]={(
|
|
Type=FXG_IncendiaryRound,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[10]={(
|
|
Type=FXG_UnexplodedGrenade,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[11]={(
|
|
Type=FXG_MicrowaveBlast,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[12]={(
|
|
Type=FXG_ShieldBash,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[13]={(
|
|
Type=FXG_MetalMace,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[14]={(
|
|
Type=FXG_Flare,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[15]={(
|
|
Type=FXG_Freeze,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[16]={(
|
|
Type=FXG_Bludgeon_Chains,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[17]={(
|
|
Type=FXG_MicrowaveProj,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[18]={(
|
|
Type=FXG_Electricity,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
ImpactFXArray[19]={(
|
|
Type=FXG_Slashing_Ion,
|
|
DefaultParticle=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield_Hit',
|
|
DefaultSound=AkEvent'WW_Skin_Impacts.Play_IMP_Ballistic_Machine_Local')}
|
|
End Object
|
|
|
|
// Shield FX
|
|
ShieldImpactEffects=ShieldEffects
|
|
InvulnerableShieldFX=ParticleSystem'ZED_Matriarch_EMIT.FX_Matriarch_Shield'
|
|
ShieldSocketName=Root
|
|
|
|
// Shield colors
|
|
ShieldColorGreen=(R=50,G=255,B=50)
|
|
ShieldCoreColorGreen=(R=0,G=255,B=0)
|
|
ShieldColorYellow=(R=255,G=255,B=20)
|
|
ShieldCoreColorYellow=(R=255,G=255,B=0)
|
|
ShieldColorOrange=(R=255,G=110,B=10)
|
|
ShieldCoreColorOrange=(R=255,G=105,B=0)
|
|
ShieldColorRed=(R=255,G=20,B=20)
|
|
ShieldCoreColorRed=(R=255,G=10,B=10)
|
|
|
|
// Glow colors
|
|
GlowColor_Phase1=(R=0.1, G=1.0)
|
|
GlowColor_Phase2=(R=1.0, G=0.5)
|
|
GlowColor_Phase3=(R=1.0, G=0.1)
|
|
GlowColor_Phase4=(R=2.0)
|
|
|
|
// ---------------------------------------------
|
|
// damage phase lights and effects
|
|
Begin Object Class=PointLightComponent Name=PointLightComponent0
|
|
Brightness=1.f
|
|
Radius=128.f
|
|
LightColor=(R=168,G=222,B=173,A=255)
|
|
CastShadows=false
|
|
bCastPerObjectShadows=false
|
|
LightingChannels=(Indoor=true,Outdoor=true,bInitialized=TRUE)
|
|
End Object
|
|
LightTemplate_Phase1=PointLightComponent0
|
|
|
|
Begin Object Class=PointLightComponent Name=PointLightComponent1
|
|
Brightness=1.f
|
|
Radius=128.f
|
|
LightColor=(R=231,G=215,B=161,A=255)
|
|
CastShadows=false
|
|
bCastPerObjectShadows=false
|
|
LightingChannels=(Indoor=true,Outdoor=true,bInitialized=TRUE)
|
|
End Object
|
|
LightTemplate_Phase2=PointLightComponent1
|
|
|
|
Begin Object Class=PointLightComponent Name=PointLightComponent2
|
|
Brightness=1.f
|
|
Radius=128.f
|
|
LightColor=(R=231,G=144,B=0,A=255)
|
|
CastShadows=false
|
|
bCastPerObjectShadows=false
|
|
LightingChannels=(Indoor=true,Outdoor=true,bInitialized=TRUE)
|
|
End Object
|
|
LightTemplate_Phase3=PointLightComponent2
|
|
|
|
Begin Object Class=PointLightComponent Name=PointLightComponent3
|
|
Brightness=2.f
|
|
Radius=128.f
|
|
LightColor=(R=255,G=64,B=64,A=255)
|
|
CastShadows=false
|
|
bCastPerObjectShadows=false
|
|
LightingChannels=(Indoor=true,Outdoor=true,bInitialized=TRUE)
|
|
|
|
// light anim
|
|
AnimationType=1 // LightAnim_Flicker
|
|
AnimationFrequency=5.f
|
|
MinBrightness=1.f
|
|
MaxBrightness=2.f
|
|
End Object
|
|
LightTemplate_Phase4=PointLightComponent3
|
|
|
|
LightSocketFront=FX_Armor_Chest
|
|
LightSocketBack=FX_Armor_Back
|
|
|
|
// Shield shatter explosion template
|
|
Begin Object Class=KFGameExplosion Name=ShatterExploTemplate0
|
|
Damage=0
|
|
DamageRadius=500
|
|
DamageFalloffExponent=1.f
|
|
DamageDelay=0.f
|
|
|
|
// Damage Effects
|
|
KnockDownStrength=0
|
|
KnockDownRadius=0
|
|
FractureMeshRadius=500.0
|
|
FracturePartVel=500.0
|
|
ExplosionEffects=KFImpactEffectInfo'ZED_Matriarch_ARCH.Matriarch_Shield_Explosion_Arch'
|
|
ExplosionSound=AkEvent'WW_ZED_Matriarch.Play_Matriarch_SFX_Shield_Break'
|
|
|
|
// Camera Shake
|
|
CamShake=CameraShake'FX_CameraShake_Arch.Grenades.Default_Grenade'
|
|
CamShakeInnerRadius=450
|
|
CamShakeOuterRadius=900
|
|
CamShakeFalloff=0.5f
|
|
bOrientCameraShakeTowardsEpicenter=true
|
|
bUseOverlapCheck=false
|
|
End Object
|
|
ShieldShatterExplosionTemplate=ShatterExploTemplate0
|
|
|
|
ShieldHealthMaxDefaults[0]=2000
|
|
ShieldHealthMaxDefaults[1]=3000
|
|
ShieldHealthMaxDefaults[2]=4500
|
|
ShieldHealthMaxDefaults[3]=5600
|
|
ShieldHealthScale=1.f
|
|
|
|
ShieldBreakPawnHealthPct=0.75f
|
|
|
|
// ---------------------------------------------
|
|
// Hit Zones
|
|
|
|
HitZones.Empty
|
|
|
|
// Dome needs to be first to count as the "head" (HZI_HEAD)
|
|
// We'll remove the dome entry when the head armor breaks so that her real head gets to be the head, too.
|
|
HitZones.Add((ZoneName=dome, BoneName=dome, Limb=BP_Head, GoreHealth=MaxInt, DmgScale=1.0, SkinID=2))
|
|
HitZones.Add((ZoneName=head, BoneName=head, Limb=BP_Head, GoreHealth=MaxInt, DmgScale=1.3, SkinID=1))
|
|
|
|
HitZones.Add((ZoneName=chest, BoneName=Spine, Limb=BP_Torso, GoreHealth=150, DmgScale=0.25, SkinID=2))
|
|
HitZones.Add((ZoneName=abdomen, BoneName=hips, Limb=BP_Torso, GoreHealth=MaxInt, DmgScale=0.5, SkinID=0))
|
|
HitZones.Add((ZoneName=stomach, BoneName=SpineDisc, Limb=BP_Torso, GoreHealth=MaxInt, DmgScale=0.25, SkinID=2))
|
|
|
|
HitZones.Add((ZoneName=lupperarm, BoneName=LeftShoulder, Limb=BP_LeftArm, GoreHealth=50, DmgScale=0.5, SkinID=0))
|
|
HitZones.Add((ZoneName=lupperauldron, BoneName=LeftPauldron, Limb=BP_LeftArm, GoreHealth=MaxInt, DmgScale=0.25, SkinID=2))
|
|
HitZones.Add((ZoneName=lforearm, BoneName=LeftForearm, Limb=BP_LeftArm, GoreHealth=20, DmgScale=1.0, SkinID=0))
|
|
HitZones.Add((ZoneName=lhandcap, BoneName=LeftHandCap, Limb=BP_LeftArm, GoreHealth=MaxInt, DmgScale=1.0, SkinID=2))
|
|
HitZones.Add((ZoneName=lhand, BoneName=LeftHandMain, Limb=BP_LeftArm, GoreHealth=MaxInt, DmgScale=1.3, SkinID=3))
|
|
|
|
HitZones.Add((ZoneName=rupperarm, BoneName=RightShoulder, Limb=BP_RightArm, GoreHealth=50, DmgScale=0.5, SkinID=0))
|
|
HitZones.Add((ZoneName=rupperpauldron,BoneName=RightPauldron, Limb=BP_RightArm, GoreHealth=MaxInt, DmgScale=0.25, SkinID=2))
|
|
HitZones.Add((ZoneName=rupperhose, BoneName=RightArmHose1, Limb=BP_RightArm, GoreHealth=MaxInt, DmgScale=0.25, SkinID=2))
|
|
HitZones.Add((ZoneName=rforearm, BoneName=RightForearm, Limb=BP_RightArm, GoreHealth=20, DmgScale=0.25, SkinID=2))
|
|
|
|
HitZones.Add((ZoneName=lthigh, BoneName=LeftUpLeg, Limb=BP_LeftLeg, GoreHealth=100, DmgScale=0.25, SkinID=2))
|
|
HitZones.Add((ZoneName=lcalf, BoneName=LeftLeg, Limb=BP_LeftLeg, GoreHealth=50, DmgScale=0.25, SkinID=2))
|
|
HitZones.Add((ZoneName=lfoot, BoneName=LeftFoot, Limb=BP_LeftLeg, GoreHealth=MaxInt, DmgScale=0.25, SkinID=2))
|
|
|
|
HitZones.Add((ZoneName=rthigh, BoneName=RightUpLeg, Limb=BP_RightLeg, GoreHealth=100, DmgScale=0.25, SkinID=2))
|
|
HitZones.Add((ZoneName=rcalf, BoneName=RightLeg, Limb=BP_RightLeg, GoreHealth=50, DmgScale=0.25, SkinID=2))
|
|
HitZones.Add((ZoneName=rfoot, BoneName=RightFoot, Limb=BP_RightLeg, GoreHealth=MaxInt, DmgScale=0.25, SkinID=2))
|
|
|
|
HitZones.Add((ZoneName=heart, BoneName=Tentacle1, Limb=BP_Special, GoreHealth=MaxInt, DmgScale=1.3, SkinID=3))
|
|
HitZones.Add((ZoneName=teslacoil, BoneName=EMP_Main, Limb=BP_Special, GoreHealth=MaxInt, DmgScale=1.0, SkinID=2))
|
|
|
|
WeakSpotSocketNames.Empty()
|
|
WeakSpotSocketNames.Add(FX_Dazed) // head weak spot
|
|
WeakSpotSocketNames.Add(Hand_FX_End_L) // Left arm weakspot
|
|
|
|
// ---------------------------------------------
|
|
// Damage Type Modifiers
|
|
|
|
// Resistant damage types
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Ballistic_Submachinegun', DamageScale=(0.5)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Ballistic_AssaultRifle', DamageScale=(0.5)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Ballistic_Shotgun', DamageScale=(0.4)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Ballistic_Handgun', DamageScale=(0.5)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Ballistic_Rifle', DamageScale=(0.5)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Slashing', DamageScale=(1.0)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Bludgeon', DamageScale=(1.0)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Fire', DamageScale=(0.5)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Microwave', DamageScale=(0.9)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Explosive', DamageScale=(0.4)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Piercing', DamageScale=(0.5)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Toxic', DamageScale=(0.05)))
|
|
|
|
//special case
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Ballistic_MicrowaveRifle', DamageScale=(0.7)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Toxic_HRGHealthrower', DamageScale=(0.5)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Ballistic_HRGTeslauncher', DamageScale=(0.7)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Ballistic_Minigun', DamageScale=(0.75)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Toxic_MineReconstructorExplosion', DamageScale=(0.6)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_EMP_ArcGenerator_Beam', DamageScale=(1.5)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_EMP_ArcGeneratorSphereImpact', DamageScale=(2)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_EMP_ArcGenerator_DefaultFiremodeZapDamage', DamageScale=(1.5)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_EMP_ArcGenerator_AltFiremodeZapDamage', DamageScale=(1.5)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Ballistic_HRGScorcherLightingImpact', DamageScale=(0.4)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Fire_HRGScorcherDoT', DamageScale=(0.4)))
|
|
|
|
//DamageTypeModifiers.Add((DamageType=class'KFDT_Ballistic_HRG_Vampire_BloodBallImpact', DamageScale=(0.3)))
|
|
//DamageTypeModifiers.Add((DamageType=class'KFDT_Ballistic_HRG_Vampire_BloodBallHeavyImpact', DamageScale=(0.3)))
|
|
//DamageTypeModifiers.Add((DamageType=class'KFDT_Piercing_HRG_Vampire_CrystalSpike', DamageScale=(0.25)))
|
|
//DamageTypeModifiers.Add((DamageType=class'KFDT_Bleeding_HRG_Vampire_BloodSuck', DamageScale=(0.5)))
|
|
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Ballistic_HRG_Vampire_BloodBallImpact', DamageScale=(0.4)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Ballistic_HRG_Vampire_BloodBallHeavyImpact', DamageScale=(0.4)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Piercing_HRG_Vampire_CrystalSpike', DamageScale=(0.3)))
|
|
DamageTypeModifiers.Add((DamageType=class'KFDT_Bleeding_HRG_Vampire_BloodSuck', DamageScale=(0.7)))
|
|
|
|
// ---------------------------------------------
|
|
// Armor
|
|
|
|
ArmorZoneStatus=3 // 0b00000011
|
|
PreviousArmorZoneStatus=3
|
|
|
|
ArmorInfoClass=class'KFZedArmorInfo_Matriarch'
|
|
RepArmorPct[0]=255
|
|
RepArmorPct[1]=255
|
|
OverrideArmorFXIndex=200
|
|
|
|
// ---------------------------------------------
|
|
// Cloaking
|
|
|
|
bCanCloak=true
|
|
bCloakOnMeleeEnd=true
|
|
|
|
CloakedLoop=AkEvent'WW_ZED_Matriarch.Play_Matriarch_SFX_Cloak'
|
|
CloakedLoopEnd=AkEvent'WW_ZED_Matriarch.Stop_Matriarch_SFX_Cloak'
|
|
Begin Object Class=AkComponent name=CloakedAkComponent0
|
|
BoneName=dummy
|
|
bStopWhenOwnerDestroyed=true
|
|
bForceOcclusionUpdateInterval=true
|
|
OcclusionUpdateInterval=0.2f
|
|
End Object
|
|
CloakedAkComponent=CloakedAkComponent0
|
|
Components.Add( CloakedAkComponent0 )
|
|
|
|
Begin Object Class=AkComponent name=BeamHitAC0
|
|
bStopWhenOwnerDestroyed=true
|
|
End Object
|
|
Components.Add(BeamHitAC0)
|
|
BeamHitAC=BeamHitAC0
|
|
|
|
// ---------------------------------------------
|
|
// Achievements
|
|
OnDeathAchievementID=KFACHID_DefeatMatriarch
|
|
|
|
// ---------------------------------------------
|
|
// Bump
|
|
HeavyBumpDamageType=class'KFGameContent.KFDT_HeavyZedBump'
|
|
|
|
// ---------------------------------------------
|
|
// Gun tracking
|
|
bUseServerSideGunTracking=true
|
|
GunTargetBoneName=Spine2
|
|
|
|
ZEDCowboyHatAttachName=Hat_Attach
|
|
}
|