293 lines
7.8 KiB
Ucode
293 lines
7.8 KiB
Ucode
//=============================================================================
|
|
// KFProj_Dosh
|
|
//=============================================================================
|
|
// Projectile for the doshinegun
|
|
//=============================================================================
|
|
// Killing Floor 2
|
|
// Copyright (C) 2021 Tripwire Interactive LLC
|
|
//=============================================================================
|
|
|
|
class KFProj_Dosh extends KFProj_RicochetBullet
|
|
hidedropdown;
|
|
|
|
`define KFPROJ_DOSH_CACHED_LOCATION 20
|
|
|
|
var PrimitiveComponent DroppedPickupMesh;
|
|
|
|
/** Dampen amount for every bounce */
|
|
var() float DampenFactor;
|
|
|
|
/** Dampen amount for parallel angle to velocity */
|
|
var() float DampenFactorParallel;
|
|
|
|
var transient Vector PreviousLocations [`KFPROJ_DOSH_CACHED_LOCATION];
|
|
var transient rotator PreviousRotations [`KFPROJ_DOSH_CACHED_LOCATION];
|
|
var transient Vector Ceiling;
|
|
|
|
// Make sure that last location always exists.
|
|
simulated event PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
}
|
|
|
|
event Tick( float DeltaTime )
|
|
{
|
|
local int i;
|
|
for (i = `KFPROJ_DOSH_CACHED_LOCATION - 1; i > 0; --i)
|
|
{
|
|
PreviousLocations[i] = PreviousLocations[i-1];
|
|
PreviousRotations[i] = PreviousRotations[i-1];
|
|
}
|
|
|
|
if (`KFPROJ_DOSH_CACHED_LOCATION > 0)
|
|
{
|
|
PreviousLocations[0] = Location;
|
|
PreviousRotations[0] = Rotation;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Give a little bounce
|
|
*/
|
|
simulated event HitWall(vector HitNormal, Actor Wall, PrimitiveComponent WallComp)
|
|
{
|
|
local TraceHitInfo HitInfo;
|
|
|
|
// check to make sure we didn't hit a pawn
|
|
if( Pawn(Wall) == none )
|
|
{
|
|
if (!Wall.bStatic && Wall.bCanBeDamaged && (DamageRadius == 0 || bDamageDestructiblesOnTouch) && !CheckRepeatingTouch(Wall) )
|
|
{
|
|
HitInfo.HitComponent = WallComp;
|
|
HitInfo.Item = INDEX_None;
|
|
Wall.TakeDamage( Damage, InstigatorController, Location, MomentumTransfer * Normal(Velocity), MyDamageType, HitInfo, self);
|
|
}
|
|
}
|
|
|
|
Bounce( HitNormal, Wall );
|
|
}
|
|
|
|
/** Adjusts movement/physics of projectile.
|
|
* Returns true if projectile actually bounced / was allowed to bounce */
|
|
simulated function bool Bounce( vector HitNormal, Actor BouncedOff)
|
|
{
|
|
Velocity = DampingFactor * (Velocity - 2.0*HitNormal*(Velocity dot HitNormal));
|
|
if( WorldInfo.NetMode != NM_DedicatedServer )
|
|
{
|
|
// do the impact effects
|
|
`ImpactEffectManager.PlayImpactEffects(Location, Instigator, HitNormal, ImpactEffects );
|
|
}
|
|
|
|
// also done from ProcessDestructibleTouchOnBounce. update LastBounced to solve problem with bouncing rapidly between world/non-world geometry
|
|
LastBounced.Actor = BouncedOff;
|
|
LastBounced.Time = WorldInfo.TimeSeconds;
|
|
|
|
SpawnDosh(BouncedOff);
|
|
Destroy();
|
|
|
|
return true;
|
|
}
|
|
|
|
function SpawnDosh(Actor BouncedOff)
|
|
{
|
|
local KFDroppedPickup_Cash P;
|
|
local int i;
|
|
local Vector Pos;
|
|
local rotator Rot;
|
|
|
|
if ( WorldInfo.NetMode == NM_Client )
|
|
return;
|
|
|
|
if (Pawn(BouncedOff) == none)
|
|
{
|
|
Pos = Location;
|
|
Rot = Rotation;
|
|
P = Spawn(class'KFDroppedPickup_Cash',,, Pos, Rot,, false);
|
|
|
|
if (P == none)
|
|
{
|
|
for (i = 0; i < `KFPROJ_DOSH_CACHED_LOCATION; ++i)
|
|
{
|
|
Pos = PreviousLocations[i];
|
|
Rot = PreviousRotations[i];
|
|
P = Spawn(class'KFDroppedPickup_Cash',,, Pos, Rot,, false);
|
|
if (P != none)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// DrawDebugSphere( Pos, 20, 8, 0, 255, 255, true );
|
|
if (P != none && RelocateFromCeiling(Pos))
|
|
{
|
|
P.Destroy();
|
|
if(Ceiling.Z > -10000)
|
|
{
|
|
// DrawDebugSphere( Ceiling, 22, 8, 255, 255, 0, true );
|
|
P = Spawn(class'KFDroppedPickup_Cash',,, Ceiling, Rot,, false);
|
|
Velocity = vect(0,0,0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
P = Spawn(class'KFDroppedPickup_Cash',,, Location, Rotation,, true);
|
|
}
|
|
|
|
if( P == None )
|
|
{
|
|
Destroy();
|
|
}
|
|
else
|
|
{
|
|
P.SetPhysics(PHYS_Falling);
|
|
P.InventoryClass = class'KFInventory_Money';
|
|
P.Inventory = Instigator.CreateInventory(P.InventoryClass);
|
|
P.Velocity = Velocity;
|
|
P.Instigator = Instigator;
|
|
P.SetPickupMesh(DroppedPickupMesh);
|
|
P.SetPickupParticles(none);
|
|
P.CashAmount = class'KFWeap_AssaultRifle_Doshinegun'.default.DoshCost;
|
|
}
|
|
|
|
}
|
|
|
|
//==============
|
|
// Touching
|
|
// Overridden to get bouncing off of destructible meshes
|
|
simulated function ProcessTouch(Actor Other, Vector HitLocation, Vector HitNormal)
|
|
{
|
|
local KFPawn KFP;
|
|
local KFPawn_Human KFPH;
|
|
local KFPlayerReplicationInfo KFPRI;
|
|
local TraceHitInfo HitInfo;
|
|
|
|
KFPH = KFPawn_Human(Other);
|
|
if ( KFPH != none && KFPH != Instigator)
|
|
{
|
|
KFPRI = KFPlayerReplicationInfo(KFPH.PlayerReplicationInfo);
|
|
if (KFPRI != none)
|
|
{
|
|
KFPRI.AddDosh(class'KFWeap_AssaultRifle_Doshinegun'.default.DoshCost);
|
|
Destroy();
|
|
return;
|
|
}
|
|
}
|
|
else if ( Other != Instigator && Other.bCanBeDamaged )
|
|
{
|
|
KFP = KFPawn( Other );
|
|
if ( KFP != None )
|
|
{
|
|
// check/ignore repeat touch events
|
|
if( CheckRepeatingTouch(Other) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
ProcessBulletTouch(Other, HitLocation, HitNormal);
|
|
|
|
Bounce(HitNormal, Other);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
HitInfo.HitComponent = LastTouchComponent;
|
|
HitInfo.Item = INDEX_None; // force TraceComponent on fractured meshes
|
|
Other.TakeDamage(Damage, InstigatorController, HitLocation, MomentumTransfer * Normal(Velocity), MyDamageType, HitInfo, self);// special cases for types of destructibles, bShouldBreakSolidGlassOnBounce
|
|
return;
|
|
}
|
|
}
|
|
|
|
super.ProcessTouch(Other, HitLocation, HitNormal);
|
|
}
|
|
|
|
simulated function SyncOriginalLocation()
|
|
{
|
|
local Actor HitActor;
|
|
local vector HitLocation, HitNormal;
|
|
local TraceHitInfo HitInfo;
|
|
|
|
if (Role < ROLE_Authority && Instigator != none && Instigator.IsLocallyControlled())
|
|
{
|
|
HitActor = Trace(HitLocation, HitNormal, OriginalLocation, Location,,, HitInfo, TRACEFLAG_Bullet);
|
|
if (HitActor != none)
|
|
{
|
|
Bounce(HitNormal, HitActor);
|
|
}
|
|
}
|
|
|
|
Super.SyncOriginalLocation();
|
|
}
|
|
|
|
simulated function bool RelocateFromCeiling(Vector Pos)
|
|
{
|
|
local Actor HitActorVolume, HitActorWorld, HitActorVolumeBack;
|
|
local Vector HitLocationVolume, HitLocationWorld;
|
|
local Vector HitNormalUnused;
|
|
|
|
HitActorWorld = Owner.Trace(HitLocationWorld, HitNormalUnused, Pos - vect(0,0,10000), Pos, false,,,TRACEFLAG_Bullet);
|
|
if(HitActorWorld != none)
|
|
{
|
|
HitActorVolume = KFWeapon(Owner).DoTraceNative(HitLocationVolume, Pos, Pos - vect(0,0,10000));
|
|
if (HitActorVolume == none || (HitLocationWorld.Z + 80) > HitLocationVolume.Z || IsZero(HitLocationVolume-Pos))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// DrawDebugSphere( HitLocationWorld , 32, 8, 0, 255, 0, true );
|
|
// DrawDebugSphere( HitLocationVolume, 30, 8, 255, 0, 0, true );
|
|
|
|
HitLocationWorld += vect(0,0,1);
|
|
HitActorVolumeBack = KFWeapon(Owner).DoTraceNative(HitLocationVolume, HitLocationWorld, HitLocationWorld + vect(0,0,10000));
|
|
if (HitActorVolumeBack != none && !IsZero(HitLocationVolume-HitLocationWorld))
|
|
{
|
|
// DrawDebugSphere( HitLocationVolume, 28, 8, 255, 255, 0, true );
|
|
Ceiling = HitLocationVolume - vect(0,0,10);
|
|
return true;
|
|
}
|
|
}
|
|
Ceiling = Vect(0,0,-10000);
|
|
return true;
|
|
}
|
|
|
|
|
|
defaultproperties
|
|
{
|
|
MaxSpeed=7500.0 //5000.0
|
|
Speed=7500.0 //5000.0
|
|
GravityScale=0.57 //0.4
|
|
|
|
Physics=PHYS_Falling
|
|
TossZ=100 //150
|
|
MomentumTransfer=50000.0
|
|
|
|
DamageRadius=0
|
|
|
|
bWarnAIWhenFired=true
|
|
|
|
BouncesLeft=1
|
|
DampingFactor=0.1
|
|
|
|
DampenFactor=0.250000
|
|
DampenFactorParallel=0.400000
|
|
LifeSpan=120 //8
|
|
|
|
bNetTemporary=False
|
|
NetPriority=5
|
|
NetUpdateFrequency=200
|
|
|
|
ProjFlightTemplate=ParticleSystem'WEP_Doshinegun_EMIT.PS_Trail'
|
|
ProjFlightTemplateZedTime=ParticleSystem'WEP_Doshinegun_EMIT.PS_Trail'
|
|
|
|
ImpactEffects=KFImpactEffectInfo'WEP_Doshinegun_ARCH.Dosh_Impact'
|
|
|
|
Begin Object Class=SkeletalMeshComponent Name=PickupMesh0
|
|
SkeletalMesh=SkeletalMesh'GP_Mesh.dosh_SM'
|
|
PhysicsAsset=PhysicsAsset'GP_Mesh.dosh_SM_Physics'
|
|
BlockNonZeroExtent=false
|
|
CastShadow=false
|
|
End Object
|
|
DroppedPickupMesh=PickupMesh0
|
|
}
|