//============================================================================= // 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 Sockets; }; struct BattleDamageInfo { var array FXInfo; var transient array 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 IncapSettings; var BattleDamageInfo DamageFX; }; var array BattlePhases; var int TentacleDamage; var class 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 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 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, 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, 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; 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, 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 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 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 }