1
0
KF2-Dev-Scripts/KFGameContent/Classes/KFProj_HighExplosive_HRG_Warthog.uc
2023-05-25 23:42:10 +03:00

423 lines
13 KiB
Ucode

//=============================================================================
// KFProj_HighExplosive_HRG_Warthog
//=============================================================================
// High explosive grenade launcher grenade for the HRG Warthog
//=============================================================================
// Killing Floor 2
// Copyright (C) 2023 Tripwire Interactive LLC
//=============================================================================
class KFProj_HighExplosive_HRG_Warthog extends KFProj_BallisticExplosive
hidedropdown;
var transient bool bHitWall;
simulated event PreBeginPlay()
{
local KFPawn InstigatorPawn;
local KFPawn_HRG_Warthog InstigatorPawnWarthog;
InstigatorPawnWarthog = KFPawn_HRG_Warthog(Instigator);
if (InstigatorPawnWarthog != none)
{
InstigatorPawn = KFPawn(InstigatorPawnWarthog.OwnerWeapon.Instigator);
if (InstigatorPawn != none)
{
Instigator = InstigatorPawn;
}
}
Super.PreBeginPlay();
}
simulated function bool AllowNuke()
{
return true;
}
simulated function bool AllowDemolitionistConcussive()
{
return true;
}
simulated function bool AllowDemolitionistExplosionChangeRadius()
{
return true;
}
// Used by Demolitionist Nuke and Mad Bomber skills
simulated function bool CanDud()
{
return false;
}
simulated function SetupDetonationTimer(float FuseTime)
{
if (FuseTime > 0)
{
bIsTimedExplosive = true;
SetTimer(FuseTime, false, 'ExplodeTimer');
}
}
function ExplodeTimer()
{
local Actor HitActor;
local vector HitLocation, HitNormal;
GetExplodeEffectLocation(HitLocation, HitNormal, HitActor);
TriggerExplosion(HitLocation, HitNormal, HitActor);
}
/**
* Trace down and get the location to spawn the explosion effects and decal
*/
simulated function GetExplodeEffectLocation(out vector HitLocation, out vector HitRotation, out Actor HitActor)
{
local vector EffectStartTrace, EffectEndTrace;
local TraceHitInfo HitInfo;
EffectStartTrace = Location + vect(0,0,1) * 4.f;
EffectEndTrace = EffectStartTrace - vect(0,0,1) * 32.f;
// Find where to put the decal
HitActor = Trace(HitLocation, HitRotation, EffectEndTrace, EffectStartTrace, false,, HitInfo, TRACEFLAG_Bullet);
// If the locations are zero (probably because this exploded in the air) set defaults
if( IsZero(HitLocation) )
{
HitLocation = Location;
}
if( IsZero(HitRotation) )
{
HitRotation = vect(0,0,1);
}
}
simulated event HitWall(vector HitNormal, actor Wall, PrimitiveComponent WallComp)
{
local Vector VNorm;
local rotator NewRotation;
local Vector Offset;
bHitWall = true;
if (bIsTimedExplosive)
{
// Reflect off Wall w/damping
VNorm = (Velocity dot HitNormal) * HitNormal;
Velocity = -VNorm * DampenFactor + (Velocity - VNorm) * DampenFactorParallel;
Speed = VSize(Velocity);
if (WorldInfo.NetMode != NM_DedicatedServer && Pawn(Wall) == none)
{
// do the impact effects
`ImpactEffectManager.PlayImpactEffects(Location, Instigator, HitNormal, GrenadeBounceEffectInfo, true );
}
// if we hit a pawn or we are moving too slowly stop moving and lay down flat
if ( Speed < MinSpeedBeforeStop )
{
ImpactedActor = Wall;
SetPhysics(PHYS_None);
if( ProjEffects != none )
{
ProjEffects.SetTranslation(LandedTranslationOffset);
}
// Position the shell on the ground
RotationRate.Yaw = 0;
RotationRate.Pitch = 0;
RotationRate.Roll = 0;
NewRotation = Rotation;
NewRotation.Pitch = 0;
if(ResetRotationOnStop)
{
SetRotation(NewRotation);
}
Offset.Z = LandedTranslationOffset.X;
SetLocation(Location + Offset);
}
return;
}
if( WorldInfo.NetMode == NM_Standalone ||
(WorldInfo.NetMode == NM_ListenServer && Instigator != none && Instigator.IsLocallyControlled()) )
{
TriggerExplosion(Location, HitNormal, None);
Shutdown(); // cleanup/destroy projectile
return;
}
if( Owner != none && KFWeapon( Owner ) != none && Instigator != none )
{
if( Instigator.Role == ROLE_Authority)
{
KFWeap_HRG_WarthogWeapon(Owner).ForceExplosionReplicateKill(Location, self);
}
}
StopSimulating(); // cleanup/destroy projectile
}
simulated function ProcessTouch(Actor Other, Vector HitLocation, Vector HitNormal)
{
// If we collided with a Siren shield, let the shield code handle touches
if( Other.IsA('KFTrigger_SirenProjectileShield') )
{
return;
}
if ( !bCollideWithTeammates && Pawn(Other) != None )
{
// Don't hit teammates
if( Other.GetTeamNum() == GetTeamNum() )
{
return;
}
}
// Process impact hits
if (Other != Instigator && !Other.bStatic)
{
ProcessBulletTouch(Other, HitLocation, HitNormal);
}
if (bIsTimedExplosive)
{
return;
}
if( WorldInfo.NetMode == NM_Standalone ||
(WorldInfo.NetMode == NM_ListenServer && Instigator != none && Instigator.IsLocallyControlled()) )
{
// Call KFProjectile base code.. as we don't want to repeat the KFProj_BallisticExplosive base again
TriggerExplosion(HitLocation, HitNormal, Other);
Shutdown(); // cleanup/destroy projectile
return;
}
if( Owner != none && KFWeapon( Owner ) != none && Instigator != none )
{
// Special case, for some very complicate reason around replication, instigators and the Warthog pawn
// This code on the base class was never triggered on Clients: (IsLocallyControlled() always fails, also on the rightful owner of he projectile)
// if( Instigator.Role < ROLE_Authority && Instigator.IsLocallyControlled() )
// Hence we call here a reliable client function on the Owner
// That will call exactly the same code that's inside that If on the base class of this file
if( Instigator.Role == ROLE_Authority)
{
KFWeap_HRG_WarthogWeapon(Owner).ForceExplosionReplicate(Other, HitLocation, HitNormal, self);
}
}
StopSimulating();
}
simulated event Tick(float DeltaTime)
{
Super.Tick(DeltaTime);
if (WorldInfo.NetMode != NM_DedicatedServer)
{
if (bHitWall == false)
{
SetRotation(rotator(Normal(Velocity)));
}
}
}
/** This will cause the projectile to move to the Original Spawn location when first replicated. This solves the issue of the projectile spawning some distance away from the player when first replicated */
simulated function SyncOriginalLocation()
{
local vector MuzzleLocation, PredictedHitLocation, AimDir, EndTrace, MuzzleToPredictedHit;
if ( WorldInfo.NetMode == NM_DedicatedServer )
{
return;
}
// For remote pawns, have the projectile look like its actually
// coming from the muzzle of the third person weapon
if( bSyncToThirdPersonMuzzleLocation && Instigator != none
&& !Instigator.IsFirstPerson() && KFPawn(Owner) != none
&& KFPawn(Owner).WeaponAttachment != none )
{
MuzzleLocation = KFPawn(Owner).WeaponAttachment.GetMuzzleLocation(bFiredFromLeftHandWeapon ? 1 : 0);
// Set the aim direction to the vector along the line where the
// projectile would hit based on velocity. This is the most accurate
if( !IsZero(Velocity) )
{
AimDir = Normal(Velocity);
}
// Set the aim direction to the vector along the line where the
// projectile would hit based on where it has moved away from
// the original location
if( IsZero(Velocity) )
{
AimDir = Normal(Location-OriginalLocation);
}
// Use the rotation if the location calcs give a zero direction
if( IsZero(AimDir) )
{
AimDir = Normal(Vector(Rotation));
}
if( Location != MuzzleLocation )
{
// if projectile is spawned at different location than the third
// person muzzle location, then simulate an instant trace where
// the projectile would hit
EndTrace = Location + AimDir * 16384;
PredictedHitLocation = GetPredictedHitLocation(Location, EndTrace);
MuzzleToPredictedHit = Normal(PredictedHitLocation - MuzzleLocation);
// only adjust AimDir if PredictedHitLocation is "forward" (i.e. don't let projectile fire back towards the shooter)
//@todo: still need to make this less wonky (can still shoot straight up sometimes when using long weapons, like the sawblade shooter)
if( MuzzleToPredictedHit dot vector(Rotation) > 0.f )
{
// Then we realign projectile aim direction to match where the projectile would hit.
AimDir = MuzzleToPredictedHit;
}
}
// Move the projectile to the MuzzleLocation
SetLocation(MuzzleLocation);
// If the Velocity is zero (usually because the projectile impacted
// something on the server in its first tick before replicating)
// then turn its phyics and collion back on
if( IsZero(Velocity) )
{
SetPhysics(default.Physics);
SetCollision( default.bCollideActors, default.bBlockActors );
}
// Adjust the velocity of the projectile so it will hit where
// it is supposed to
Velocity = Speed * Normal(AimDir);
}
// set location based on 'OriginalLocation'
else if ( Role < ROLE_Authority )
{
// If the Velocity is zero (usually because the projectile impacted
// something on the server in its first tick before replicating)
// then turn its physics and collion back on and give it velocity
// again so the simulation will work properly on the client
if( IsZero(Velocity) )
{
SetPhysics(default.Physics);
// Set the aim direction to the vector along the line where the
// projectile would hit
AimDir = Normal(Location-OriginalLocation);
// Use the rotation if the location calcs give a zero direction
if( IsZero(AimDir) )
{
AimDir = Vector(Rotation);
}
Velocity = Speed * AimDir;
SetCollision( default.bCollideActors, default.bBlockActors );
}
SetLocation(OriginalLocation);
}
}
defaultproperties
{
bCollideWithTeammates = false
Physics=PHYS_Falling
Speed=2000
MaxSpeed=2000
TerminalVelocity=2000
TossZ=0
GravityScale=1.0
MomentumTransfer=50000.0
ArmDistSquared=0
LifeSpan=25.0f
bIsTimedExplosive = false
bWarnAIWhenFired=true
ProjFlightTemplate=ParticleSystem'WEP_HRG_Warthog_EMIT.FX_HRG_Warthog_Projectile'
ProjFlightTemplateZedTime=ParticleSystem'WEP_HRG_Warthog_EMIT.FX_HRG_Warthog_Projectile_ZEDTIME'
ProjDudTemplate=ParticleSystem'WEP_HRG_Warthog_EMIT.FX_HRG_Warthog_Projectile_Dud'
GrenadeBounceEffectInfo=KFImpactEffectInfo'FX_Impacts_ARCH.DefaultGrenadeImpacts'
ProjDisintegrateTemplate=ParticleSystem'ZED_Siren_EMIT.FX_Siren_grenade_disable_01'
AltExploEffects=KFImpactEffectInfo'WEP_HRG_Warthog_ARCH.HRG_Warthog_Explosion_Concussive_Force'
// Grenade 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
ExplosionActorClass=class'KFExplosion_HRG_Warthog'
// explosion
Begin Object Class=KFGameExplosion Name=ExploTemplate0
Damage=50
DamageRadius=200
DamageFalloffExponent=1
DamageDelay=0.f
// Damage Effects
MyDamageType=class'KFDT_Explosive_HRG_Warthog_HighExplosive'
KnockDownStrength=0
FractureMeshRadius=200.0
FracturePartVel=500.0
ExplosionEffects=KFImpactEffectInfo'WEP_HRG_WarthogWeapon_ARCH.HRG_WarthogWeapon_GrenadeExplosion'
ExplosionSound=AkEvent'WW_WEP_HRG_Warthog.Play_WEP_HRG_Warthog_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
bIgnoreInstigator=true
ActorClassToIgnoreForDamage = class'KFPawn_Human'
End Object
ExplosionTemplate=ExploTemplate0
AmbientSoundPlayEvent=AkEvent'WW_WEP_HRG_Warthog.Play_WEP_HRG_Warthog_Projectile_LP'
AmbientSoundStopEvent=AkEvent'WW_WEP_HRG_Warthog.Stop_WEP_HRG_Warthog_Projectile'
// The higher the more bouncing
DampenFactor=0.4f
DampenFactorParallel=0.4f
bHitWall = false
}