497 lines
14 KiB
Ucode
497 lines
14 KiB
Ucode
//=============================================================================
|
|
// KFWeapAttach_HRG_Vampire
|
|
//=============================================================================
|
|
//
|
|
//=============================================================================
|
|
// Killing Floor 2
|
|
// Copyright (C) 2020 Tripwire Interactive LLC
|
|
//=============================================================================
|
|
class KFWeapAttach_HRG_Vampire extends KFWeapAttach_SprayBase;
|
|
|
|
var transient ParticleSystemComponent ChargingPSC;
|
|
var transient ParticleSystemComponent ChargedPSC;
|
|
var ParticleSystem ChargingEffect;
|
|
var ParticleSystem ChargedEffect;
|
|
var ParticleSystem BloodStolenEffect;
|
|
var bool bIsCharging;
|
|
var bool bIsFullyCharged;
|
|
var bool bIsChargeEffectsActive;
|
|
var bool bIsBloodParticlesEffectActive;
|
|
var bool bIsDisabledSprayVisualAndMesh;
|
|
|
|
var repnotify float StartFireTime;
|
|
|
|
var int ChargeLevel;
|
|
|
|
var float FXScalingFactorByCharge;
|
|
var float ChargeRTPC;
|
|
|
|
var KFPawn_Monster oZedCurrentlyBeingSprayed;
|
|
var KFPawn_Monster oZedPreviouslyBeingSprayed;
|
|
|
|
var KFWeap_HRG_Vampire Weapon;
|
|
|
|
var KFEmit_DirectionalPath BloodStolenParticles[15];
|
|
var int NumBloodStolenParticlesForPool;
|
|
|
|
var transient float BloodStolenControlTime;
|
|
|
|
var float RateUpdateDestinationBloodParticles;
|
|
var transient float UpdateDestinationBloodParticlesTime;
|
|
|
|
var class<KFProj_BloodSplash> BloodSplashClass;
|
|
|
|
var bool bHasToStopDoingFireAnim;
|
|
var bool bHasToStopDoingFireAnimB;
|
|
|
|
/** Blood Particles */
|
|
var(BloodParticles) float SpeedBloodParticles;
|
|
var(BloodParticles) float SpawnRateBloodParticles;
|
|
var(BloodParticles) float SpeedBloodParticles_3P;
|
|
var(BloodParticles) float SpawnRateBloodParticles_3P;
|
|
var(BloodParticles) float HalfAngleSpawnCone;
|
|
var(BloodParticles) float CurveTurnRateUntilDestinationFinal;
|
|
var(BloodParticles) float CurveTurnRateUntilDestinationMidPoint;
|
|
var(BloodParticles) float LimitDistanceFinalPoint;
|
|
var(BloodParticles) float LimitDistanceMidPoint;
|
|
|
|
simulated function PostBeginPlay()
|
|
{
|
|
local int Index;
|
|
|
|
super.PostBeginPlay();
|
|
UpdateDestinationBloodParticlesTime = RateUpdateDestinationBloodParticles;
|
|
|
|
for( Index = (NumBloodStolenParticlesForPool - 1) ; Index >= 0 ; Index-- )
|
|
{
|
|
BloodStolenParticles[Index] = Spawn(class'KFEmit_DirectionalPath');
|
|
BloodStolenParticles[Index].DeactivateEmitter();
|
|
BloodStolenParticles[Index].SetTemplate(BloodStolenEffect, true);
|
|
}
|
|
}
|
|
|
|
simulated function StartFire()
|
|
{
|
|
StartFireTime = WorldInfo.TimeSeconds;
|
|
bIsCharging = false;
|
|
bIsFullyCharged = false;
|
|
bIsDisabledSprayVisualAndMesh = false;
|
|
|
|
if (ChargingPSC == none)
|
|
{
|
|
ChargingPSC = new(self) class'ParticleSystemComponent';
|
|
|
|
if (WeapMesh != none)
|
|
{
|
|
WeapMesh.AttachComponentToSocket(ChargingPSC, 'MuzzleFlash');
|
|
}
|
|
else
|
|
{
|
|
AttachComponent(ChargingPSC);
|
|
}
|
|
ChargingPSC.SetTemplate(ChargingEffect);
|
|
}
|
|
|
|
if (ChargedPSC == none)
|
|
{
|
|
ChargedPSC = new(self) class'ParticleSystemComponent';
|
|
|
|
if (WeapMesh != none)
|
|
{
|
|
WeapMesh.AttachComponentToSocket(ChargedPSC, 'MuzzleFlash');
|
|
}
|
|
else
|
|
{
|
|
AttachComponent(ChargedPSC);
|
|
}
|
|
ChargedPSC.SetTemplate(ChargedEffect);
|
|
}
|
|
ChargingPSC.SetActive( false );
|
|
ChargedPSC.SetActive( false );
|
|
}
|
|
|
|
simulated event Tick(float DeltaTime)
|
|
{
|
|
local int Index;
|
|
local vector MuzzleFlashSocketLocation, BloodParticlesMidPointSocketLocation;
|
|
local KFEmit_DirectionalPath EmitterToRemove;
|
|
local vector VectorParameterParticle;
|
|
local vector ChargePercentageVector;
|
|
local Rotator DestinationRotation, BloodParticlesMidPointSocketRotation;
|
|
local vector BloodSplashVelocity;
|
|
|
|
if(bIsChargeEffectsActive)
|
|
{
|
|
if(bIsCharging)
|
|
{
|
|
ChargingPSC.SetActive( true, true );
|
|
ChargePercentageVector.X = ChargeRTPC;
|
|
ChargePercentageVector.Y = ChargeRTPC;
|
|
ChargePercentageVector.Z = ChargeRTPC;
|
|
ChargingPSC.SetVectorParameter( name("BlobCharge"), ChargePercentageVector);
|
|
}
|
|
|
|
if(bIsFullyCharged)
|
|
{
|
|
ChargedPSC.SetActive( true, true );
|
|
ChargingPSC.SetFloatParameter( name("InflateBlob"), ChargeRTPC);
|
|
}
|
|
}
|
|
|
|
if (bIsDisabledSprayVisualAndMesh)
|
|
{
|
|
TurnOffFireSpray();
|
|
ActiveFlameSpray.CleanupEndFire();
|
|
}
|
|
|
|
//Spawning blood particles if conditions met
|
|
if (bIsBloodParticlesEffectActive)
|
|
{
|
|
if(oZedCurrentlyBeingSprayed != none && oZedCurrentlyBeingSprayed.IsAliveAndWell())
|
|
{
|
|
CreateBloodParticle(DeltaTime, oZedCurrentlyBeingSprayed);
|
|
}
|
|
}
|
|
|
|
|
|
// Updating blood stolen particles FX destination position
|
|
|
|
UpdateDestinationBloodParticlesTime -= DeltaTime;
|
|
if (UpdateDestinationBloodParticlesTime <= 0)
|
|
{
|
|
UpdateDestinationBloodParticlesTime = RateUpdateDestinationBloodParticles;
|
|
|
|
if( WeapMesh != none )
|
|
{
|
|
GetFlameSocketLocAndRot(MuzzleFlashSocketLocation, DestinationRotation);
|
|
WeapMesh.GetSocketWorldLocationAndRotation('BloodParticlesMidPoint', BloodParticlesMidPointSocketLocation, BloodParticlesMidPointSocketRotation);
|
|
}
|
|
|
|
for( Index = (NumBloodStolenParticlesForPool - 1) ; Index >= 0 ; Index-- )
|
|
{
|
|
if(!BloodStolenParticles[Index].IsEnabled || BloodStolenParticles[Index] == None)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( BloodStolenParticles[Index].bReachDestinationFinal )
|
|
{
|
|
EmitterToRemove = BloodStolenParticles[Index];
|
|
//BloodStolenParticles.Remove(Index, 1);
|
|
EmitterToRemove.DeactivateEmitter();
|
|
}
|
|
else
|
|
{
|
|
if (BloodStolenParticles[Index].ParticleSystemComponent != None)
|
|
{
|
|
VectorParameterParticle.X = WorldInfo.TimeDilation;
|
|
VectorParameterParticle.Y = WorldInfo.TimeDilation;
|
|
VectorParameterParticle.Z = WorldInfo.TimeDilation;
|
|
BloodStolenParticles[Index].ParticleSystemComponent.SetVectorParameter( name("ZedtimeScale"), VectorParameterParticle );
|
|
}
|
|
BloodStolenParticles[Index].UpdateDestination( MuzzleFlashSocketLocation, BloodParticlesMidPointSocketLocation );
|
|
|
|
if (FRand() > 0.47)
|
|
{
|
|
BloodSplashVelocity.x = 0;
|
|
BloodSplashVelocity.y = RandRange(-100, 100);
|
|
BloodSplashVelocity.z = -200;
|
|
SpawnBloodSplash(BloodSplashClass, BloodStolenParticles[Index].Location, BloodSplashVelocity);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Super.Tick(DeltaTime);
|
|
}
|
|
|
|
simulated function FirstPersonFireEffects(Weapon W, vector HitLocation)
|
|
{
|
|
super.FirstPersonFireEffects(W, HitLocation);
|
|
}
|
|
|
|
simulated function bool ThirdPersonFireEffects(vector HitLocation, KFPawn P, byte ThirdPersonAnimRateByte )
|
|
{
|
|
local EAnimSlotStance AnimType;
|
|
local bool bResult;
|
|
bIsChargeEffectsActive = true;
|
|
bIsBloodParticlesEffectActive = true;
|
|
|
|
//bResult = Super(KFWeaponAttachment).ThirdPersonFireEffects(HitLocation,P,ThirdPersonAnimRateByte);
|
|
|
|
SpawnTracer(GetMuzzleLocation(), HitLocation);
|
|
|
|
// Effects below this point are culled based on visibility and distance
|
|
if ( !ActorEffectIsRelevant(P, false, MaxFireEffectDistance) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
DecodeThirdPersonAnimRate( ThirdPersonAnimRateByte );
|
|
|
|
// Weapon shoot anims
|
|
if( !bWeapMeshIsPawnMesh && bHasToStopDoingFireAnim == false )
|
|
{
|
|
PlayWeaponFireAnim();
|
|
bHasToStopDoingFireAnim = true;
|
|
}
|
|
|
|
if( P.IsDoingSpecialMove() && P.SpecialMoves[P.SpecialMove].bAllowFireAnims )
|
|
{
|
|
AnimType = EAS_Additive;
|
|
}
|
|
else
|
|
{
|
|
AnimType = EAS_FullBody;
|
|
}
|
|
|
|
// Character shoot anims
|
|
if ( !P.IsDoingSpecialMove() || AnimType == EAS_Additive )
|
|
{
|
|
if(!bHasToStopDoingFireAnimB)
|
|
{
|
|
bHasToStopDoingFireAnimB = true;
|
|
PlayPawnFireAnim( P, AnimType );
|
|
}
|
|
|
|
// interrupt other weapon action anims (e.g. Reload)
|
|
if( !P.IsDoingSpecialMove() )
|
|
{
|
|
P.StopBodyAnim(P.bIsCrouched ? EAS_CH_UpperBody : EAS_UpperBody, 0.1f);
|
|
}
|
|
|
|
if ( OnWeaponStateChanged != None )
|
|
{
|
|
OnWeaponStateChanged(true);
|
|
}
|
|
}
|
|
|
|
CauseMuzzleFlash(P.FiringMode);
|
|
|
|
// Wider effect distances for fire spray. Called on Instigator to go beyond the weapon mesh cull distance
|
|
if ( P.FiringMode != 1 && P.ActorEffectIsRelevant(P, false, 15000, 2000) && !bIsDisabledSprayVisualAndMesh )
|
|
{
|
|
TurnOnFireSpray();
|
|
bResult = true;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
simulated function StopThirdPersonFireEffects(optional bool bForce)
|
|
{
|
|
Super.StopThirdPersonFireEffects(bForce);
|
|
bIsChargeEffectsActive = false;
|
|
bIsBloodParticlesEffectActive = false;
|
|
RemoveAllBloodParticles();
|
|
bIsDisabledSprayVisualAndMesh = false;
|
|
if (ChargingPSC != none)
|
|
{
|
|
ChargingPSC.SetActive(false);
|
|
}
|
|
if (ChargedPSC != none)
|
|
{
|
|
ChargedPSC.SetActive(false);
|
|
}
|
|
bHasToStopDoingFireAnim = false;
|
|
bHasToStopDoingFireAnimB = false;
|
|
}
|
|
|
|
simulated function CauseMuzzleFlash(byte FiringMode)
|
|
{
|
|
if (MuzzleFlash == None && MuzzleFlashTemplate != None)
|
|
{
|
|
AttachMuzzleFlash();
|
|
}
|
|
|
|
Super.CauseMuzzleFlash(FiringMode);
|
|
}
|
|
|
|
simulated protected function TurnOnPilot()
|
|
{
|
|
Super.TurnOnPilot();
|
|
|
|
if( FlamePool[0] != None && KFSprayActor_HRG_Vampire(FlamePool[0]) != None && KFSprayActor_HRG_Vampire(FlamePool[0]).OwnerWeapon == None)
|
|
{
|
|
KFSprayActor_HRG_Vampire(FlamePool[0]).OwnerWeapon = KFWeap_HRG_Vampire(KFPawn_Human(Instigator).MyKFWeapon);
|
|
}
|
|
if( FlamePool[1] != None && KFSprayActor_HRG_Vampire(FlamePool[1]) != None && KFSprayActor_HRG_Vampire(FlamePool[1]).OwnerWeapon == None)
|
|
{
|
|
KFSprayActor_HRG_Vampire(FlamePool[1]).OwnerWeapon = KFWeap_HRG_Vampire(KFPawn_Human(Instigator).MyKFWeapon);
|
|
}
|
|
}
|
|
|
|
simulated function CreateBloodParticle(float DeltaTime, KFPawn_Monster Monster)
|
|
{
|
|
Local KFEmit_DirectionalPath Emitter;
|
|
local vector DestinationLocation, MonsterLocation, BloodParticlesMidPointSocketLocation;
|
|
local Rotator DestinationRotation, BloodParticlesMidPointSocketRotation;
|
|
local vector BloodSplashVelocity;
|
|
local int Index;
|
|
|
|
if( BloodStolenControlTime > 0 )
|
|
{
|
|
BloodStolenControlTime -= DeltaTime;
|
|
return;
|
|
}
|
|
|
|
Emitter = none;
|
|
for( Index = (NumBloodStolenParticlesForPool - 1) ; Index >= 0 ; Index-- )
|
|
{
|
|
if(BloodStolenParticles[Index].IsEnabled == false)
|
|
{
|
|
//`log("I gave the emitter");
|
|
Emitter = BloodStolenParticles[Index];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(Emitter == none)
|
|
{
|
|
//`log("NO EMITTER");
|
|
return;
|
|
}
|
|
|
|
|
|
if( WeapMesh != none && WeapMesh.SkeletalMesh != none)
|
|
{
|
|
GetFlameSocketLocAndRot(DestinationLocation, DestinationRotation);
|
|
WeapMesh.GetSocketWorldLocationAndRotation('BloodParticlesMidPoint', BloodParticlesMidPointSocketLocation, BloodParticlesMidPointSocketRotation);
|
|
}
|
|
|
|
BloodStolenControlTime += SpawnRateBloodParticles_3P;
|
|
MonsterLocation = ActiveFlameSpray.GetLastContactPositionMeshHit();
|
|
if (IsZero(MonsterLocation))
|
|
{
|
|
Monster.Mesh.GetBoneLocation('Spine1');
|
|
}
|
|
|
|
if(MonsterLocation == vect(0,0,0))
|
|
{
|
|
MonsterLocation = Monster.Location + vect(0,0,20);
|
|
}
|
|
|
|
if (FRand() > 0.4)
|
|
{
|
|
BloodSplashVelocity = BloodParticlesMidPointSocketLocation - MonsterLocation;
|
|
BloodSplashVelocity = VRandCone(vect(0,0,-1), PI / 5) * 100;
|
|
SpawnBloodSplash(BloodSplashClass, MonsterLocation, BloodSplashVelocity);
|
|
}
|
|
|
|
//Emitter = Spawn(class'KFEmit_DirectionalPath',,, MonsterLocation);
|
|
Emitter.ParticleSpeed = SpeedBloodParticles_3P;
|
|
Emitter.RateTickCheckHasReached = 0.2;
|
|
//BloodStolenParticles.AddItem(Emitter);
|
|
Emitter.SetLocation(MonsterLocation);
|
|
|
|
Emitter.SetDestination(DestinationLocation, BloodParticlesMidPointSocketLocation, 20, 20, 50, 50, 0);
|
|
Emitter.ActivateEmitter();
|
|
//Emitter.isEnabled = true;
|
|
|
|
}
|
|
|
|
simulated function SetChargePercentage(float ChargePercentage)
|
|
{
|
|
ChargeRTPC = ChargePercentage;
|
|
bIsCharging = false;
|
|
bIsFullyCharged = false;
|
|
|
|
if (ChargeRTPC >= 0.0)
|
|
{
|
|
bIsCharging = true;
|
|
}
|
|
|
|
if (ChargeRTPC >= 1.0)
|
|
{
|
|
bIsFullyCharged = true;
|
|
}
|
|
}
|
|
|
|
simulated function SetZedCurrentlyBeingSprayed(KFPawn_Monster ZedCurrentlyBeingSprayed)
|
|
{
|
|
oZedPreviouslyBeingSprayed = oZedCurrentlyBeingSprayed;
|
|
oZedCurrentlyBeingSprayed = ZedCurrentlyBeingSprayed;
|
|
}
|
|
|
|
simulated function DisableSprayVisualAndMesh()
|
|
{
|
|
bIsDisabledSprayVisualAndMesh = true;
|
|
}
|
|
|
|
function SpawnBloodSplash( class<KFProj_BloodSplash> SpawnClass, vector SpawnLoc, vector SpawnVel )
|
|
{
|
|
local TraceHitInfo HitInfo;
|
|
local vector HitLocation, HitRotation;
|
|
local KFGoreManager GoreManager;
|
|
|
|
// Grab the gore manager
|
|
GoreManager = KFGoreManager(WorldInfo.MyGoreEffectManager);
|
|
|
|
if (GoreManager == none || oZedCurrentlyBeingSprayed == none)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//EffectStartTrace = Location + vect(0,0,1) * 4.f;
|
|
//EffectEndTrace = EffectStartTrace - vect(0,0,1) * 32.f;
|
|
|
|
// Find where to put the decal
|
|
Trace(HitLocation, HitRotation, SpawnLoc + SpawnVel * 32.f, SpawnLoc, false,, HitInfo, TRACEFLAG_Bullet);
|
|
//DrawDebugLine(SpawnLoc,SpawnLoc + SpawnVel * 32.f,0,255,0,TRUE);
|
|
|
|
// If the locations are zero (probably because this exploded in the air) set defaults
|
|
if( IsZero(HitLocation) )
|
|
{
|
|
HitLocation = Location;
|
|
}
|
|
|
|
if( IsZero(HitRotation) )
|
|
{
|
|
HitRotation = vect(0,0,1);
|
|
}
|
|
|
|
|
|
//Put the decals
|
|
GoreManager.LeaveABloodSplatterDecal(oZedCurrentlyBeingSprayed, HitLocation, HitRotation);
|
|
|
|
//GoreManager. LeaveAPersistentBloodSplat(HitLocation, HitNormal, 1.0);
|
|
|
|
if (oZedCurrentlyBeingSprayed != none)
|
|
{
|
|
GoreManager.CausePersistentBlood(oZedCurrentlyBeingSprayed, class'KFDamageType', HitLocation, vect(0,0,-1), 0, false, false);
|
|
}
|
|
}
|
|
|
|
simulated function RemoveAllBloodParticles()
|
|
{
|
|
local int Index;
|
|
local KFEmit_DirectionalPath EmitterToRemove;
|
|
|
|
for( Index = (NumBloodStolenParticlesForPool - 1) ; Index >= 0 ; Index-- )
|
|
{
|
|
EmitterToRemove = BloodStolenParticles[Index];
|
|
//BloodStolenParticles.Remove(Index, 1);
|
|
EmitterToRemove.DeactivateEmitter();
|
|
}
|
|
}
|
|
|
|
defaultproperties
|
|
{
|
|
ChargeRTPC=0
|
|
bIsChargeEffectsActive=false
|
|
bIsBloodParticlesEffectActive=false
|
|
bIsDisabledSprayVisualAndMesh=false
|
|
MuzzleFlashTemplate=KFMuzzleFlash'WEP_HRG_Vampire_Arch.Wep_HRG_Vampire_MuzzleFlash_3P'
|
|
|
|
ChargingEffect=ParticleSystem'WEP_HRG_Vampire_EMIT.FX_HRG_Vampire_BlobCharge_3P_01'
|
|
ChargedEffect=ParticleSystem'WEP_HRG_Vampire_EMIT.FX_HRG_Vampire_FullCharge'
|
|
|
|
BloodStolenEffect=ParticleSystem'WEP_HRG_Vampire_EMIT.FX_HRG_Vampire_BloodStolen_3P'
|
|
|
|
BloodSplashClass=KFProj_BloodSplash
|
|
|
|
RateUpdateDestinationBloodParticles = 0.7
|
|
|
|
NumBloodStolenParticlesForPool = 15;
|
|
}
|