//============================================================================= // KFProj_HuskCannon_Fireball //============================================================================= // Player version for the Husk Cannon of the Husk fire ball. //============================================================================= // Killing Floor 2 // Copyright (C) 2017 Tripwire Interactive LLC //============================================================================= class KFProj_HuskCannon_Fireball extends KFProj_BallisticExplosive implements(KFInterface_DamageCauser); var float DamageScale; var float AOEScale; var float IncapScale; var repnotify int ChargeLevel; var const ParticleSystem ExplosionEffectL1; var const ParticleSystem ExplosionEffectL2; var const ParticleSystem ExplosionEffectL3; var const ParticleSystem ProjFlightTemplateL1; var const ParticleSystem ProjFlightTemplateL2; var const ParticleSystem ProjFlightTemplateL3; var const AkBaseSoundObject ExplosionSoundL1; var const AkBaseSoundObject ExplosionSoundL2; var const AkBaseSoundObject ExplosionSoundL3; var const ParticleSystem ConcussiveForceEffectL1; var const ParticleSystem ConcussiveForceEffectL2; var const ParticleSystem ConcussiveForceEffectL3; /** Explosion actor class to use for ground fire */ var const protected class GroundFireExplosionActorClass; /** Explosion template to use for ground fire */ var KFGameExplosion GroundFireExplosionTemplate; /** How long the ground fire should stick around */ var const protected float BurnDuration; /** How often, in seconds, we should apply burn */ var const protected float BurnDamageInterval; var bool bSpawnGroundFire; var bool bAltGroundFire; var KFImpactEffectInfo AltGroundFire; replication { if (bNetInitial) bSpawnGroundFire, ChargeLevel; } simulated event ReplicatedEvent(name VarName) { if (VarName == nameof(ChargeLevel)) { bSpawnGroundFire = ChargeLevel == 3; SpawnFlightEffects(); } Super.ReplicatedEvent(VarName); } simulated function PostBeginPlay() { local KFWeap_HuskCannon HuskCannon; local KFPlayerReplicationInfo InstigatorPRI; if(Role == ROLE_Authority) { HuskCannon = KFWeap_HuskCannon(Owner); if (HuskCannon != none) { ChargeLevel = HuskCannon.GetChargeFXLevel(); bSpawnGroundFire = ChargeLevel == 3; } } if(Instigator != none) { if (AltGroundFire != none) { InstigatorPRI = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo); if (InstigatorPRI != none) { bAltGroundFire = InstigatorPRI.bSplashActive; } } else { bAltGroundFire = false; } } Super.PostBeginPlay(); } simulated protected function PrepareExplosionActor(GameExplosionActor GEA) { local KFExplosionActor_HuskCannon HuskExplode; HuskExplode = KFExplosionActor_HuskCannon(GEA); if (HuskExplode != None) { HuskExplode.DamageScale = DamageScale; } } simulated function TriggerExplosion(Vector HitLocation, Vector HitNormal, Actor HitActor) { local KFExplosionActorLingering GFExplosionActor; local vector GroundExplosionHitNormal; if (bHasDisintegrated) { return; } if (!bHasExploded && bSpawnGroundFire) { if (bAltGroundFire && AltGroundFire != none) { GroundFireExplosionTemplate.ExplosionEffects = AltGroundFire; } GroundExplosionHitNormal = HitNormal; // Spawn our explosion and set up its parameters GFExplosionActor = Spawn(GroundFireExplosionActorClass, self, , HitLocation + (HitNormal * 32.f), rotator(HitNormal)); if (GFExplosionActor != None) { GFExplosionActor.Instigator = Instigator; GFExplosionActor.InstigatorController = InstigatorController; // These are needed for the decal tracing later in GameExplosionActor.Explode() GroundFireExplosionTemplate.HitLocation = HitLocation; GroundFireExplosionTemplate.HitNormal = GroundExplosionHitNormal; // Apply explosion direction if (GroundFireExplosionTemplate.bDirectionalExplosion) { GroundExplosionHitNormal = GetExplosionDirection(GroundExplosionHitNormal); } // Set our duration GFExplosionActor.MaxTime = BurnDuration; // Set our burn interval GFExplosionActor.Interval = BurnDamageInterval; // Boom GFExplosionActor.Explode(GroundFireExplosionTemplate, GroundExplosionHitNormal); } } super.TriggerExplosion(HitLocation, HitNormal, HitActor); } //============== // Touching simulated function ProcessTouch(Actor Other, Vector HitLocation, Vector HitNormal) { if (ClassIsChildOf(Other.class, class'KFPawn')) { bSpawnGroundFire = false; } super.ProcessTouch(Other, HitLocation, HitNormal); } simulated protected function PrepareExplosionTemplate() { local bool bUseConcussiveForce; local Weapon OwnerWeapon; local Pawn OwnerPawn; local KFPlayerReplicationInfo PRI; super(KFProjectile).PrepareExplosionTemplate(); bUseConcussiveForce = false; OwnerWeapon = Weapon(Owner); if (OwnerWeapon != none) { OwnerPawn = Pawn(OwnerWeapon.Owner); if (OwnerPawn != none) { PRI = KFPlayerReplicationInfo(OwnerPawn.PlayerReplicationInfo); if (PRI != none) { bUseConcussiveForce = PRI.bConcussiveActive; } } } switch (ChargeLevel) { case 1: if (bUseConcussiveForce) { ExplosionTemplate.ExplosionEffects.DefaultImpactEffect.ParticleTemplate = ConcussiveForceEffectL1; ExplosionTemplate.ExplosionSound = class'KFPerk_Demolitionist'.static.GetConcussiveExplosionSound(); } else { ExplosionTemplate.ExplosionEffects.DefaultImpactEffect.ParticleTemplate = ExplosionEffectL1; ExplosionTemplate.ExplosionSound = ExplosionSoundL1; } break; case 2: if (bUseConcussiveForce) { ExplosionTemplate.ExplosionEffects.DefaultImpactEffect.ParticleTemplate = ConcussiveForceEffectL2; ExplosionTemplate.ExplosionSound = class'KFPerk_Demolitionist'.static.GetConcussiveExplosionSound(); } else { ExplosionTemplate.ExplosionEffects.DefaultImpactEffect.ParticleTemplate = ExplosionEffectL2; ExplosionTemplate.ExplosionSound = ExplosionSoundL2; } break; case 3: if (bUseConcussiveForce) { ExplosionTemplate.ExplosionEffects.DefaultImpactEffect.ParticleTemplate = ConcussiveForceEffectL3; ExplosionTemplate.ExplosionSound = class'KFPerk_Demolitionist'.static.GetConcussiveExplosionSound(); } else { ExplosionTemplate.ExplosionEffects.DefaultImpactEffect.ParticleTemplate = ExplosionEffectL3; ExplosionTemplate.ExplosionSound = ExplosionSoundL3; } break; } class'KFPerk_Demolitionist'.static.PrepareExplosive(Instigator, self, AOEScale, DamageScale); } simulated protected function SetExplosionActorClass() { local KFPlayerReplicationInfo InstigatorPRI; if (bWasTimeDilated && Instigator != none) { InstigatorPRI = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo); if (InstigatorPRI != none && InstigatorPRI.CurrentPerkClass == class'KFPerk_Demolitionist') { if (InstigatorPRI.bNukeActive && class'KFPerk_Demolitionist'.static.ProjectileShouldNuke(self)) { ExplosionActorClass = class'KFPerk_Demolitionist'.static.GetNukeExplosionActorClass(); } } } super.SetExplosionActorClass(); } // KFInterface_DamageCauser function float GetIncapMod() { return IncapScale; } // Override ProjFlightTemplate to correct emitter. simulated function SpawnFlightEffects() { if (ChargeLevel == 0) { return; // Charge level will be set using replication. } switch (ChargeLevel) { case 1: ProjFlightTemplate = ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_Projectile_L1'; break; case 2: ProjFlightTemplate = ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_Projectile_L2'; break; case 3: ProjFlightTemplate = ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_Projectile_L3'; break; } Super.SpawnFlightEffects(); } defaultproperties { ExplosionActorClass=class'KFExplosionActor_HuskCannon' // Ground fire BurnDuration = 4.f BurnDamageInterval = 0.5f GroundFireExplosionActorClass=class'KFExplosion_HuskCannonFireballGroundFire' ProjFlightTemplate=ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_Projectile_L3' // Fire light Begin Object Class=PointLightComponent Name=FlamePointLight LightColor = (R = 245,G = 190,B = 140,A = 255) Brightness = 4.f Radius = 500.f FalloffExponent = 10.f CastShadows = False CastStaticShadows = FALSE CastDynamicShadows = TRUE bCastPerObjectShadows = false bEnabled = FALSE LightingChannels = (Indoor = TRUE,Outdoor = TRUE,bInitialized = TRUE) End Object // Grenade explosion light Begin Object Class=PointLightComponent Name=ExplosionPointLight LightColor = (R = 245,G = 190,B = 140,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 Begin Object Class=KFGameExplosion Name=ExploTemplate1 Damage=3 DamageRadius=150 DamageFalloffExponent=1.f DamageDelay=0.f // Don't burn the guy that tossed it, it's just too much damage with multiple fires, its almost guaranteed to kill the guy that tossed it bIgnoreInstigator=true MomentumTransferScale=1 // Damage Effects MyDamageType=class'KFDT_Fire_Ground_HuskCannon' KnockDownStrength=0 FractureMeshRadius=0 ExplosionEffects=KFImpactEffectInfo'wep_molotov_arch.Molotov_GroundFire' bDirectionalExplosion=true // Camera Shake CamShake=none // Dynamic Light ExploLight=FlamePointLight ExploLightStartFadeOutTime=1.5f ExploLightFadeOutTime=0.3 End Object GroundFireExplosionTemplate=ExploTemplate1 Begin Object Class=KFGameExplosion Name=ExploTemplate2 Damage=60 //100 DamageRadius=100 //450 //550 DamageFalloffExponent=1.f //1.0 DamageDelay=0.f bUseOverlapCheck = true // Damage Effects MyDamageType=class'KFDT_Explosive_HuskCannon' bCausesFracture=true MomentumTransferScale=6000.f KnockDownStrength=100 FractureMeshRadius=200.0 FracturePartVel=100.0 ExplosionEffects=KFImpactEffectInfo'FX_Impacts_ARCH.Explosions.HuskProjectile_Explosion' ExplosionSound=AkEvent'WW_ZED_Husk.ZED_Husk_SFX_Ranged_Shot_Impact' ExplosionEmitterScale=2.f // Dynamic Light ExploLight=ExplosionPointLight ExploLightStartFadeOutTime = 0.0 ExploLightFadeOutTime = 0.5 // Camera Shake // Camera Shake CamShake = none bOrientCameraShakeTowardsEpicenter=true bIgnoreInstigator=false End Object ExplosionTemplate=ExploTemplate2 //AltExploEffects=KFImpactEffectInfo'WEP_Flamethrower_ARCH.GroundFire_Splash_Impacts' AltGroundFire=KFImpactEffectInfo'WEP_Flamethrower_ARCH.GroundFire_Splash_Impacts' Begin Object Name=CollisionCylinder CollisionRadius=4 //6 CollisionHeight=4 //2 End Object ExtraLineCollisionOffsets.Add((Y = -8)) ExtraLineCollisionOffsets.Add((Y = 8)) // Since we're still using an extent cylinder, we need a line at 0 ExtraLineCollisionOffsets.Add(()) MomentumTransfer=0 ConcussiveForceEffectL1=ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_Impact_L1_CF' ConcussiveForceEffectL2=ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_Impact_L2_CF' ConcussiveForceEffectL3=ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_Impact_L3_CF' ExplosionEffectL1=ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_Impact_L1' ExplosionEffectL2=ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_Impact_L2' ExplosionEffectL3=ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_Impact_L3' ProjFlightTemplateL1=ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_Projectile_L1' ProjFlightTemplateL2=ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_Projectile_L2' ProjFlightTemplateL3=ParticleSystem'WEP_HuskCannon_EMIT.FX_Huskcannon_Projectile_L3' ExplosionSoundL1=AkEvent'WW_ZED_Husk.ZED_Husk_SFX_Ranged_Shot_Impact'; ExplosionSoundL2=AkEvent'WW_ZED_Husk.ZED_Husk_SFX_Ranged_Shot_Impact'; ExplosionSoundL3=AkEvent'WW_ZED_Husk.ZED_Husk_SFX_Ranged_Shot_Impact'; AmbientSoundPlayEvent=none AmbientSoundStopEvent=none MaxSpeed=4000.0 Speed=4000.0 bNetTemporary = False bBlockedByInstigator=false bAlwaysReplicateExplosion = true bUseClientSideHitDetection = true bNoReplicationToInstigator = false bReplicateLocationOnExplosion = true bValidateExplosionNormalOnClient = true TouchTimeThreshhold = 0.15 }