1
0
KF2-Dev-Scripts/KFGameContent/Classes/KFWeap_HRG_Vampire.uc
2023-09-21 22:31:11 +03:00

1377 lines
40 KiB
Ucode

//=============================================================================
// KFWeap_HRG_Vampire
//=============================================================================
// A gun that sucks zeds blood and use it against them
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
// FFerrando @ saber3d
//=============================================================================
/*
*/
class KFWeap_HRG_Vampire extends KFWeap_FlameBase;
//START BLOOD BALL PROPERTIES
//Props related to charging the weapon
//var float MaxChargeTime;
var float MaxChargeAmmo;
var float ChargeSpeed;
/** While ChargeTime is below this threshold, a static min damage value (MinDamageByCharge) will be used for BloodBall instant damage */
var float MinDamageWhileChargingThreshold;
var float ValueIncreaseTime;
var float DmgIncreasePerCharge;
var float AOEIncreasePerCharge;
var float IncapIncreasePerCharge;
var transient float ChargeTime;
var transient float CurrentCharge;
var transient float CurrentChargeOrigin;
var transient float CurrentChargeDesired;
var transient float CurrentChargeAmmo;
var transient float CurrentChargeAccumulatedTime;
var transient float CurrentChargeForBloodBallProjectile;
var ParticleSystem ChargingEffect;
var ParticleSystem ChargedEffect;
var ParticleSystem BloodStolenEffect;
var const ParticleSystem MuzzleFlashEffectL3;
var transient ParticleSystemComponent FullyChargedPSC;
var transient ParticleSystemComponent ChargingPSC;
var KFEmit_DirectionalPath BloodStolenParticles[15];
var int NumBloodStolenParticlesForPool;
var float SpeedBloodParticlesDefault;
var float SpawnRateBloodParticlesDefault;
var float HalfAngleSpawnConeDefault;
var float CurveTurnRateUntilDestinationMidPointDefault;
var float CurveTurnRateUntilDestinationFinalDefault;
var float LimitDistanceMidPointDefault;
var float LimitDistanceFinalPointDefault;
var transient float BloodStolenControlTime;
//var transient bool bIsFullyCharged;
var transient bool bHasCharged;
var const WeaponFireSndInfo FullyChargedSound;
var const WeaponFireSndInfo ChargingSound;
var const WeaponFireSndInfo ChargedSound;
var const WeaponFireSndInfo BloodSuctionStartSound;
var const WeaponFireSndInfo BloodSuctionEndSound;
var const WeaponFireSndInfo BloodSuctionLoopNoAmmoAndBloodBallChargedSound;
var bool bIsSprayDisabled;
var float SelfDamageReductionValue;
var float FullChargedTimerInterval;
var float ChargePercentage;
/** Value used to lerp projectile damage and scale depending on if ChargePercentage has surpassed MinDamageWhileChargingThreshold */
var float DamageByChargePercentage;
var float MinScale, MaxScale;
var int MaxDamageByCharge;
var int MinDamageByCharge;
const SecondaryFireAnim = 'Alt_Fire';
const SecondaryFireIronAnim = 'Alt_Fire_Iron';
const SecondaryFireAnimEmpty = 'Alt_Fire_Empty';
const SecondaryFireIronAnimEmpty = 'Alt_Fire_Iron_Empty';
var bool bHasToLaunchEmptyAnim;
var SkelControlSingleBone Control;
var bool bBlocked;
//END BLOOD BALL PROPERTIES
/** Shoot animation to play when shooting secondary fire */
var(Animations) const editconst name FireHeavyAnim;
/** Shoot animation to play when shooting secondary fire last shot */
var(Animations) const editconst name FireLastHeavyAnim;
/** Shoot animation to play when shooting secondary fire last shot when aiming */
var(Animations) const editconst name FireLastHeavySightedAnim;
/** Alt-fire explosion template */
var() GameExplosion ExplosionTemplate;
//var float MaxChargeTime, ChargePercentage, ChargeTime;
//var bool bIsFullyCharged;
var float ReplenishingAmmoOnSuctioningTime;
var float ReplenishingAmmoOnSuctioningInterval;
var int ReplenishingAmmoOnSuctioningCount;
var class<KFProjectile> BloodBallProjClass;
var float SpeedBloodParticles;
var float SpawnRateBloodParticles;
var float HalfAngleSpawnCone;
var float CurveTurnRateUntilDestinationMidPoint;
var float CurveTurnRateUntilDestinationFinal;
var float LimitDistanceMidPoint;
var float LimitDistanceFinalPoint;
var float RateUpdateDestinationBloodParticles;
var transient float UpdateDestinationBloodParticlesTime;
var int InitialAmmoSecondaryCount;
/** Variables to scale ammo cost on primary fire (so we can use "floats" on ammo and make ammo has no cost or small cost when no hitting zeds) */
var float AmmoCostScaleDefaultFiremode;
var float AmmoCostAccumulated;
/** Simulate delay in start charging like waiting for first blood particle to arrive */
var transient bool bFirstBloodParticleCreated;
var transient float DelayUntilStartCharging;
var float ScaleDelayUntilStartCharging;
var transient float CurrentStartChargingTime;
var transient bool bIsAlreadyInitializedFX;
var class<KFProj_BloodSplash> BloodSplashClass;
var transient float TimesConsumeAmmoCalled;
var transient bool bIsFullCharged;//Only for using in 1p
var transient bool bIsChargingSoundStarted;//Only for using in authority
Replication
{
if(bNetDirty)
oZedCurrentlyBeingSprayed, ChargeTime, ClientCurrentChargeDesired;
if (bNetDirty && !bNetOwner)
ClientChargePercentage, bClientDisableSprayVisualAndMesh;
}
var KFPawn_Monster oZedPreviouslyBeingSprayed;
/**************************** HRG SPRAY STUFF*/
var repnotify KFPawn_Monster oZedCurrentlyBeingSprayed;
var repnotify float ClientChargePercentage;
var repnotify float ClientCurrentChargeDesired;
var repnotify bool bClientDisableSprayVisualAndMesh;
/*********************** */
simulated event ReplicatedEvent(name VarName)
{
if (VarName == nameof(ClientChargePercentage))
{
NotifyChargePercentage(ClientChargePercentage);
}
if (VarName == nameof(oZedCurrentlyBeingSprayed))
{
NotifyZedCurrentlyBeingSprayed(oZedCurrentlyBeingSprayed);
}
if (VarName == nameof(bClientDisableSprayVisualAndMesh) && bClientDisableSprayVisualAndMesh)
{
NotifyDisableSprayVisualAndMesh();
}
if (VarName == nameof(ClientCurrentChargeDesired))
{
CurrentChargeDesired = ClientCurrentChargeDesired;
}
Super.ReplicatedEvent(VarName);
}
simulated function PostBeginPlay()
{
local KFPawn_Human KFPH;
local int Index;
super.PostBeginPlay();
AmmoCostAccumulated = 0;
KFPH = KFPawn_Human(Instigator);
bIsAlreadyInitializedFX = false;
if (WorldInfo.NetMode == NM_DedicatedServer || (KFPH != none && !KFPH.IsFirstPerson()))
{
return;
}
UpdateDestinationBloodParticlesTime = RateUpdateDestinationBloodParticles;
bFirstBloodParticleCreated = false;
CurrentStartChargingTime = DelayUntilStartCharging * ScaleDelayUntilStartCharging;
for( Index = (NumBloodStolenParticlesForPool - 1) ; Index >= 0 ; Index-- )
{
BloodStolenParticles[Index] = Spawn(class'KFEmit_DirectionalPath');
BloodStolenParticles[Index].SetTemplate(BloodStolenEffect, true);
//BloodStolenParticles[Index].IsEnabled=false;
BloodStolenParticles[Index].DeactivateEmitter();
}
}
simulated event Tick(float DeltaTime)
{
return;
}
/** Handle one-hand fire anims */
simulated function name GetWeaponFireAnim(byte FireModeNum)
{
local bool bPlayFireLast;
bPlayFireLast = ShouldPlayFireLast(FireModeNum);
if ( FireModeNum == CUSTOM_FIREMODE )
{
return FireLoopEndAnim;
}
if ( bUsingSights )
{
if( bPlayFireLast )
{
if ( FireModeNum == ALTFIRE_FIREMODE )
{
return FireLastHeavySightedAnim;
}
else
{
return FireLastSightedAnim;
}
}
else
{
return FireSightedAnims[FireModeNum];
}
}
else
{
if( bPlayFireLast )
{
if ( FireModeNum == ALTFIRE_FIREMODE )
{
return FireLastHeavyAnim;
}
else
{
return FireLastAnim;
}
}
else
{
if ( FireModeNum == ALTFIRE_FIREMODE )
{
return FireHeavyAnim;
}
else
{
return FireAnim;
}
}
}
}
/**
* Instead of a toggle, just immediately fire alternate fire.
*/
simulated function AltFireMode()
{
// LocalPlayer Only
if ( !Instigator.IsLocallyControlled() )
{
return;
}
StartFire(ALTFIRE_FIREMODE);
}
/** Disable auto-reload for alt-fire */
simulated function bool ShouldAutoReload(byte FireModeNum)
{
local bool bRequestReload;
bRequestReload = Super.ShouldAutoReload(FireModeNum);
// Must be completely empty for auto-reload or auto-switch
if ( FireModeNum == ALTFIRE_FIREMODE && AmmoCount[DEFAULT_FIREMODE] > 0 )
{
bPendingAutoSwitchOnDryFire = false;
return false;
}
return bRequestReload;
}
static simulated event EFilterTypeUI GetTraderFilter()
{
return FT_Projectile;
}
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 = self;
}
if( FlamePool[1] != None && KFSprayActor_HRG_Vampire(FlamePool[1]) != None && KFSprayActor_HRG_Vampire(FlamePool[1]).OwnerWeapon == None)
{
KFSprayActor_HRG_Vampire(FlamePool[1]).OwnerWeapon = self;
}
}
simulated function float FlameHeatCalc()
{
//hack in order to make the arc gen always glow
LastBarrelHeat = 1.0f;
return 1.0f;
}
simulated function SetCurrentSprayedZed(KFPawn_Monster _Monster)
{
if(role != role_authority && WorldInfo.NetMode != NM_ListenServer && WorldInfo.NetMode != NM_StandAlone)
{
return;
}
oZedPreviouslyBeingSprayed = oZedCurrentlyBeingSprayed;
oZedCurrentlyBeingSprayed = _Monster;
bNetDirty=true;
AmmoCostScaleDefaultFiremode=1.0;
if (oZedCurrentlyBeingSprayed == none || !oZedCurrentlyBeingSprayed.IsAliveAndWell())
{
AmmoCostScaleDefaultFiremode=default.AmmoCostScaleDefaultFiremode;
}
}
/**
* Drop this item out in to the world
*/
function DropFrom(vector StartLocation, vector StartVelocity)
{
super.DropFrom(StartLocation, StartVelocity);
self.SetTickIsDisabled(true);
}
function SetOriginalValuesFromPickup( KFWeapon PickedUpWeapon )
{
super.SetOriginalValuesFromPickup(PickedUpWeapon);
self.SetTickIsDisabled(false);
}
/**
* Functions to notify KFWeapAttach (used for 3P FX) about state
*/
simulated function NotifyChargePercentage(float ChargePercentageNotified)
{
local KFPawn KFPawn;
local KFWeapAttach_HRG_Vampire KFWeapAttach;
KFPawn = KFPawn(Instigator);
KFWeapAttach = KFWeapAttach_HRG_Vampire(KFPawn.WeaponAttachment);
if(KFWeapAttach != none)
{
KFWeapAttach.SetChargePercentage(ChargePercentageNotified);
}
}
simulated function NotifyZedCurrentlyBeingSprayed(KFPawn_Monster Monster)
{
local KFPawn KFPawn;
local KFWeapAttach_HRG_Vampire KFWeapAttach;
KFPawn = KFPawn(Instigator);
KFWeapAttach = KFWeapAttach_HRG_Vampire(KFPawn.WeaponAttachment);
if(KFWeapAttach != none)
{
KFWeapAttach.SetZedCurrentlyBeingSprayed(Monster);
}
}
simulated function NotifyDisableSprayVisualAndMesh()
{
local KFPawn KFPawn;
local KFWeapAttach_HRG_Vampire KFWeapAttach;
KFPawn = KFPawn(Instigator);
KFWeapAttach = KFWeapAttach_HRG_Vampire(KFPawn.WeaponAttachment);
if(KFWeapAttach != none)
{
KFWeapAttach.DisableSprayVisualAndMesh();
}
}
simulated function CreateBloodParticle(KFPawn_Monster Monster)
{
Local KFEmit_DirectionalPath Emitter;
local vector DestinationLocation, MonsterLocation, BloodParticlesMidPointSocketLocation;
local Rotator DestinationRotation, BloodParticlesMidPointSocketRotation;
local vector BloodSplashVelocity;
local int Index;
if (!IsInState('FiringSuctioning'))
{
return;
}
Emitter = none;
for( Index = (NumBloodStolenParticlesForPool - 1) ; Index >= 0 ; Index-- )
{
if(BloodStolenParticles[Index].IsEnabled == false)
{
Emitter = BloodStolenParticles[Index];
break;
}
}
if(Emitter == none)
{
return;
}
if(MySkelMesh != none)
{
GetFlameSocketLocAndRot(DestinationLocation, DestinationRotation);
MySkelMesh.GetSocketWorldLocationAndRotation('BloodParticlesMidPoint', BloodParticlesMidPointSocketLocation, BloodParticlesMidPointSocketRotation);
}
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;
//BloodStolenParticles.AddItem(Emitter);
Emitter.SetLocation(MonsterLocation);
Emitter.SetDestination( DestinationLocation,
BloodParticlesMidPointSocketLocation,
LimitDistanceFinalPoint,
LimitDistanceMidPoint,
CurveTurnRateUntilDestinationFinal,
CurveTurnRateUntilDestinationMidPoint,
HalfAngleSpawnCone);
Emitter.ActivateEmitter();
//Emitter.isEnabled = true;
}
simulated 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();
}
}
simulated function OnStartFire()
{
local KFPawn PawnInst;
PawnInst = KFPawn(Instigator);
if (PawnInst != none)
{
PawnInst.OnStartFire();
}
}
simulated function InitBloodBallFX()
{
if (FullyChargedPSC == none)
{
FullyChargedPSC = new(self) class'ParticleSystemComponent';
if(MySkelMesh != none)
{
MySkelMesh.AttachComponentToSocket(FullyChargedPSC, 'MuzzleFlash');
}
else
{
AttachComponent(FullyChargedPSC);
}
FullyChargedPSC.SetTemplate(ChargedEffect);
}
FullyChargedPSC.SetActive( false );
if (ChargingPSC == none)
{
ChargingPSC = new(self) class'ParticleSystemComponent';
if(MySkelMesh != none)
{
MySkelMesh.AttachComponentToSocket(ChargingPSC, 'MuzzleFlash');
}
else
{
AttachComponent(ChargingPSC);
}
ChargingPSC.SetTemplate(ChargingEffect);
}
ChargingPSC.SetActive( false );
}
// Placing the actual Weapon Firing end state here since we need it to happen at the end of the actual firing loop.
simulated function Timer_StopFireEffects()
{
// Simulate weapon firing effects on the local client
if (WorldInfo.NetMode == NM_Client)
{
Instigator.WeaponStoppedFiring(self, false);
}
ClearFlashCount();
ClearFlashLocation();
}
simulated function name GetLoopEndFireAnim(byte FireModeNum)
{
if (FireModeNum == DEFAULT_FIREMODE)
{
return '';
}
return super.GetLoopEndFireAnim(FireModeNum);
}
simulated function KFProjectile SpawnProjectile(class<KFProjectile> KFProjClass, vector RealStartLoc, vector AimDir)
{
local KFProj_BloodBall_HRG_Vampire BloodBall;
local KFProjectile Projectile;
Projectile = super.SpawnProjectile(KFProjClass, RealStartLoc, AimDir);
BloodBall = KFProj_BloodBall_HRG_Vampire(Projectile);
//Calc and set scaling values
if (BloodBall != none)
{
BloodBall.SetInheritedScale(CurrentChargeForBloodBallProjectile, DamageByChargePercentage);
return BloodBall;
}
//If reaches here, projectile will be CRYSTALIZED SPIKE
return Projectile;
}
simulated function DisableRecoil()
{
maxRecoilPitch = 0;
minRecoilPitch = 0;
maxRecoilYaw = 0;
minRecoilYaw = 0;
}
simulated function RestoreRecoil()
{
maxRecoilPitch = default.maxRecoilPitch;
minRecoilPitch = default.minRecoilPitch;
maxRecoilYaw = default.maxRecoilYaw;
minRecoilYaw = default.minRecoilYaw;
}
function InitializeAmmo()
{
super.InitializeAmmo();
AmmoCount[1] = InitialAmmoSecondaryCount;
}
simulated function ConsumeAmmo( byte FireModeNum )
{
local byte AmmoType;
local KFPerk InstigatorPerk;
if (FireModeNum == DEFAULT_FIREMODE)
{
//Code from super.ConsumeAmmo()
`if(`notdefined(ShippingPC))
if( bInfiniteAmmo )
{
return;
}
`endif
AmmoType = GetAmmoType(FireModeNum);
InstigatorPerk = GetPerk();
if( InstigatorPerk != none && InstigatorPerk.GetIsUberAmmoActive( self ) )
{
return;
}
TimesConsumeAmmoCalled+=AmmoCost[FireModeNum];
// If AmmoCount is being replicated, don't allow the client to modify it here
if ( Role == ROLE_Authority || bAllowClientAmmoTracking )
{
// Don't consume ammo if magazine size is 0 (infinite ammo with no reload)
if (MagazineCapacity[AmmoType] > 0 && AmmoCount[AmmoType] > 0)
{
AmmoCostAccumulated += AmmoCost[FireModeNum] * AmmoCostScaleDefaultFiremode;
CurrentChargeDesired = FMin(1.0, (float(AmmoConsumed) + AmmoCostAccumulated) / MaxChargeAmmo);
if (CurrentChargeDesired > 0)
{
bHasCharged = true;
}
if (WorldInfo.NetMode == NM_DedicatedServer)
{
ClientCurrentChargeDesired = CurrentChargeDesired;
}
if (AmmoCostAccumulated >= AmmoCost[FireModeNum])
{
AmmoCostAccumulated=0;
AmmoConsumed+=AmmoCost[CurrentFireMode];
CurrentChargeDesired = FMin(1.0, float(AmmoConsumed) / MaxChargeAmmo);
if (WorldInfo.NetMode == NM_DedicatedServer)
{
ClientCurrentChargeDesired = CurrentChargeDesired;
}
// Ammo cost needs to be firemodenum because it is independent of ammo type.
AmmoCount[AmmoType] = Max(AmmoCount[AmmoType] - AmmoCost[FireModeNum], 0);
}
}
}
return;
}
else
{
super.ConsumeAmmo(FireModeNum);
}
}
simulated function Timer_CreateBloodParticle()
{
if (oZedCurrentlyBeingSprayed != none && oZedCurrentlyBeingSprayed.IsAliveAndWell())
{
CreateBloodParticle(oZedCurrentlyBeingSprayed);
}
}
simulated state FiringSuctioning extends SprayingFire
{
// Overriden to not call FireAmmunition right at the start of the state
simulated event BeginState( Name PreviousStateName )
{
Super.BeginState(PreviousStateName);
NotifyBeginState();
if ( KFPawn(Owner).IsLocallyControlled() )
{
PlaySoundBase(BloodSuctionStartSound.FirstPersonCue);
}
else
{
PlaySoundBase(BloodSuctionStartSound.DefaultCue);
}
CurrentCharge = 0;
bHasCharged = false;
global.OnStartFire();
bIsSprayDisabled = false;
AmmoCostScaleDefaultFiremode=default.AmmoCostScaleDefaultFiremode;
CurrentCharge = 0;
CurrentChargeOrigin = 0;
CurrentChargeDesired = 0;
CurrentChargeForBloodBallProjectile = 0;
if (WorldInfo.NetMode == NM_DedicatedServer)
{
ClientCurrentChargeDesired = 0;
}
TimesConsumeAmmoCalled = 0;
bIsChargingSoundStarted = false;
}
simulated function EndState(Name NextStateName)
{
local KFPawn_Human KFPH;
Super.EndState(NextStateName);
NotifyEndState();
ClearZedTimeResist();
ClearPendingFire(CurrentFireMode);
ClearTimer(nameof(RefireCheckTimer));
KFPawn(Instigator).bHasStartedFire = false;
KFPawn(Instigator).bNetDirty = true;
if (oZedCurrentlyBeingSprayed == None || !oZedCurrentlyBeingSprayed.IsAliveAndWell())
{
if ( KFPawn(Owner).IsLocallyControlled() )
{
PlaySoundBase(BloodSuctionEndSound.FirstPersonCue);
}
else
{
PlaySoundBase(BloodSuctionEndSound.DefaultCue);
}
}
KFPawn(Instigator).SetWeaponAmbientSound(none);
KFPawn(Instigator).SetSecondaryWeaponAmbientSound(none);
//BLOOD PARTICLES AND BALL MANAGEMENT
KFPH = KFPawn_Human(Instigator);
if (!(WorldInfo.NetMode == NM_DedicatedServer) || !(KFPH != none && !KFPH.IsFirstPerson()))
{
RemoveAllBloodParticles();
CurrentChargeAccumulatedTime = 0;
if( ChargingPSC != none)
{
ChargingPSC.SetActive( false );
}
if (FullyChargedPSC != none)
{
FullyChargedPSC.SetActive( false );
}
}
CurrentChargeForBloodBallProjectile = CurrentChargeDesired;
CurrentCharge = 0;
CurrentChargeOrigin = 0;
CurrentChargeDesired = 0;
}
simulated function bool ShouldRefire()
{
if (!HasAmmo(CurrentFireMode))
{
return StillFiring(CurrentFireMode);
}
return StillFiring(CurrentFireMode) || TimesConsumeAmmoCalled < MinAmmoConsumed;
}
simulated function ConsumeAmmo( byte FireMode )
{
global.ConsumeAmmo(FireMode);
}
simulated event Tick(float DeltaTime)
{
//In this tick enters:
//- Role == Role_Authority
//- WorldInfo.NetMode == NM_DedicatedServer
//- WorldInfo.NetMode == NM_StandAlone
//Blood particle variables
local int Index;
local vector MuzzleFlashSocketLocation, BloodParticlesMidPointSocketLocation;
local Rotator DestinationRotation, BloodParticlesMidPointSocketRotation;
local KFEmit_DirectionalPath EmitterToRemove;
local vector VectorParameterParticle;
local vector BloodSplashVelocity;
local KFPawn_Human KFPH;
//Charging variables
local vector ChargePercentageVector;
local float InstantHitDamageValue;
Super.Tick(DeltaTime);
if (!HasAmmo(CurrentFireMode) && !bIsSprayDisabled)
{
if (CurrentChargeDesired <= 0)
{
GoToState('Active');
}
else
{
TurnOffFireSpray();
KFPawn(Instigator).SetWeaponAmbientSound(BloodSuctionLoopNoAmmoAndBloodBallChargedSound.DefaultCue, BloodSuctionLoopNoAmmoAndBloodBallChargedSound.FirstPersonCue);
KFPawn(Instigator).SetSecondaryWeaponAmbientSound(None, None);
oZedCurrentlyBeingSprayed = none;
DisableRecoil();
bIsSprayDisabled = true;
bClientDisableSprayVisualAndMesh=true;
}
}
if(oZedCurrentlyBeingSprayed == none)
{
bIsChargingSoundStarted = false;
KFPawn(Instigator).SetSecondaryWeaponAmbientSound(None, None);
}
if(oZedCurrentlyBeingSprayed != none && oZedCurrentlyBeingSprayed.IsAliveAndWell())
{
//Replenishing secondary ammo
ReplenishingAmmoOnSuctioningTime -= DeltaTime;
if (ReplenishingAmmoOnSuctioningTime <= 0)
{
AmmoCount[ALTFIRE_FIREMODE] = Min(MagazineCapacity[ALTFIRE_FIREMODE], AmmoCount[ALTFIRE_FIREMODE] + ReplenishingAmmoOnSuctioningCount);
ReplenishingAmmoOnSuctioningTime += ReplenishingAmmoOnSuctioningInterval;
}
//Scaling damage values depending on charge
if (CurrentChargeDesired > 0)
{
DamageByChargePercentage = FMin((CurrentChargeDesired - MinDamageWhileChargingThreshold)/(1 - MinDamageWhileChargingThreshold), 1);
InstantHitDamageValue = FMax(MinDamageByCharge, Lerp(MinDamageByCharge, MaxDamageByCharge, DamageByChargePercentage ));
InstantHitDamage[CUSTOM_FIREMODE] = InstantHitDamageValue;//TODO
InstantHitDamageTypes[CUSTOM_FIREMODE]=class'KFDT_Ballistic_HRG_Vampire_BloodBallImpact';
if(CurrentChargeDesired >= 1.0)
{
InstantHitDamageTypes[CUSTOM_FIREMODE]=class'KFDT_Ballistic_HRG_Vampire_BloodBallHeavyImpact';
}
KFPawn(Instigator).SetWeaponComponentRTPCValue("Weapon_Charge", CurrentChargeDesired); //For looping component
Instigator.SetRTPCValue('Weapon_Charge', CurrentChargeDesired); //For one-shot sounds
if (WorldInfo.NetMode == NM_DedicatedServer)
{
ClientChargePercentage = CurrentChargeDesired;
}
if (!bIsChargingSoundStarted)
{
KFPawn(Instigator).SetSecondaryWeaponAmbientSound(ChargingSound.DefaultCue, ChargingSound.FirstPersonCue);
}
bIsChargingSoundStarted = true;
}
}
//BLOOD PARTICLES AND BALL MANAGEMENT
KFPH = KFPawn_Human(Instigator);
if (WorldInfo.NetMode == NM_DedicatedServer || (KFPH != none && !KFPH.IsFirstPerson()))
{
return;
}
//Blood Ball and Blood Particles are managed here for 1P offline and 1P online.
//Blood particles updating destination and removing, and spawning blood splashes.
UpdateDestinationBloodParticlesTime -= DeltaTime;
if (UpdateDestinationBloodParticlesTime <= 0)
{
UpdateDestinationBloodParticlesTime = RateUpdateDestinationBloodParticles;
GetFlameSocketLocAndRot(MuzzleFlashSocketLocation, DestinationRotation);
if(MySkelMesh != none)
{
MySkelMesh.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.8)
{
BloodSplashVelocity.x = 0;
BloodSplashVelocity.y = RandRange(-100, 100);
BloodSplashVelocity.z = -200;
SpawnBloodSplash(BloodSplashClass, BloodStolenParticles[Index].Location, BloodSplashVelocity);
}
}
}
}
for( Index = (NumBloodStolenParticlesForPool - 1) ; Index >= 0 ; Index-- )
{
if(BloodStolenParticles[Index].IsEnabled == true)
{
bFirstBloodParticleCreated=true;
}
}
CurrentStartChargingTime = FMax(0, CurrentStartChargingTime - DeltaTime);
if (CurrentChargeDesired > 0 && CurrentStartChargingTime <= 0)
{
CurrentChargeAccumulatedTime = FMin(CurrentChargeAccumulatedTime + DeltaTime * ChargeSpeed, CurrentChargeDesired);
CurrentCharge = CurrentChargeAccumulatedTime;
}
if ( CurrentCharge > 0 )
{
if( ChargingPSC != none)
{
ChargingPSC.SetActive( true, true );
ChargePercentageVector.X = CurrentCharge;
ChargePercentageVector.Y = CurrentCharge;
ChargePercentageVector.Z = CurrentCharge;
ChargingPSC.SetVectorParameter( name("BlobCharge"), ChargePercentageVector );
}
if (FullyChargedPSC != none && CurrentCharge >= 1.0)
{
if (!bIsFullCharged)
{
//WeaponPlaySound(ChargedSound.FirstPersonCue);
//PlaySoundBase(BloodSuctionEndSound.DefaultCue);
if ( KFPawn(Owner).IsLocallyControlled() )
{
PlaySoundBase(ChargedSound.FirstPersonCue);
}
else
{
PlaySoundBase(ChargedSound.DefaultCue);
}
}
bIsFullCharged = true;
FullyChargedPSC.SetActive( true, true );
}
}
}
simulated function HandleFinishedFiring()
{
if (bPlayingLoopingFireAnim)
{
StopLoopingFireEffects(CurrentFireMode);
}
SetTimer(0.1f, false, 'Timer_StopFireEffects');
NotifyWeaponFinishedFiring(CurrentFireMode);
super.HandleFinishedFiring();
}
simulated function PutDownWeapon()
{
if (bPlayingLoopingFireAnim)
{
StopLoopingFireEffects(CurrentFireMode);
}
SetTimer(0.1f, false, 'Timer_StopFireEffects');
NotifyWeaponFinishedFiring(CurrentFireMode);
super.PutDownWeapon();
}
}
simulated state Active
{
simulated event BeginState( Name PreviousStateName )
{
local KFPawn KFPawn;
local KFWeapAttach_HRG_Vampire KFWeapAttach;
//Safest place to start firing Blood Ball (after finishing all logic for Blood Suck firing)
if (PreviousStateName == 'FiringSuctioning' && Role == Role_Authority && bHasCharged)
{
StartFire(CUSTOM_FIREMODE);
}
super.BeginState(PreviousStateName);
RestoreRecoil();
bClientDisableSprayVisualAndMesh = false;
bHasCharged = false;
bIsFullCharged = false;
if (WorldInfo.NetMode == NM_DedicatedServer || bIsAlreadyInitializedFX)
{
return;
}
//All of the following would make more sense to initialize it in PostBeginPlay, but at that moment KFPawn.WeaponAttachment and MySkelMesh are not populated
//Setting parameters for blood particles from 3P attachment
KFPawn = KFPawn(Instigator);
KFWeapAttach = KFWeapAttach_HRG_Vampire(KFPawn.WeaponAttachment);
if (KFWeapAttach != None)
{
SpeedBloodParticles = KFWeapAttach.SpeedBloodParticles;
SpawnRateBloodParticles = KFWeapAttach.SpawnRateBloodParticles;
HalfAngleSpawnCone = KFWeapAttach.HalfAngleSpawnCone;
CurveTurnRateUntilDestinationMidPoint = KFWeapAttach.CurveTurnRateUntilDestinationMidPoint;
CurveTurnRateUntilDestinationFinal = KFWeapAttach.CurveTurnRateUntilDestinationFinal;
LimitDistanceMidPoint = KFWeapAttach.LimitDistanceMidPoint;
LimitDistanceFinalPoint = KFWeapAttach.LimitDistanceFinalPoint;
}
if (SpeedBloodParticles <= 0)
{
SpeedBloodParticles = SpeedBloodParticlesDefault;
}
if (SpawnRateBloodParticles <= 0)
{
SpawnRateBloodParticles = SpawnRateBloodParticlesDefault;
}
if (HalfAngleSpawnCone <= 0)
{
HalfAngleSpawnCone = HalfAngleSpawnConeDefault;
}
if (CurveTurnRateUntilDestinationMidPoint <= 0)
{
CurveTurnRateUntilDestinationMidPoint = CurveTurnRateUntilDestinationMidPointDefault;
}
if (CurveTurnRateUntilDestinationFinal <= 0)
{
CurveTurnRateUntilDestinationFinal = CurveTurnRateUntilDestinationFinalDefault;
}
if (LimitDistanceMidPoint <= 0)
{
LimitDistanceMidPoint = LimitDistanceMidPointDefault;
}
if (LimitDistanceFinalPoint <= 0)
{
LimitDistanceFinalPoint = LimitDistanceFinalPointDefault;
}
if (KFPawn != none && !KFPawn.IsFirstPerson())
{
return;
}
InitBloodBallFX();
SetTimer(SpawnRateBloodParticles, true, nameOf(Timer_CreateBloodParticle));
bIsAlreadyInitializedFX = true;
}
}
simulated function PerformReload(optional byte FireModeNum)
{
super.PerformReload(FireModeNum);
//Ammo is count on server. If reload finishes in client before ammo value comes from server, it will not fire if it is pending fire. This is a fix.
if(role != role_authority && WorldInfo.NetMode != NM_ListenServer && WorldInfo.NetMode != NM_StandAlone)
{
SetTimer(0.09f, true, nameOf(Timer_CheckPendingFire));
SetTimer(0.5f, false, nameOf(Timer_EndCheckPendingFire));
}
}
simulated function Timer_CheckPendingFire()
{
local int i;
for( i=0; i<GetPendingFireLength(); i++ )
{
if( PendingFire(i) )
{
BeginFire(i);
ClearTimer(nameOf(Timer_CheckPendingFire));
break;
}
}
}
simulated function Timer_EndCheckPendingFire()
{
ClearTimer(nameOf(Timer_CheckPendingFire));
}
defaultproperties
{
BloodBallProjClass=class'KFProj_BloodBall_HRG_Vampire'
FlameSprayArchetype=KFSprayActor_HRG_Vampire'WEP_HRG_Vampire_ARCH.WEP_HRG_Vampire_Spray'
// Shooting Animations (Alternate)
bHasFireLastAnims=true
FireSightedAnims[0]=Shoot
FireSightedAnims[1]=Shoot_Heavy_Iron
FireLastHeavySightedAnim=Shoot_Heavy_Iron_Last
FireHeavyAnim=Shoot_Heavy
FireLastHeavyAnim=Shoot_Heavy_Last
// Shooting Animations Last (Default)
FireLoopEndLastAnim=ShootLoop_End;
FireLoopEndLastSightedAnim=ShootLoop_Iron_End;
// FOV
Meshfov=80
MeshIronSightFOV=65 //52
PlayerIronSightFOV=50 //80
// Zooming/Position
PlayerViewOffset=(X=20.0,Y=12,Z=-1)
IronSightPosition=(X=0,Y=0,Z=0)
// Depth of field
DOF_FG_FocalRadius=150
DOF_FG_MaxNearBlurSize=1
// Content
PackageKey="HRG_Vampire"
FirstPersonMeshName="WEP_1P_HRG_Vampire_MESH.Wep_1stP_HRG_Vampire_Rig"
FirstPersonAnimSetNames(0)="WEP_1P_HRG_Vampire_Anim.Wep_1stP_HRG_Vampire_Anim"
PickupMeshName="WEP_3P_HRG_Vampire_MESH.Wep_3rdP_HRG_Vampire_Pickup"
AttachmentArchetypeName="WEP_HRG_Vampire_ARCH.WEP_HRG_Vampire_3P"
MuzzleFlashTemplateName="WEP_HRG_Vampire_ARCH.Wep_HRG_Vampire_MuzzleFlash"
// Ammo
MagazineCapacity[0]=40 //50
SpareAmmoCapacity[0]=240 //280 //350 //300
InitialSpareMags[0]=1
AmmoPickupScale[0]=1
MagazineCapacity[1]=100
SpareAmmoCapacity[1]=0
InitialSpareMags[1]=0
InitialAmmoSecondaryCount=0;
bCanRefillSecondaryAmmo=FALSE;
bCanBeReloaded=true
bReloadFromMagazine=true
// Recoil
maxRecoilPitch=115 //150
minRecoilPitch=75 //115
maxRecoilYaw=75 //115
minRecoilYaw=-75 //-115
RecoilRate=0.085
RecoilMaxYawLimit=500
RecoilMinYawLimit=65034
RecoilMaxPitchLimit=900
RecoilMinPitchLimit=65035
RecoilISMaxYawLimit=75
RecoilISMinYawLimit=65460
RecoilISMaxPitchLimit=375
RecoilISMinPitchLimit=65460
RecoilViewRotationScale=0.25
IronSightMeshFOVCompensationScale=1.5
HippedRecoilModifier=1.5
// Inventory
InventorySize=8 //9
GroupPriority=100
WeaponSelectTexture=Texture2D'WEP_UI_HRG_Vampire_TEX.UI_WeaponSelect_HRG_Vampire'
// DEFAULT_FIREMODE
//FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Flamethrower'
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_MedicDart'
FiringStatesArray(DEFAULT_FIREMODE)=FiringSuctioning
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_Custom
FireInterval(DEFAULT_FIREMODE)=+0.1 // 600 RPM
AmmoCostScaleDefaultFiremode=0.0;
MinAmmoConsumed=4 //3
FireOffset=(X=30,Y=4.5,Z=-5)
// ALT_FIREMODE
FireModeIconPaths(ALTFIRE_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Vampire'
FiringStatesArray(ALTFIRE_FIREMODE)=WeaponSingleFiring
WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Projectile
WeaponProjectiles(ALTFIRE_FIREMODE)=class'KFProj_CrystalSpike_HRG_Vampire'
InstantHitDamage(ALTFIRE_FIREMODE)=320 //250
InstantHitDamageTypes(ALTFIRE_FIREMODE)=class'KFDT_Piercing_HRG_Vampire_CrystalSpike'
FireInterval(ALTFIRE_FIREMODE)=+0.22 // 269 RPM
AmmoCost(ALTFIRE_FIREMODE)=20 //25
PenetrationPower(ALTFIRE_FIREMODE)=2.0
SecondaryAmmoTexture=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Vampire'
// CUSTOM_FIREMODE
//FireModeIconPaths(CUSTOM_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Electricity'
FiringStatesArray(CUSTOM_FIREMODE)=WeaponSingleFiring
WeaponFireTypes(CUSTOM_FIREMODE)=EWFT_Projectile
WeaponProjectiles(CUSTOM_FIREMODE)=class'KFProj_BloodBall_HRG_Vampire'
InstantHitDamage(CUSTOM_FIREMODE)=150
InstantHitDamageTypes(CUSTOM_FIREMODE)=class'KFDT_Ballistic_HRG_Vampire_BloodBallImpact'
FireInterval(CUSTOM_FIREMODE)=+0.22 //+0.22
AmmoCost(CUSTOM_FIREMODE)=0
InstantHitMomentum(CUSTOM_FIREMODE)=50000.0
// BASH_FIREMODE
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_HRG_Vampire'
InstantHitDamage(BASH_FIREMODE)=26
// Fire Effects
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_HRG_Vampire.Play_WEP_HRG_Vampire_Suck_Loop_3P', FirstPersonCue=AkEvent'WW_WEP_HRG_Vampire.Play_WEP_HRG_Vampire_Suck_Loop_1P')
WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_HRG_Vampire.Play_WEP_HRG_Vampire_3P_AltFire', FirstPersonCue=AkEvent'WW_WEP_HRG_Vampire.Play_WEP_HRG_Vampire_1P_AltFire')
WeaponFireSnd(CUSTOM_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_HRG_Vampire.Play_WEP_HRG_Vampire_3P_Shoot', FirstPersonCue=AkEvent'WW_WEP_HRG_Vampire.Play_WEP_HRG_Vampire_1P_Shoot')
//@todo: add akevents when we have them
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_SA_Microwave_Gun.Play_SA_MicrowaveGun_DryFire'
WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_SA_Microwave_Gun.Play_SA_MicrowaveGun_DryFire'
WeaponDryFireSnd(CUSTOM_FIREMODE)=None
// Advanced (High RPM) Fire Effects
bLoopingFireAnim(DEFAULT_FIREMODE)=true
bLoopingFireSnd(DEFAULT_FIREMODE)=true
SingleFireSoundIndex=FIREMODE_NONE
// Attachments
bHasIronSights=true
bHasFlashlight=false
AssociatedPerkClasses(0)=class'KFPerk_FieldMedic'
BonesToLockOnEmpty=(RW_Handle1, RW_BatteryCylinder1, RW_BatteryCylinder2, RW_LeftArmSpinner, RW_RightArmSpinner, RW_LockEngager2, RW_LockEngager1)
// AI Warning
bWarnAIWhenFiring=true
MaxAIWarningDistSQ=2250000
// Weapon Upgrade stat boosts
//WeaponUpgrades[1]=(IncrementDamage=1.15f,IncrementWeight=1)
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Damage1, Scale=1.15f), (Stat=EWUS_Weight, Add=1)))
UpgradeFireModes(CUSTOM_FIREMODE)=0
oZedCurrentlyBeingSprayed=none;
bAlwaysRelevant = true
bOnlyRelevantToOwner = false
bAllowClientAmmoTracking=false
// Replenishing secondary ammo while using primary firing
ReplenishingAmmoOnSuctioningTime=0;
ReplenishingAmmoOnSuctioningInterval=0.04; //0.075; //0.2;
ReplenishingAmmoOnSuctioningCount=1; //4;
BloodSuctionStartSound=(DefaultCue = AkEvent'WW_WEP_HRG_Vampire.Play_WEP_HRG_Vampire_SuckBlood_3P_Start', FirstPersonCue=AkEvent'WW_WEP_HRG_Vampire.Play_WEP_HRG_Vampire_1P_Start')
BloodSuctionEndSound=(DefaultCue = AkEvent'WW_WEP_HRG_Vampire.Play_WEP_HRG_Vampire_3P_End', FirstPersonCue=AkEvent'WW_WEP_HRG_Vampire.Play_WEP_HRG_Vampire_1P_End')
BloodSuctionLoopNoAmmoAndBloodBallChargedSound=(DefaultCue = AkEvent'WW_WEP_HRG_Vampire.Play_WEP_HRG_Vampire_SuckBlood_Charged_Loop_3P', FirstPersonCue=AkEvent'WW_WEP_HRG_Vampire.Play_WEP_HRG_Vampire_SuckBlood_Charged_Loop_1P')
//BLOOD BALL
ChargingSound=(DefaultCue = AkEvent'WW_WEP_HRG_Vampire.Play_WEP_HRG_Vampire_SuckBlood_Loop_3P', FirstPersonCue=AkEvent'WW_WEP_HRG_Vampire.Play_WEP_HRG_Vampire_SuckBlood_Loop_1P')
ChargedSound=(DefaultCue = AkEvent'WW_WEP_HRG_Vampire.Play_WEP_HRG_Vampire_SuckBlood_Charged_3P', FirstPersonCue=AkEvent'WW_WEP_HRG_Vampire.Play_WEP_HRG_Vampire_SuckBlood_Charged_1P')
SelfDamageReductionValue=0.1f
//MaxChargeTime=0.6 //0.8
MinDamageWhileChargingThreshold=0.12 //10% of MaxChargeTime
ValueIncreaseTime=0.2 //NOT USED
MaxDamageByCharge=150
MinDamageByCharge=15
ChargingEffect=ParticleSystem'WEP_HRG_Vampire_EMIT.FX_HRG_Vampire_BlobCharge_01'
ChargedEffect=ParticleSystem'WEP_HRG_Vampire_EMIT.FX_HRG_Vampire_FullCharge'
FullChargedTimerInterval=2.0f
MinScale=0.5
MaxScale=4.5//1.5 is the good value
bBlocked = false
//default values for blood particles params in case there is no value set in KFWeapAttach_HRG_Vampire or is below 0
SpawnRateBloodParticlesDefault = 0.1
SpeedBloodParticlesDefault = 750
HalfAngleSpawnConeDefault = 45
CurveTurnRateUntilDestinationMidPointDefault = 0.6
CurveTurnRateUntilDestinationFinalDefault = 4.0
LimitDistanceMidPointDefault = 16
LimitDistanceFinalPointDefault = 12
BloodStolenEffect=ParticleSystem'WEP_HRG_Vampire_EMIT.FX_HRG_Vampire_BloodStolen'
RateUpdateDestinationBloodParticles = 0.2
ScaleDelayUntilStartCharging=0.2 //0.29 //0.5
MaxChargeAmmo=10 //15
ChargeSpeed=1.0
BloodSplashClass=KFProj_BloodSplash
NumBloodStolenParticlesForPool = 15
bForceCrosshair=true
}