//============================================================================= // SeekerSixRocketProjectile //============================================================================= // Rocket projectile class for the SeekerSix mini rocket launcher //============================================================================= // Killing Floor Source // Copyright (C) 2013 Tripwire Interactive LLC // - John "Ramm-Jaeger" Gibson //============================================================================= class SeekerSixRocketProjectile extends LAWProj; //var Emitter Corona; var xEmitter RocketTrail; var xEmitter RocketSmoke; var byte FlockIndex; var SeekerSixRocketProjectile Flock[6]; var(Flocking) float FlockRadius; var(Flocking) float FlockStiffness; var(Flocking) float FlockMaxForce; var(Flocking) float FlockCurlForce; var bool bCurl; var string AmbientSoundTwoRef; var string AmbientSoundThreeRef; var(Sound) sound AmbientSoundTwo; // Ambient sound effect. var(Sound) sound AmbientSoundThree; // Ambient sound effect. var() InterpCurve AppliedMomentumCurve; // How much momentum to apply to a zed based on how much mass it has replication { reliable if ( bNetInitial && (Role == ROLE_Authority) ) FlockIndex, bCurl; } static function PreloadAssets() { default.ExplosionSound = sound(DynamicLoadObject(default.ExplosionSoundRef, class'Sound', true)); default.AmbientSound = sound(DynamicLoadObject(default.AmbientSoundRef, class'Sound', true)); default.AmbientSoundTwo = sound(DynamicLoadObject(default.AmbientSoundTwoRef, class'Sound', true)); default.AmbientSoundThree = sound(DynamicLoadObject(default.AmbientSoundThreeRef, class'Sound', true)); default.DisintegrateSound = sound(DynamicLoadObject(default.DisintegrateSoundRef, class'Sound', true)); UpdateDefaultStaticMesh(StaticMesh(DynamicLoadObject(default.StaticMeshRef, class'StaticMesh', true))); } static function bool UnloadAssets() { default.ExplosionSound = none; default.AmbientSound = none; default.AmbientSoundTwo = none; default.AmbientSoundThree = none; default.DisintegrateSound = none; UpdateDefaultStaticMesh(none); return true; } simulated function PostBeginPlay() { BCInverse = 1 / BallisticCoefficient; if( FRand() < 0.33 ) { AmbientSound = AmbientSoundTwo; } else if( FRand() < 0.33 ) { AmbientSound = AmbientSoundThree; } if ( Level.NetMode != NM_DedicatedServer) { RocketSmoke = Spawn(class'SeekerSixRocketSmokeX',self); RocketTrail = Spawn(class'SeekerSixRocketTrailX',self); } OrigLoc = Location; if( !bDud ) { Dir = vector(Rotation); Velocity = speed * Dir; } if (PhysicsVolume.bWaterVolume) { bHitWater = True; Velocity=0.6*Velocity; } super(Projectile).PostBeginPlay(); } simulated function PostNetBeginPlay() { local SeekerSixRocketProjectile R; local int i, p, q; local Array Rockets; Super.PostNetBeginPlay(); if ( FlockIndex != 0 ) { SetTimer(0.1, true); // look for other rockets and set thier flock values if ( Flock[1] == None ) { Rockets[0]=self; i=1; ForEach DynamicActors(class'SeekerSixRocketProjectile',R) if ( R.FlockIndex == FlockIndex ) { if( R == Self ) { continue; } Rockets[i] = R; i++; if ( i == 6 ) break; } for ( p = 0; p < Rockets.Length; p++ ) { if ( Rockets[p] != None ) { i = 0; for ( q=0; q damageType, optional int HitIndex) { if( damageType == class'SirenScreamDamage') { Disintegrate(HitLocation, vect(0,0,1)); } } simulated function Destroyed() { // if( Corona != none ) // { // Corona.Kill(); // } // if ( RocketTrail != none ) { RocketTrail.mRegen=False; RocketTrail.SetPhysics(PHYS_None); RocketTrail.GotoState(''); } if ( RocketSmoke != none ) { RocketSmoke.mRegen=False; RocketSmoke.SetPhysics(PHYS_None); RocketSmoke.GotoState(''); } Super.Destroyed(); } /* HurtRadius() Hurt locally authoritative actors within the radius. Overridden to scale the momentum of the zeds hit by mass based on a curve we define */ simulated function HurtRadius( float DamageAmount, float DamageRadius, class DamageType, float Momentum, vector HitLocation ) { local actor Victims; local float damageScale, dist; local vector dirs; local int NumKilled; local KFMonster KFMonsterVictim; local Pawn P; local KFPawn KFP; local array CheckedPawns; local int i; local bool bAlreadyChecked; local float UsedMomentum; if ( bHurtEntry ) return; bHurtEntry = true; foreach CollidingActors (class 'Actor', Victims, DamageRadius, HitLocation) { // don't let blast damage affect fluid - VisibleCollisingActors doesn't really work for them - jag if( (Victims != self) && (Hurtwall != Victims) && (Victims.Role == ROLE_Authority) && !Victims.IsA('FluidSurfaceInfo') && ExtendedZCollision(Victims)==None ) { dirs = Victims.Location - HitLocation; dist = FMax(1,VSize(dirs)); dirs = dirs/dist; damageScale = 1 - FMax(0,(dist - Victims.CollisionRadius)/DamageRadius); if ( Instigator == None || Instigator.Controller == None ) Victims.SetDelayedDamageInstigatorController( InstigatorController ); if ( Victims == LastTouched ) LastTouched = None; P = Pawn(Victims); UsedMomentum = Momentum; if( P != none ) { for (i = 0; i < CheckedPawns.Length; i++) { if (CheckedPawns[i] == P) { bAlreadyChecked = true; break; } } if( bAlreadyChecked ) { bAlreadyChecked = false; P = none; continue; } // Scale the momentum by the mass of the pawn hit UsedMomentum *= InterpCurveEval(AppliedMomentumCurve,Victims.Mass); KFMonsterVictim = KFMonster(Victims); if( KFMonsterVictim != none && KFMonsterVictim.Health <= 0 ) { KFMonsterVictim = none; } KFP = KFPawn(Victims); if( KFMonsterVictim != none ) { damageScale *= KFMonsterVictim.GetExposureTo(HitLocation/*Location + 15 * -Normal(PhysicsVolume.Gravity)*/); } else if( KFP != none ) { damageScale *= KFP.GetExposureTo(HitLocation/*Location + 15 * -Normal(PhysicsVolume.Gravity)*/); } CheckedPawns[CheckedPawns.Length] = P; if ( damageScale <= 0) { P = none; continue; } else { //Victims = P; P = none; } } Victims.TakeDamage ( damageScale * DamageAmount, Instigator, Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * dirs, (damageScale * UsedMomentum * dirs), DamageType ); if (Vehicle(Victims) != None && Vehicle(Victims).Health > 0) Vehicle(Victims).DriverRadiusDamage(DamageAmount, DamageRadius, InstigatorController, DamageType, UsedMomentum, HitLocation); if( Role == ROLE_Authority && KFMonsterVictim != none && KFMonsterVictim.Health <= 0 ) { NumKilled++; } } } if ( (LastTouched != None) && (LastTouched != self) && (LastTouched.Role == ROLE_Authority) && !LastTouched.IsA('FluidSurfaceInfo') ) { Victims = LastTouched; LastTouched = None; dirs = Victims.Location - HitLocation; dist = FMax(1,VSize(dirs)); dirs = dirs/dist; damageScale = FMax(Victims.CollisionRadius/(Victims.CollisionRadius + Victims.CollisionHeight),1 - FMax(0,(dist - Victims.CollisionRadius)/DamageRadius)); if ( Instigator == None || Instigator.Controller == None ) Victims.SetDelayedDamageInstigatorController(InstigatorController); UsedMomentum = Momentum; if( Pawn(Victims) != none ) { UsedMomentum *= InterpCurveEval(AppliedMomentumCurve,Victims.Mass); } Victims.TakeDamage ( damageScale * DamageAmount, Instigator, Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * dirs, (damageScale * UsedMomentum * dirs), DamageType ); if (Vehicle(Victims) != None && Vehicle(Victims).Health > 0) Vehicle(Victims).DriverRadiusDamage(DamageAmount, DamageRadius, InstigatorController, DamageType, UsedMomentum, HitLocation); } if( Role == ROLE_Authority ) { if( NumKilled >= 4 ) { KFGameType(Level.Game).DramaticEvent(0.05); } else if( NumKilled >= 2 ) { KFGameType(Level.Game).DramaticEvent(0.03); } } bHurtEntry = false; } defaultproperties { StaticMeshRef="KF_IJC_Halloween_Weps2.seeker6_projectile" LifeSpan=10.000000 DrawScale=2.500000 MyDamageType=Class'KFMod.DamTypeSeekerSixRocket' ImpactDamageType=Class'KFMod.DamTypeSeekerRocketImpact' RemoteRole=ROLE_SimulatedProxy bBounce=false RotationRate=(Roll=50000) ExplosionDecal=Class'KFMod.FlameThrowerBurnMark_Medium' ImpactDamage=75 Damage=100 DamageRadius=150 ArmDistSquared=10000 // 2 meters Speed=2000.000000 MaxSpeed=2000.000000 FlockRadius=12 FlockStiffness=-100 FlockMaxForce=600 FlockCurlForce=450 ExplosionSoundRef="KF_FY_SeekerSixSND.WEP_Seeker_Explode" AmbientSoundRef="KF_FY_SeekerSixSND.WEP_Seeker_Rocket_LP" AmbientSoundTwoRef="KF_FY_SeekerSixSND.WEP_Seeker_Rocket_LP_02" AmbientSoundThreeRef="KF_FY_SeekerSixSND.WEP_Seeker_Rocket_LP_03" SoundVolume=255 SoundRadius=250 AmbientVolumeScale=5.0 TransientSoundVolume=2.0 TransientSoundRadius=500 AppliedMomentumCurve=(Points=((InVal=0.0,OutVal=0.5),(InVal=100.0,OutVal=0.5),(InVal=350.0,OutVal=1.0),(InVal=600.0,OutVal=1.0))) }