1
0
KF2-Dev-Scripts/KFGameContent/Classes/KFProj_Mine_Reconstructor.uc
2021-09-03 00:46:08 +03:00

934 lines
25 KiB
Ucode

//=============================================================================
// KFProj_Mine_Reconstructor
//=============================================================================
// Projectile class for Mine Reconstructor
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
//=============================================================================
class KFProj_Mine_Reconstructor extends KFProjectile;
/** Steepest a slope can be for the mine to stick */
const MINMINEFLOORZ = 0.8f;
/** Ground FX template */
var ParticleSystem GroundFXTemplate;
/** Burst FX template */
var ParticleSystem BurstFXTemplate;
/** Cached team number, because players can switch teams */
var byte TeamNum;
/** How much damage the mine can take before exploding */
var int Health;
/** Dampen amount for every bounce */
var float DampenFactor;
/** Dampen amount for parallel angle to velocity */
var float DampenFactorParallel;
/** Vector to offset the ground FX particle system by when landing */
var vector LandedFXOffset;
/** Armed mine collision settings */
var float ExplodeTriggerRadius, ExplodeTriggerHeight;
/** Sound mine makes when it hits something and bounces off */
var AkEvent BounceAkEvent;
/** Sound mine makes when it hits something and comes to rest */
var AkEvent ImpactAkEvent;
/** Sound mine makes when it hits something and bounces off */
var AkEvent BounceAkEventHeavy;
/** Sound mine makes when it hits something and comes to rest */
var AkEvent ImpactAkEventHeavy;
/** Decal settings */
var MaterialInterface ImpactDecalMaterial;
var float ImpactDecalWidth;
var float ImpactDecalHeight;
var float ImpactDecalThickness;
/** How long the mine can exist before exploding */
var float FuseDuration;
/** Tells clients to trigger an explosion */
var repnotify bool bClientExplode;
/** Whether we've triggered a fade out */
var bool bFadingOut;
/** How long it should take to fade out this mine */
var float FadeOutTime;
/** Maximum number of times this mine can bounce */
var const int MaxBounces;
var int NumBounces;
var float MaxExplodeTriggerRadiusPerPercentage;
var float MinExplodeTriggerRadiusPerPercentage;
var float MaxExplodeTriggerHeightPerPercentage;
var float MinExplodeTriggerHeightPerPercentage;
var float MaxDamageRadiusPerPercentage;
var float MinDamageRadiusPerPercentage;
var float MaxCollisionRadius;
var float MinCollisionRadius;
var float MaxCollisionHeight;
var float MinCollisionHeight;
var float MaxDamagePerPercentage;
var float MinDamagePerPercentage;
var repnotify float InheritedScale;
var repnotify float fChargePercentage;
var float fCachedCylinderWidth, fCachedCylinderHeight;
//EXPERIMENTAL FEATURES
var bool bCantBeTouchedByInstigator;
var bool bManuallyDetonated;
var bool bCantDetonateOnFullHP;
var bool bSticked;
var repnotify bool bArmed;
struct ReplicatedStickInfo
{
var vector vRepStuckLocation, vRepStuckNormal;
};
var repnotify ReplicatedStickInfo StickInfo;
replication
{
if( bNetDirty && Role == Role_Authority)
bClientExplode, InheritedScale, fChargePercentage, StickInfo;
if(bNetInitial && Role == Role_Authority)
bArmed;
}
simulated event ReplicatedEvent( name VarName )
{
if( VarName == nameOf(bClientExplode) )
{
TriggerExplosion( Location, vect(0,0,1), none );
}
else
{
super.ReplicatedEvent( VarName );
}
if( VarName == nameOf(fChargePercentage))
{
fCachedCylinderWidth =Lerp(MinCollisionRadius, MaxCollisionRadius, fChargePercentage);
fCachedCylinderHeight = Lerp(MinCollisionHeight, MaxCollisionHeight, fChargePercentage);
CylinderComponent(CollisionComponent).SetCylinderSize(fCachedCylinderWidth, fCachedCylinderHeight);
ExplodeTriggerRadius = Lerp(MinExplodeTriggerRadiusPerPercentage, MaxExplodeTriggerRadiusPerPercentage, fChargePercentage);
ExplodeTriggerHeight = Lerp(MinExplodeTriggerHeightPerPercentage, MaxExplodeTriggerHeightPerPercentage, fChargePercentage);
ExplosionTemplate.DamageRadius = Lerp(MinDamageRadiusPerPercentage, MaxDamageRadiusPerPercentage, fChargePercentage);
ExplosionTemplate.Damage = Lerp(MinDamagePerPercentage, MaxDamagePerPercentage, fChargePercentage);
}
if(VarName == nameOf(StickInfo))
{
StickInClient(StickInfo.vRepStuckLocation, StickInfo.vRepStuckNormal);
}
if( VarName == nameOf(bArmed) )
{
if(bArmed)
{
SetPhysics( PHYS_Falling );
}
}
}
simulated function SetInheritedScale(float Scale, float ChargePercentage)
{
InheritedScale=Scale;
fChargePercentage=ChargePercentage;
fChargePercentage = FMax(0.1, fChargePercentage);
//ProjEffects.SetScale( InheritedScale );
CylinderComponent(CollisionComponent).SetCylinderSize(Lerp(MinCollisionRadius, MaxCollisionRadius, fChargePercentage), Lerp(MinCollisionHeight, MaxCollisionHeight, ChargePercentage));
ExplodeTriggerRadius = Lerp(MinExplodeTriggerRadiusPerPercentage, MaxExplodeTriggerRadiusPerPercentage, fChargePercentage);
ExplodeTriggerHeight = Lerp(MinExplodeTriggerHeightPerPercentage, MaxExplodeTriggerHeightPerPercentage, fChargePercentage);
ExplosionTemplate.DamageRadius = Lerp(MinDamageRadiusPerPercentage, MaxDamageRadiusPerPercentage, fChargePercentage);
ExplosionTemplate.Damage = Lerp(MinDamagePerPercentage, MaxDamagePerPercentage, fChargePercentage);
ExplodeTriggerRadius = FMax(0.1, ExplodeTriggerRadius);
ExplodeTriggerHeight = FMax(0.1, ExplodeTriggerHeight);
ExplosionTemplate.DamageRadius = FMax(0.1, ExplosionTemplate.DamageRadius);
ExplosionTemplate.Damage = FMax(0.1, ExplosionTemplate.Damage);
bNetDirty=true;
}
/** Adds our puke mine to the pool */
simulated event PostBeginPlay()
{
// Cache team num
TeamNum = GetTeamNum();
super.PostBeginPlay();
if( WorldInfo.NetMode != NM_Client )
{
if( InstigatorController != none || IsAIProjectile() )
{
//class'KFGameplayPoolManager'.static.GetPoolManager().AddProjectileToPool( self, PPT_MineReconstructor );
}
else
{
//Destroy();
//return;
}
}
if( Role == ROLE_Authority )
{
SetTimer( FuseDuration, false, nameOf(Timer_Explode) );
}
}
simulated function SpawnFlightEffects()
{
local vector vec;
vec.X = fChargePercentage;
vec.Y = fChargePercentage;
vec.Z = fChargePercentage;
super.SpawnFlightEffects();
//ProjEffects.SetScale( InheritedScale );
if(ProjEffects != None)
{
ProjEffects.SetVectorParameter( name("BlobCharge"), vec);
ProjEffects.SetFloatParameter( name("MineFxControlParam"), fChargePercentage);
}
}
/** Overridden to do nothing */
simulated function Shutdown() {}
simulated protected function StopSimulating() {}
simulated function Explode( vector HitLocation, vector HitNormal ) {
super.Explode(HitLocation, HitNormal);
}
/** Give a little bounce */
simulated event HitWall( vector HitNormal, Actor Wall, PrimitiveComponent WallComp )
{
// Don't collide with other puke mines
if( Wall.class == class )
{
return;
}
// Stick to static walls and destructible environment objects.
if( CanStick(Wall, HitNormal) && (Wall.bStatic == true || (Wall.bCanBeDamaged && KFPawn(Wall) == none)) )
{
Stick( Location, HitNormal );
}
else
{
Bounce( HitNormal, Wall );
}
}
simulated protected function bool CanStick( Actor HitActor, out vector HitNormal )
{
// Basic slope check
if( HitNormal.Z < MINMINEFLOORZ )
{
return false;
}
return true;
}
simulated event Bump( Actor Other, PrimitiveComponent OtherComp, Vector HitNormal )
{
if( Other.bWorldGeometry || Other.bStatic )
{
HitWall( HitNormal, Other, OtherComp );
}
}
function RestoreCylinder()
{
CylinderComponent(CollisionComponent).SetCylinderSize(fCachedCylinderWidth, fCachedCylinderHeight);
}
/** Adjusts movement/physics of projectile.
* Returns true if projectile actually bounced / was allowed to bounce */
simulated function bool Bounce( vector HitNormal, Actor BouncedOff )
{
local vector VNorm;
// Avoid crazy bouncing
if(CheckRepeatingTouch(BouncedOff))
{
CylinderComponent(CollisionComponent).SetCylinderSize(1,1);
SetTimer(0.06f, false, nameof(RestoreCylinder));
return false;
}
/*if(HitNormal.Z > 0.9f || HitNormal.Z < -0.9f)
{
HitNormal = -Velocity;
if(HitNormal.Z > 0)
{
HitNormal.Z = -HitNormal.Z;
HitNormal=Normal(HitNormal);
}
else
{
HitNormal=Normal(HitNormal);
}
}*/
// Reflect off BouncedOff w/damping
VNorm = (Velocity dot HitNormal) * HitNormal;
Velocity = -VNorm * DampenFactor + (Velocity - VNorm) * DampenFactorParallel;
Speed = VSize(Velocity);
if( Speed < 60 )
{
Speed = 200;
//Stick( Location, HitNormal );
//return false;
}
// Play a sound
PlayImpactSound();
return true;
}
simulated function ProcessTouch(Actor Other, Vector HitLocation, Vector HitNormal)
{
if (Other != Instigator && Other.GetTeamNum() != GetTeamNum() && !IsInState('Armed'))
{
ProcessBulletTouch(Other, HitLocation, HitNormal);
}
if (bCanStick || bCanPin)
{
StickHelper.TryStick(HitNormal, HitLocation, Other);
return;
}
if (ExplosionTemplate != None && Role == ROLE_Authority)
{
TriggerExplosion(HitLocation, HitNormal, Other);
}
Shutdown(); // cleanup/destroy projectile
}
/** Called once the mine has finished moving */
simulated function Stick( vector StuckLocation, vector StuckNormal )
{
local vector HitLocation, HitNormal;
local rotator StuckRotation;
local KFProj_Mine_Reconstructor PukeMine;
local rotator RandRot;
if( Role != ROLE_Authority ) return;
//we added a scapegoat that fixes the problem of hitwall not calling always in client, so we need to check it in case it comes
//to not call it twice
if(bSticked == true) return;
RotationRate = rot(0,0,0);
// Modify the collision so it can be detonated by the player
CylinderComponent.SetTraceBlocking( true, true );
SetCollisionSize( ExplodeTriggerRadius, ExplodeTriggerHeight );
CylinderComponent.SetActorCollision( true, false );
bCollideComplex = false;
bBounce = false;
SetPhysics( PHYS_None );
SetOwner( none );
// Optimize for network
NetUpdateFrequency = 10;
bOnlyDirtyReplication = true;
bForceNetUpdate = true;
// Set rotation
Trace( HitLocation, HitNormal, Location - vect(0,0,50), Location + vect(0,0,5), false,,, TRACEFLAG_Bullet );
if( !IsZero(HitLocation) )
{
StuckRotation = rotator( HitNormal );
}
else
{
StuckRotation = rotator( StuckNormal );
}
// Destroy any overlapping mines
if( Role == ROLE_Authority )
{
foreach TouchingActors( class'KFProj_Mine_Reconstructor', PukeMine )
{
PukeMine.TriggerExplosion( PukeMine.Location, vect(0,0,1), none );
}
}
SetRotation( StuckRotation );
// Apply some random yaw
RandRot.Yaw = Rand( 65535 );
SetRelativeRotation( RandRot );
// Swap to ground FX
SwapToGroundFX( StuckRotation );
// Play a sound
PlayImpactSound( true );
// Spawn an impact decal
SpawnImpactDecal( StuckLocation, StuckNormal );
// Go to armed state
GotoState( 'Armed' );
StickInfo.vRepStuckNormal=StuckNormal;
StickInfo.vRepStuckLocation=StuckLocation;
bNetDirty = true;
bSticked = true;
bArmed = true;
}
reliable client function StickInClient(vector StuckLocation, vector StuckNormal)
{
local vector HitLocation, HitNormal;
local rotator StuckRotation;
local rotator RandRot;
//we added a scapegoat that fixes the problem of hitwall not calling always in client, so we need to check it in case it comes
//to not call it twice
if(bSticked == true) return;
RotationRate = rot(0,0,0);
SetLocation(StuckLocation);
// Modify the collision so it can be detonated by the player
CylinderComponent.SetTraceBlocking( true, true );
SetCollisionSize( ExplodeTriggerRadius, ExplodeTriggerHeight );
CylinderComponent.SetActorCollision( true, false );
bCollideComplex = false;
bBounce = false;
SetOwner( none );
// Optimize for network
NetUpdateFrequency = 0.25f;
bOnlyDirtyReplication = true;
bForceNetUpdate = true;
// Set rotation
Trace( HitLocation, HitNormal, Location - vect(0,0,50), Location + vect(0,0,5), false,,, TRACEFLAG_Bullet );
if( !IsZero(HitLocation) )
{
StuckRotation = rotator( HitNormal );
}
else
{
StuckRotation = rotator( StuckNormal );
}
SetRotation( StuckRotation );
// Apply some random yaw
RandRot.Yaw = Rand( 65535 );
SetRelativeRotation( RandRot );
// Swap to ground FX
SwapToGroundFX( StuckRotation );
// Play a sound
PlayImpactSound( true );
// Spawn an impact decal
SpawnImpactDecal( StuckLocation, StuckNormal );
// Go to armed state
GotoState( 'Armed' );
bSticked = true;
bArmed = true;
}
/** Switch to ground fx */
simulated function SwapToGroundFX( rotator GroundRotation )
{
local vector vec;
// Replace the flying effects with ground FX
if(/* WorldInfo.NetMode != NM_DedicatedServer && */!IsInState('Armed') )
{
vec.X = fChargePercentage;
vec.Y = fChargePercentage;
vec.Z = fChargePercentage;
StopFlightEffects();
ProjFlightTemplate = GroundFXTemplate;
ProjFlightTemplateZedTime = GroundFXTemplate;
bAutoStartAmbientSound = true;
SpawnFlightEffects();
if(ProjEffects != None)
{
ProjEffects.SetAbsolute( true, true, false );
ProjEffects.SetTranslation( Location + LandedFXOffset );
ProjEffects.SetRotation( GroundRotation );
//ProjEffects.SetScale( InheritedScale );
ProjEffects.SetVectorParameter( name("BlobCharge"), vec);
ProjEffects.SetFloatParameter( name("MineFxControlParam"), fChargePercentage);
}
}
}
/** Plays a sound on impact */
simulated function PlayImpactSound( optional bool bIsAtRest )
{
if( WorldInfo.NetMode != NM_DedicatedServer )
{
if( bIsAtRest )
{
if(fChargePercentage < 0.75f)
PostAkEvent( ImpactAkEvent, true, true, false );
else
PostAkEvent( ImpactAkEventHeavy, true, true, false );
}
else
{
if(fChargePercentage < 0.75f)
PostAkEvent( BounceAkEvent, true, true, false );
else
PostAkEvent( BounceAkEventHeavy, true, true, false );
}
}
}
/** Spawns a decal at the impact location */
simulated function SpawnImpactDecal( vector HitLocation, vector HitNormal )
{
if( WorldInfo.MyDecalManager != none && !WorldInfo.bDropDetail && !IsInState('Armed'))
{
WorldInfo.MyDecalManager.SpawnDecal( ImpactDecalMaterial, HitLocation, rotator(-HitNormal), ImpactDecalWidth, ImpactDecalHeight, ImpactDecalThickness, true );
}
}
/** Validates a touch */
simulated function bool ValidTouch( Pawn Other )
{
// Make sure only enemies detonate
if(bCantBeTouchedByInstigator == false)
{
if( Other.IsAliveAndWell() == false )
{
return false;
}
if(bCantDetonateOnFullHP)
{
if(Other.GetTeamNum() == TeamNum && Other.Health >= Other.HealthMax )
{
return false;
}
}
// Make sure not touching through wall
return FastTrace( Other.Location, Location,, true );
}
else
{
if(bCantDetonateOnFullHP)
{
if(Other.GetTeamNum() == TeamNum && Other.Health >= Other.HealthMax )
{
return false;
}
}
if( Other.IsAliveAndWell() == false || Other == Instigator )
{
return false;
}
// Make sure not touching through wall
return FastTrace( Other.Location, Location,, true );
}
return FastTrace( Other.Location, Location,, true );
}
/** When touched by an actor */
simulated event Touch( Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal )
{
local Pawn P;
// If touched by an enemy pawn, explode
P = Pawn( Other );
if( P != None )
{
if( ((P != Instigator) || (`TimeSince(CreationTime) >= 0.1f && P == Instigator)) && ValidTouch(P) )
{
//super.Touch( Other, OtherComp, HitLocation, HitNormal );
ImpactedActor = Other;
ProcessTouch(Other, HitLocation, HitNormal);
ImpactedActor = none;
}
}
else if( bBounce )
{
super.Touch( Other, OtherComp, HitLocation, HitNormal );
}
}
/** Blows up mine immediately */
function Detonate()
{
if( Role == ROLE_Authority )
{
TriggerExplosion( Location, vect(0,0,1), none );
}
}
/** Blows up mine immediately */
function ManuallyDetonate()
{
bManuallyDetonated = true;
if( Role == ROLE_Authority )
{
TriggerExplosion( Location, vect(0,0,1), none );
}
}
/** Blows up on a timer */
function Timer_Explode()
{
Detonate();
}
/** Explode this mine */
simulated function TriggerExplosion(Vector HitLocation, Vector HitNormal, Actor HitActor)
{
// If we're fading out, don't explode
if( bFadingOut )
{
return;
}
super.TriggerExplosion( Location, HitNormal , HitActor );
SetHidden( true );
/** Tell clients to explode */
if( Role == ROLE_Authority )
{
bClientExplode = true;
bForceNetUpdate = true;
}
}
/** Tells clients to start fading out */
simulated event TornOff()
{
FadeOut();
}
/** Fades this mine out and destroys it */
simulated function FadeOut()
{
// If we're in midair, just destroy
if( Physics == PHYS_Falling )
{
Destroy();
return;
}
// Already fading, early out
if( bFadingOut || bDeleteMe || (WorldInfo.NetMode == NM_DedicatedServer && bTearOff) )
{
return;
}
// Remove ownership
SetOwner( none );
// Turn off collision
SetCollision( false, false );
// Dedicated server doesn't need to fade
if( WorldInfo.NetMode != NM_DedicatedServer )
{
// Set initial fade values
bFadingOut = false;
FadeOutTime = WorldInfo.TimeSeconds + default.FadeOutTime;
}
else
{
// Delay destruction slightly
SetTimer( 0.2f, false, nameOf(Timer_Destroy) );
}
// Tell clients to tear off and fade out on their own
if( WorldInfo.NetMode != NM_Client )
{
bTearOff = true;
bNetDirty = true;
bForceNetUpdate = true;
}
}
simulated function Timer_Destroy()
{
Destroy();
}
/** Spawns a small burst effect when the mine has finished shrinking */
simulated function SpawnBurstEffect()
{
if( WorldInfo.NetMode == NM_DedicatedServer || WorldInfo.MyEmitterPool == none || ProjEffects == none )
{
return;
}
WorldInfo.MyEmitterPool.SpawnEmitter( BurstFXTemplate, ProjEffects.GetPosition(), rotator(vect(0,0,1)) );
}
/** Removes our puke mine from the pool */
simulated event Destroyed()
{
if( WorldInfo.NetMode != NM_Client )
{
if( InstigatorController != none )
{
class'KFGameplayPoolManager'.static.GetPoolManager().RemoveProjectileFromPool( self, PPT_PukeMine );
}
}
super.Destroyed();
}
/**
* State where this mine is waiting to detonate
*/
simulated state Armed
{
/** Make sure no pawn already touching */
simulated function CheckTouching()
{
local Pawn P;
foreach TouchingActors( class'Pawn', P )
{
Touch( P, None, Location, Normal(Location - P.Location) );
}
}
/** Adjust collision */
simulated function BeginState( Name PreviousStateName )
{
if(Role != Role_Authority)
{
SetPhysics( PHYS_Falling );
CheckTouching();
}
}
}
simulated protected function PrepareExplosionTemplate()
{
local Weapon OwnerWeapon;
local KFWeap_Mine_Reconstructor OwnerMinerec;
local Pawn OwnerPawn;
//local vector vec;
super(KFProjectile).PrepareExplosionTemplate();
//vec.X = 0;
//vec.Y = 0;
//vec.Z = 0;
OwnerWeapon = Weapon(Owner);
if (OwnerWeapon != none)
{
OwnerPawn = Pawn(OwnerWeapon.Owner);
if (OwnerPawn != none)
{
//vec.X = fChargePercentage;
//vec.Y = fChargePercentage;
//vec.Z = fChargePercentage;
ExplosionTemplate.DamageRadius *= KFPawn(OwnerPawn).GetPerk().GetAoERadiusModifier();
if(fChargePercentage > 0.51f)
ExplosionTemplate.ExplosionSound=AkEvent'WW_WEP_MineReconstructor.Play_WEP_Mine_Reconstructor_Mine_Explosion_Heavy';
//ExplosionTemplate.ExplosionEffects.DefaultImpactEffect.ParticleTemplate.SetVectorParameter( name("BlobCharge"), vec);
//SetFloatParameter( name("MineFxControlParam"), fChargePercentage);
OwnerMinerec = KFWeap_Mine_Reconstructor(OwnerWeapon);
if(OwnerMinerec != none && !bManuallyDetonated)
OwnerMinerec.RemoveProjectileFromPool(self);
}
}
}
simulated protected function PrepareExplosionActor(GameExplosionActor GEA)
{
KFExplosion_MineReconstructor(GEA).fChargePercentage = fChargePercentage;
super.PrepareExplosionActor(GEA);
}
/** Controller left, explode after a short time */
/*simulated function OnInstigatorControllerLeft()
{
if( WorldInfo.NetMode != NM_Client )
{
SetTimer( 1.f + Rand(5) + fRand(), false, nameOf(Timer_Explode) );
}
}*/
defaultproperties
{
Speed=2000
MaxSpeed=2000
TerminalVelocity=2000
TossZ=150
GravityScale=0.5
MomentumTransfer=50000.0
LifeSpan=300
FuseDuration=300
PostExplosionLifetime=1
Physics=PHYS_Falling
bBounce=true
ProjFlightTemplate= ParticleSystem'WEP_Mine_Reconstructor_EMIT.FX_Bloat_Mine_projectile_01'
GroundFXTemplate= ParticleSystem'WEP_Mine_Reconstructor_EMIT.FX_Bloat_Mine_01'
BurstFXTemplate= ParticleSystem'WEP_Mine_Reconstructor_EMIT.FX_Bloat_Mine_Hit_01'
ExplosionActorClass=class'KFExplosion_MineReconstructor'
bSuppressSounds=false
bAmbientSoundZedTimeOnly=false
bAutoStartAmbientSound=false
bStopAmbientSoundOnExplode=true
AmbientSoundPlayEvent=AkEvent'WW_WEP_MineReconstructor.Play_WEP_Mine_Reconstructor_Mine_Loop'
AmbientSoundStopEvent=AkEvent'WW_WEP_MineReconstructor.Stop_WEP_Mine_Reconstructor_Mine'
ImpactAkEvent=AkEvent'WW_WEP_MineReconstructor.Play_WEP_Mine_Reconstructor_Mine'
BounceAkEvent=AkEvent'WW_WEP_MineReconstructor.Play_WEP_Mine_Reconstructor_Mine'
ImpactAkEventHeavy=AkEvent'WW_WEP_MineReconstructor.Play_WEP_Mine_Reconstructor_Mine_Heavy'
BounceAkEventHeavy=AkEvent'WW_WEP_MineReconstructor.Play_WEP_Mine_Reconstructor_Mine_Heavy'
Begin Object Class=AkComponent name=AmbientAkSoundComponent
bStopWhenOwnerDestroyed=true
bForceOcclusionUpdateInterval=true
OcclusionUpdateInterval=0.25f
End Object
AmbientComponent=AmbientAkSoundComponent
Components.Add(AmbientAkSoundComponent)
//ImpactDecalMaterial=DecalMaterial'FX_Mat_Lib.FX_Puke_Mine_Splatter_DM'
ImpactDecalWidth=178.f
ImpactDecalHeight=178.f
ImpactDecalThickness=28.f
Begin Object Name=CollisionCylinder
CollisionRadius=10.f
CollisionHeight=10.f
CollideActors=true
PhysMaterialOverride=PhysicalMaterial'WEP_Mine_Reconstructor_EMIT.BloatPukeMine_PM'
End Object
bCollideActors=true
bProjTarget=true
bCanBeDamaged=false
bCollideComplex=true
bNoEncroachCheck=true
bPushedByEncroachers=false
DampenFactor=0.125f
DampenFactorParallel=0.175f
LandedFXOffset=(X=0,Y=0,Z=2)
// Since we're still using an extent cylinder, we need a line at 0
ExtraLineCollisionOffsets.Add(())
// Collision size we should use when waiting to be triggered
ExplodeTriggerRadius=60.f
ExplodeTriggerHeight=22.f
// Fade out properties
FadeOutTime=500000f
// Explosion
Begin Object Class=KFGameExplosion Name=ExploTemplate0
Damage=150 //30
DamageRadius=200 //450
DamageFalloffExponent=0.5f //0.f
DamageDelay=0.f
MyDamageType=class'KFDT_Toxic_MineReconstructorExplosion'
//bIgnoreInstigator is set to true in PrepareExplosionTemplate
//Impulse applied to Zeds
MomentumTransferScale=45000
// Damage Effects
KnockDownStrength=0
KnockDownRadius=0
FractureMeshRadius=200.0
FracturePartVel=500.0
ExplosionEffects=KFImpactEffectInfo'WEP_Mine_Reconstructor_Arch.Mine_Reconstructor_Mine_Explosion'
ExplosionSound=AkEvent'WW_WEP_MineReconstructor.Play_WEP_Mine_Reconstructor_Mine_Explosion'
//MomentumTransferScale=0
// Dynamic Light
ExploLight=none
// Camera Shake
CamShake=CameraShake'WEP_Mine_Reconstructor_Arch.Camera_Shake'
CamShakeInnerRadius=200
CamShakeOuterRadius=400
CamShakeFalloff=1.f
bOrientCameraShakeTowardsEpicenter=true
End Object
ExplosionTemplate=ExploTemplate0
GlassShatterType=FMGS_ShatterAll
InheritedScale=1
MaxExplodeTriggerRadiusPerPercentage=60
MinExplodeTriggerRadiusPerPercentage=30
MaxExplodeTriggerHeightPerPercentage=22
MinExplodeTriggerHeightPerPercentage=11
MaxDamageRadiusPerPercentage=340
MinDamageRadiusPerPercentage=160
MaxDamagePerPercentage=350 //300
MinDamagePerPercentage=35 //30
MaxCollisionRadius=20
MinCollisionRadius=10
MaxCollisionHeight=20
MinCollisionHeight=10
bBlockedByInstigator=true
bNetTemporary=false
bSyncToOriginalLocation=true
bSyncToThirdPersonMuzzleLocation=true
bUseClientSideHitDetection=true
bUpdateSimulatedPosition=false
bReplicateLocationOnExplosion=true
bSticked=false
TouchTimeThreshhold=0.05
//EXPERIMENTAL FEATURES FOR DESING
bManuallyDetonated=false
bCantBeTouchedByInstigator=true
bCantDetonateOnFullHP=true
}