434 lines
11 KiB
Ucode
434 lines
11 KiB
Ucode
|
//=============================================================================
|
||
|
// KFProj_Thrown_C4
|
||
|
//=============================================================================
|
||
|
// Projectile class for C4 weapon
|
||
|
//=============================================================================
|
||
|
// Killing Floor 2
|
||
|
// Copyright (C) 2015 Tripwire Interactive LLC
|
||
|
// Jeff Robinson
|
||
|
//=============================================================================
|
||
|
|
||
|
class KFProj_Thrown_C4 extends KFProjectile;
|
||
|
|
||
|
var KFImpactEffectInfo ImpactEffectInfo;
|
||
|
|
||
|
/** "beep" sound to play (on an interval) when instigator is within blast radius */
|
||
|
var() AkEvent ProximityAlertAkEvent;
|
||
|
/** Time between proximity beeps */
|
||
|
var() float ProximityAlertInterval;
|
||
|
/** Time between proximity beeps when the instigator is within "fatal" radius */
|
||
|
var() float ProximityAlertIntervalClose;
|
||
|
/** Time until next alert */
|
||
|
var transient float ProximityAlertTimer;
|
||
|
|
||
|
/** Visual component of this projectile (we don't use ProjEffects particle system because we need to manipulate the MIC) */
|
||
|
var StaticMeshComponent ChargeMesh;
|
||
|
/** Mesh MIC, used to make LED blink */
|
||
|
var MaterialInstanceConstant ChargeMIC;
|
||
|
/** Dynamic light for blinking */
|
||
|
var PointLightComponent BlinkLightComp;
|
||
|
/** Blink colors */
|
||
|
var LinearColor BlinkColorOn, BlinkColorOff;
|
||
|
/** How long LED and dynamic light should stay lit for */
|
||
|
var float BlinkTime;
|
||
|
|
||
|
var ParticleSystem BlinkFX;
|
||
|
var ParticleSystemComponent BlinkPSC;
|
||
|
|
||
|
/** Id for skin override */
|
||
|
var repnotify int WeaponSkinId;
|
||
|
|
||
|
replication
|
||
|
{
|
||
|
if(bNetDirty)
|
||
|
WeaponSkinId;
|
||
|
}
|
||
|
|
||
|
simulated function PostBeginPlay()
|
||
|
{
|
||
|
if( WorldInfo.NetMode != NM_Client )
|
||
|
{
|
||
|
if( InstigatorController != none )
|
||
|
{
|
||
|
class'KFGameplayPoolManager'.static.GetPoolManager().AddProjectileToPool( self, PPT_C4 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Destroy();
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
super.PostBeginPlay();
|
||
|
|
||
|
ProximityAlertTimer = ProximityAlertInterval;
|
||
|
|
||
|
AdjustCanDisintigrate();
|
||
|
|
||
|
ChargeMIC = ChargeMesh.CreateAndSetMaterialInstanceConstant(0);
|
||
|
}
|
||
|
|
||
|
/** Used to check current status of StuckTo actor (to figure out if we should fall) */
|
||
|
simulated event Tick( float DeltaTime )
|
||
|
{
|
||
|
super.Tick(DeltaTime);
|
||
|
|
||
|
StickHelper.Tick(DeltaTime);
|
||
|
|
||
|
if (StuckToActor != none)
|
||
|
{
|
||
|
UpdateAlert(DeltaTime);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Checks if deployed charge should play a warning "beep" for the instigator. Beeps faster if the instigator is within "lethal" range. */
|
||
|
simulated function UpdateAlert( float DeltaTime )
|
||
|
{
|
||
|
local vector ToInstigator, BBoxCenter;
|
||
|
local float DistToInstigator, DamageScale;
|
||
|
local Actor TraceActor;
|
||
|
local Box BBox;
|
||
|
|
||
|
if( WorldInfo.NetMode == NM_DedicatedServer )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if( bHasExploded || bHasDisintegrated )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if( ProximityAlertTimer <= 0 )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ProximityAlertTimer -= DeltaTime;
|
||
|
|
||
|
if( ProximityAlertTimer > 0 )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ProximityAlertTimer = ProximityAlertInterval;
|
||
|
|
||
|
// only play sound for instigator (based on distance)
|
||
|
if( Instigator != none && Instigator.IsLocallyControlled() )
|
||
|
{
|
||
|
ToInstigator = Instigator.Location - Location;
|
||
|
DistToInstigator = VSize( ToInstigator );
|
||
|
if( DistToInstigator <= ExplosionTemplate.DamageRadius )
|
||
|
{
|
||
|
Instigator.GetComponentsBoundingBox(BBox);
|
||
|
BBoxCenter = (BBox.Min + BBox.Max) * 0.5f;
|
||
|
TraceActor = class'GameExplosionActor'.static.StaticTraceExplosive(BBoxCenter, Location + vect(0,0,20), self);
|
||
|
if( TraceActor == none || TraceActor == Instigator )
|
||
|
{
|
||
|
DamageScale = FClamp(1.f - DistToInstigator/ExplosionTemplate.DamageRadius, 0.f, 1.f);
|
||
|
DamageScale = DamageScale ** ExplosionTemplate.DamageFalloffExponent;
|
||
|
|
||
|
if( ExplosionTemplate.Damage * DamageScale > Instigator.Health )
|
||
|
{
|
||
|
ProximityAlertTimer = ProximityAlertIntervalClose;
|
||
|
}
|
||
|
|
||
|
PlaySoundBase( ProximityAlertAkEvent, true );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// blink for everyone to see
|
||
|
BlinkOn();
|
||
|
}
|
||
|
|
||
|
/** Turns on LED and dynamic light */
|
||
|
simulated function BlinkOn()
|
||
|
{
|
||
|
if( BlinkPSC == none )
|
||
|
{
|
||
|
BlinkPSC = WorldInfo.MyEmitterPool.SpawnEmitter(BlinkFX, Location + (vect(0,0,4) + vect(8,0,0) >> Rotation),, self,,, true);
|
||
|
}
|
||
|
|
||
|
BlinkPSC.SetFloatParameter('Glow', 1.0);
|
||
|
|
||
|
ChargeMIC.SetVectorParameterValue('Vector_GlowColor', BlinkColorOn);
|
||
|
BlinkLightComp.SetEnabled( true );
|
||
|
SetTimer( BlinkTime, false, nameof(BlinkOff) );
|
||
|
}
|
||
|
|
||
|
/** Turns off LED and dynamic light */
|
||
|
simulated function BlinkOff()
|
||
|
{
|
||
|
if( BlinkPSC != none )
|
||
|
{
|
||
|
BlinkPSC.SetFloatParameter('Glow', 0.0);
|
||
|
}
|
||
|
|
||
|
ChargeMIC.SetVectorParameterValue('Vector_GlowColor', BlinkColorOff);
|
||
|
BlinkLightComp.SetEnabled( false );
|
||
|
}
|
||
|
|
||
|
simulated function SetStickOrientation(vector HitNormal)
|
||
|
{
|
||
|
local rotator StickRot;
|
||
|
|
||
|
StickRot = CalculateStickOrientation(HitNormal);
|
||
|
SetRotation(StickRot);
|
||
|
}
|
||
|
|
||
|
/** Causes charge to explode */
|
||
|
function Detonate()
|
||
|
{
|
||
|
local KFWeap_Thrown_C4 C4WeaponOwner;
|
||
|
local vector ExplosionNormal;
|
||
|
|
||
|
if( Role == ROLE_Authority )
|
||
|
{
|
||
|
C4WeaponOwner = KFWeap_Thrown_C4( Owner );
|
||
|
if( C4WeaponOwner != none )
|
||
|
{
|
||
|
C4WeaponOwner.RemoveDeployedCharge(, self);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ExplosionNormal = vect(0,0,1) >> Rotation;
|
||
|
Explode( Location, ExplosionNormal );
|
||
|
}
|
||
|
|
||
|
simulated function Explode(vector HitLocation, vector HitNormal)
|
||
|
{
|
||
|
if( WorldInfo.NetMode != NM_DedicatedServer )
|
||
|
{
|
||
|
BlinkOff();
|
||
|
}
|
||
|
|
||
|
super.Explode( HitLocation, HitNormal );
|
||
|
}
|
||
|
|
||
|
simulated function Disintegrate( rotator InDisintegrateEffectRotation )
|
||
|
{
|
||
|
local KFWeap_Thrown_C4 C4WeaponOwner;
|
||
|
|
||
|
if( Role == ROLE_Authority )
|
||
|
{
|
||
|
C4WeaponOwner = KFWeap_Thrown_C4( Owner );
|
||
|
if( C4WeaponOwner != none )
|
||
|
{
|
||
|
C4WeaponOwner.RemoveDeployedCharge(, self);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( WorldInfo.NetMode != NM_DedicatedServer )
|
||
|
{
|
||
|
BlinkOff();
|
||
|
}
|
||
|
|
||
|
super.Disintegrate( InDisintegrateEffectRotation );
|
||
|
}
|
||
|
|
||
|
// for nukes && concussive force
|
||
|
simulated protected function PrepareExplosionTemplate()
|
||
|
{
|
||
|
class'KFPerk_Demolitionist'.static.PrepareExplosive( Instigator, self );
|
||
|
|
||
|
super.PrepareExplosionTemplate();
|
||
|
}
|
||
|
|
||
|
simulated protected function SetExplosionActorClass()
|
||
|
{
|
||
|
local KFPlayerReplicationInfo InstigatorPRI;
|
||
|
|
||
|
if( WorldInfo.TimeDilation < 1.f && Instigator != none )
|
||
|
{
|
||
|
InstigatorPRI = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo);
|
||
|
if( InstigatorPRI != none )
|
||
|
{
|
||
|
if( InstigatorPRI.bNukeActive && class'KFPerk_Demolitionist'.static.ProjectileShouldNuke( self ) )
|
||
|
{
|
||
|
ExplosionActorClass = class'KFPerk_Demolitionist'.static.GetNukeExplosionActorClass();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
super.SetExplosionActorClass();
|
||
|
}
|
||
|
|
||
|
/** Blows up on a timer */
|
||
|
function Timer_Explode()
|
||
|
{
|
||
|
Detonate();
|
||
|
}
|
||
|
|
||
|
/** Remove C4 from pool */
|
||
|
simulated event Destroyed()
|
||
|
{
|
||
|
if( WorldInfo.NetMode != NM_Client )
|
||
|
{
|
||
|
if( InstigatorController != none )
|
||
|
{
|
||
|
class'KFGameplayPoolManager'.static.GetPoolManager().RemoveProjectileFromPool( self, PPT_C4 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
super.Destroyed();
|
||
|
}
|
||
|
|
||
|
/** Called when the owning instigator controller has left a game */
|
||
|
simulated function OnInstigatorControllerLeft()
|
||
|
{
|
||
|
if( WorldInfo.NetMode != NM_Client )
|
||
|
{
|
||
|
SetTimer( 1.f + Rand(5) + fRand(), false, nameOf(Timer_Explode) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
simulated function SetWeaponSkin(int SkinId)
|
||
|
{
|
||
|
local array<MaterialInterface> SkinMICs;
|
||
|
local int i;
|
||
|
|
||
|
if (SkinId > 0)
|
||
|
{
|
||
|
SkinMICs = class'KFWeaponSkinList'.static.GetWeaponSkin(SkinId, WST_FirstPerson);
|
||
|
for (i = 0; i < SkinMICs.length; i++)
|
||
|
{
|
||
|
ChargeMesh.SetMaterial(i, SkinMICs[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ChargeMIC = ChargeMesh.CreateAndSetMaterialInstanceConstant(0);
|
||
|
}
|
||
|
|
||
|
defaultproperties
|
||
|
{
|
||
|
StuckToBoneIdx=INDEX_NONE
|
||
|
|
||
|
Physics=PHYS_Falling
|
||
|
MaxSpeed=1200.0
|
||
|
Speed=1200.0
|
||
|
TossZ=100
|
||
|
GravityScale=1.0
|
||
|
|
||
|
LifeSpan=0
|
||
|
|
||
|
bBounce=true
|
||
|
GlassShatterType=FMGS_ShatterDamaged
|
||
|
|
||
|
ExplosionActorClass=class'KFExplosionActorC4'
|
||
|
|
||
|
DamageRadius=0
|
||
|
|
||
|
bCollideComplex=true
|
||
|
|
||
|
bIgnoreFoliageTouch=true
|
||
|
|
||
|
bBlockedByInstigator=false
|
||
|
bAlwaysReplicateExplosion=true
|
||
|
|
||
|
bNetTemporary=false
|
||
|
|
||
|
bCanBeDamaged=true
|
||
|
bCanDisintegrate=true
|
||
|
Begin Object Name=CollisionCylinder
|
||
|
BlockNonZeroExtent=false
|
||
|
|
||
|
// for siren scream
|
||
|
CollideActors=true
|
||
|
End Object
|
||
|
|
||
|
AlwaysRelevantDistanceSquared=6250000 // 25m, same as grenade
|
||
|
|
||
|
AltExploEffects=KFImpactEffectInfo'WEP_C4_ARCH.C4_Explosion_Concussive_Force'
|
||
|
|
||
|
// blink light
|
||
|
Begin Object Class=PointLightComponent Name=BlinkPointLight
|
||
|
LightColor=(R=255,G=63,B=63,A=255)
|
||
|
Brightness=4.f
|
||
|
Radius=300.f
|
||
|
FalloffExponent=10.f
|
||
|
CastShadows=False
|
||
|
CastStaticShadows=FALSE
|
||
|
CastDynamicShadows=False
|
||
|
bCastPerObjectShadows=false
|
||
|
bEnabled=FALSE
|
||
|
LightingChannels=(Indoor=TRUE,Outdoor=TRUE,bInitialized=TRUE)
|
||
|
Translation=(X=8, Z=4)
|
||
|
End Object
|
||
|
BlinkLightComp=BlinkPointLight
|
||
|
Components.Add(BlinkPointLight)
|
||
|
|
||
|
// projectile mesh (use this instead of ProjEffects particle system)
|
||
|
Begin Object Class=StaticMeshComponent Name=StaticMeshComponent0
|
||
|
StaticMesh=StaticMesh'WEP_3P_C4_MESH.Wep_C4_Projectile'
|
||
|
bCastDynamicShadow=FALSE
|
||
|
CollideActors=false
|
||
|
LightingChannels=(bInitialized=True,Dynamic=True,Indoor=True,Outdoor=True)
|
||
|
End Object
|
||
|
ChargeMesh=StaticMeshComponent0
|
||
|
Components.Add(StaticMeshComponent0)
|
||
|
|
||
|
// explosion light
|
||
|
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=820
|
||
|
DamageRadius=400
|
||
|
DamageFalloffExponent=2.f
|
||
|
DamageDelay=0.f
|
||
|
|
||
|
// Damage Effects
|
||
|
MyDamageType=class'KFDT_Explosive_C4'
|
||
|
KnockDownStrength=0
|
||
|
FractureMeshRadius=200.0
|
||
|
FracturePartVel=500.0
|
||
|
ExplosionEffects=KFImpactEffectInfo'WEP_C4_ARCH.C4_Explosion'
|
||
|
ExplosionSound=AkEvent'WW_WEP_EXP_C4.Play_WEP_EXP_C4_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
|
||
|
|
||
|
ImpactEffectInfo=KFImpactEffectInfo'WEP_C4_ARCH.C4_Projectile_Impacts'
|
||
|
|
||
|
ProjDisintegrateTemplate=ParticleSystem'ZED_Siren_EMIT.FX_Siren_grenade_disable_01'
|
||
|
|
||
|
ProximityAlertAkEvent=AkEvent'WW_WEP_EXP_C4.Play_WEP_EXP_C4_Prox_Beep'
|
||
|
ProximityAlertInterval=1.0
|
||
|
ProximityAlertIntervalClose=0.5
|
||
|
|
||
|
BlinkTime=0.2f
|
||
|
BlinkColorOff=(R=0, G=0, B=0)
|
||
|
BlinkColorOn=(R=1, G=0, B=0)
|
||
|
|
||
|
BlinkFX=ParticleSystem'WEP_C4_EMIT.FX_C4_Glow'
|
||
|
|
||
|
bCanStick=true
|
||
|
Begin Object Class=KFProjectileStickHelper Name=StickHelper0
|
||
|
StickAkEvent=AkEvent'WW_WEP_EXP_C4.Play_WEP_EXP_C4_Handling_Place'
|
||
|
End Object
|
||
|
StickHelper=StickHelper0
|
||
|
}
|