//============================================================================= // KFProj_BrokenFlare_HRGScorcher //============================================================================= // Shotgun pellet class for the HRG Scorcher //============================================================================= // Killing Floor 2 // Copyright (C) 2020 Tripwire Interactive LLC // Roberto Moreno (Saber Interactive) //============================================================================= class KFProj_BrokenFlare_HRGScorcher extends KFProjectile hidedropdown; /** Speed when residual flames are dropped during projectile flight */ var vector SpeedDirectionResidualFlames; /** Amount of residual flames to drop during flight * This is the max number, if the projectile is interrupted before reaching the max, the left residual numbers will NOT be spawned. * This value can NOT be 0 or 1. */ var int AmountResidualFlamesDuringFlight; /** Time delay until starting to drop residual flames during flight (should NOT be greater than Lifespan)*/ var float TimeDelayStartDroppingResidualFlames; /** Class for spawning residual flames **/ var class ResidualFlameProjClass; /** Number of lingering flames to spawn when projectile hits environment or a pawn before reaching max * Note: one flame will always spawn in the place or pawn hit. */ var() int AmountResidualFlamesInExplosion; /** Magnitude to multiply velocity computed for residual flames in explosion */ var float MagnitudeVelocityResidualFlamesInExplosion; /** Offset added to the final velocity computed for residual flames in explosion */ var vector OffsetVelocityResidualFlamesInExplosion; /** (Computed) Last Velocity from Explode() */ var vector LastVelocity; /** (Computed) Time between residual flames drops */ var float IntervalDroppingResidualFlames; /** Same as Lifespan (but using TimeAlive we assure projectile follows same flow as an explosion) */ var float TimeAlive; simulated protected function StopSimulating() { if (Instigator != none && Instigator.Role == ROLE_Authority) { ClearTimer(nameof(Timer_SpawningResidualFlamesDuringFlight)); ClearTimer(nameof(Timer_StartSpawningResidualFlamesDuringFlight)); } ClearTimer(nameof(Timer_Shutdown)); super.StopSimulating(); } simulated function PostBeginPlay() { //Subtract a bit (0.005) from TimeAlive to not match last cycle of the timer with time the projectile has to disappear (causing last flame not to drop then) //Subtract 1 from AmountResidualFlamesDuringFlight because the first flame will be spawned manually at the start of the timer. IntervalDroppingResidualFlames=((TimeAlive - 0.005) - TimeDelayStartDroppingResidualFlames)/(AmountResidualFlamesDuringFlight - 1); if (Instigator != none && Instigator.Role == ROLE_Authority) { SetTimer(TimeDelayStartDroppingResidualFlames, false, nameof(Timer_StartSpawningResidualFlamesDuringFlight)); } SetTimer(TimeAlive, false, nameof(Timer_Shutdown)); super.PostBeginPlay(); } simulated function Init(vector Direction) { super.Init(Direction); SpeedDirectionResidualFlames = Velocity/5; } /** Timer to spawn residual flames while projectile is flying */ simulated function Timer_SpawningResidualFlamesDuringFlight() { SpawnResidualFlame(ResidualFlameProjClass, Location, SpeedDirectionResidualFlames); } /** Timer to act as offset to start spawning residual flames during flight (in order to avoid dropping flames to close to player) */ simulated function Timer_StartSpawningResidualFlamesDuringFlight() { SpawnResidualFlame(ResidualFlameProjClass, Location, SpeedDirectionResidualFlames); SetTimer(IntervalDroppingResidualFlames, true, nameof(Timer_SpawningResidualFlamesDuringFlight)); } /** Timer until calling Shutdown */ simulated function Timer_Shutdown() { Shutdown(); } /** Spawn several projectiles that explode and linger on impact */ function SpawnResidualFlames (vector HitLocation, vector HitNormal, vector HitVelocity) { local int i; local vector HitVelDir; local float HitVelMag; local vector SpawnLoc, SpawnVel; HitVelMag = VSize (HitVelocity)*MagnitudeVelocityResidualFlamesInExplosion; HitVelDir = Normal (HitVelocity); SpawnLoc = HitLocation + (HitNormal * 10.f); // spawn random lingering fires (rather, projectiles that cause little fires) for( i = 0; i < AmountResidualFlamesInExplosion; ++i ) { SpawnVel = CalculateResidualFlameVelocity( HitNormal, HitVelDir, HitVelMag ); SpawnVel = SpawnVel + OffsetVelocityResidualFlamesInExplosion; SpawnResidualFlame( ResidualFlameProjClass, SpawnLoc, SpawnVel ); } } /** Spawn several projectiles that explode and linger on impact on explosion and one projectile to explode where this projectile hit */ simulated function TriggerExplosion(Vector HitLocation, Vector HitNormal, Actor HitActor) { local bool bDoExplosion; if (bHasDisintegrated) { return; } bDoExplosion = !bHasExploded && Instigator.Role == ROLE_Authority; if (bDoExplosion) { SpawnResidualFlames (HitLocation, HitNormal, LastVelocity); SpawnResidualFlame (ResidualFlameProjClass, Location, LastVelocity); } super.TriggerExplosion(HitLocation, HitNormal, HitActor); } simulated function Explode (vector HitLocation, vector HitNormal) { LastVelocity = Velocity; super.Explode (HitLocation, HitNormal); } simulated function ProcessTouch(Actor Other, Vector HitLocation, Vector HitNormal) { ProcessBulletTouch(Other, HitLocation, HitNormal); super.ProcessTouch(Other, HitLocation, HitNormal); } simulated function SpawnFlightEffects() { super.SpawnFlightEffects(); if (ProjEffects != None) { ProjEffects.SetFloatParameter( 'FlareLifetime', LifeSpan ); } } defaultproperties { Physics=PHYS_Falling MaxSpeed=7000.0 Speed=3000.0 //7000.0 TerminalVelocity=7000.0 bWarnAIWhenFired=true bCollideActors=true bCollideComplex=true DamageRadius=0 GravityScale=0.4 //0.5 //1.0 TossZ=0 TimeDelayStartDroppingResidualFlames=0.005 //0.05 TimeAlive=0.5//0.6 //0.2 ProjEffectsFadeOutDuration=5.0 AmountResidualFlamesDuringFlight=8 //10 SpeedDirectionResidualFlames=(X=0, Y=0, Z=0) AmountResidualFlamesInExplosion=3 MagnitudeVelocityResidualFlamesInExplosion=0.5 OffsetVelocityResidualFlamesInExplosion=(X=0, Y=0, Z=200) bNoReplicationToInstigator=false Begin Object Class=PointLightComponent Name=PointLight0 //LightColor=(R=252,G=218,B=171,A=255) LightColor=(R=250,G=25,B=80,A=255) Brightness=0.5f Radius=500.f FalloffExponent=10.f CastShadows=False CastStaticShadows=FALSE CastDynamicShadows=False bCastPerObjectShadows=false bEnabled=true LightingChannels=(Indoor=TRUE,Outdoor=TRUE,bInitialized=TRUE) End Object ProjFlightLight=PointLight0 ResidualFlameProjClass=class'KFProj_BrokenFlare_HRGScorcherSplash' //ProjFlightTemplateZedTime=ParticleSystem'WEP_DragonsBreath_EMIT.Tracer.FX_DragonsBreath_Tracer_ZEDTime' ProjFlightTemplate=ParticleSystem'WEP_HRGScorcher_Pistol_EMIT.FX_HRGScorcher_Projectile_01_ALT' AssociatedPerkClass=class'KFPerk_Firebug' // Light during explosion Begin Object Class=PointLightComponent Name=ExplosionPointLight LightColor=(R=252,G=218,B=171,A=255) Brightness=4.f Radius=2000.f FalloffExponent=10.f CastShadows=False CastStaticShadows=FALSE CastDynamicShadows=False bCastPerObjectShadows=false bEnabled=FALSE LightingChannels=(Indoor=TRUE,Outdoor=TRUE,bInitialized=TRUE) End Object // Explosion Begin Object Class=KFGameExplosion Name=ExploTemplate0 Damage=0 DamageRadius=500 DamageFalloffExponent=1.f DamageDelay=0.f bIgnoreInstigator=false MomentumTransferScale=0 // Damage Effects MyDamageType=class'KFDT_Fire_HRGScorcherDoT' KnockDownStrength=0 FractureMeshRadius=200.0 FracturePartVel=500.0 ExplosionEffects=KFImpactEffectInfo'WEP_HRGScorcher_Pistol_ARCH.HRGScorcher_Pistol_Grenade_Explosion' ExplosionSound=AkEvent'WW_WEP_HRG_Scorcher.Play_WEP_HRG_Scorcher_AltFire_Explosion' // Dynamic Light ExploLight=ExplosionPointLight ExploLightStartFadeOutTime=0.0 ExploLightFadeOutTime=0.2 // Camera Shake CamShake=CameraShake'FX_CameraShake_Arch.Misc_Explosions.Light_Explosion_Rumble' CamShakeInnerRadius=200 CamShakeOuterRadius=900 CamShakeFalloff=1.5f bOrientCameraShakeTowardsEpicenter=true End Object ExplosionTemplate=ExploTemplate0 ExplosionActorClass=class'KFExplosionActor' bDamageDestructiblesOnTouch=true }