344 lines
9.6 KiB
Ucode
344 lines
9.6 KiB
Ucode
//=============================================================================
|
|
// M99Bullet
|
|
//=============================================================================
|
|
// M99 Sniper Rifle bullet class
|
|
//=============================================================================
|
|
// Killing Floor Source
|
|
// Copyright (C) 2012 Tripwire Interactive LLC
|
|
// - John "Ramm-Jaeger" Gibson, and IJC Development
|
|
//=============================================================================
|
|
|
|
class M99Bullet extends Projectile;
|
|
|
|
var xEmitter Trail;
|
|
var() class<DamageType> DamageTypeHeadShot;
|
|
var sound Arrow_hitwall[3];
|
|
var sound Arrow_rico[2];
|
|
var sound Arrow_hitarmor;
|
|
var sound Arrow_hitflesh;
|
|
|
|
var() float HeadShotDamageMult;
|
|
|
|
var Actor ImpactActor;
|
|
var Pawn IgnoreImpactPawn;
|
|
|
|
var() string AmbientSoundRef;
|
|
//var string MeshRef;
|
|
var string Arrow_hitwallRef[3];
|
|
var string Arrow_ricoRef[2];
|
|
var string Arrow_hitarmorRef;
|
|
var string Arrow_hitfleshRef;
|
|
|
|
replication
|
|
{
|
|
reliable if ( Role==ROLE_Authority && bNetInitial )
|
|
ImpactActor;
|
|
}
|
|
|
|
static function PreloadAssets()
|
|
{
|
|
default.AmbientSound = sound(DynamicLoadObject(default.AmbientSoundRef, class'Sound', true));
|
|
|
|
default.Arrow_hitwall[0] = sound(DynamicLoadObject(default.Arrow_hitwallRef[0], class'Sound', true));
|
|
default.Arrow_hitwall[1] = sound(DynamicLoadObject(default.Arrow_hitwallRef[1], class'Sound', true));
|
|
default.Arrow_hitwall[2] = sound(DynamicLoadObject(default.Arrow_hitwallRef[2], class'Sound', true));
|
|
|
|
default.Arrow_rico[0] = sound(DynamicLoadObject(default.Arrow_ricoRef[0], class'Sound', true));
|
|
default.Arrow_rico[1] = sound(DynamicLoadObject(default.Arrow_ricoRef[1], class'Sound', true));
|
|
|
|
default.Arrow_hitarmor = sound(DynamicLoadObject(default.Arrow_hitarmorRef, class'Sound', true));
|
|
default.Arrow_hitflesh = sound(DynamicLoadObject(default.Arrow_hitfleshRef, class'Sound', true));
|
|
|
|
//UpdateDefaultMesh(Mesh(DynamicLoadObject(default.MeshRef, class'Mesh', true)));
|
|
}
|
|
|
|
static function bool UnloadAssets()
|
|
{
|
|
default.AmbientSound = none;
|
|
default.Arrow_hitwall[0] = none;
|
|
default.Arrow_hitwall[1] = none;
|
|
default.Arrow_hitwall[2] = none;
|
|
default.Arrow_rico[0] = none;
|
|
default.Arrow_rico[1] = none;
|
|
default.Arrow_hitarmor = none;
|
|
default.Arrow_hitflesh = none;
|
|
|
|
//UpdateDefaultMesh(none);
|
|
|
|
return true;
|
|
}
|
|
|
|
simulated function PostNetBeginPlay()
|
|
{
|
|
if( Level.NetMode!=NM_DedicatedServer && (Level.NetMode!=NM_Client || Physics==PHYS_Projectile) )
|
|
{
|
|
if ( !PhysicsVolume.bWaterVolume )
|
|
{
|
|
Trail = Spawn(class'KFArrowTracer',self);
|
|
Trail.Lifespan = Lifespan;
|
|
}
|
|
}
|
|
else if( Level.NetMode==NM_Client )
|
|
{
|
|
if( ImpactActor!=None )
|
|
SetBase(ImpactActor);
|
|
GoToState('OnWall');
|
|
}
|
|
}
|
|
simulated function PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
Velocity = Speed * Vector(Rotation);
|
|
if( PhysicsVolume.bWaterVolume )
|
|
Velocity*=0.65;
|
|
}
|
|
|
|
simulated state OnWall
|
|
{
|
|
Ignores HitWall;
|
|
|
|
simulated function Tick( float Delta )
|
|
{
|
|
if( Base==None )
|
|
{
|
|
if( Level.NetMode==NM_Client )
|
|
bHidden = True;
|
|
else Destroy();
|
|
}
|
|
}
|
|
|
|
simulated function BeginState()
|
|
{
|
|
bCollideWorld = False;
|
|
if( Level.NetMode!=NM_DedicatedServer )
|
|
AmbientSound = None;
|
|
if( Trail!=None )
|
|
Trail.mRegen = False;
|
|
SetCollisionSize(25,25);
|
|
}
|
|
}
|
|
|
|
simulated function Explode(vector HitLocation, vector HitNormal);
|
|
|
|
simulated function ProcessTouch (Actor Other, vector HitLocation)
|
|
{
|
|
local vector X,End,HL,HN;
|
|
local Vector TempHitLocation, HitNormal;
|
|
local array<int> HitPoints;
|
|
local KFPawn HitPawn;
|
|
local bool bHitWhipAttachment;
|
|
|
|
if ( Other == none || Other == Instigator || Other.Base == Instigator || !Other.bBlockHitPointTraces || Other==IgnoreImpactPawn ||
|
|
(IgnoreImpactPawn != none && Other.Base == IgnoreImpactPawn) )
|
|
return;
|
|
|
|
X = Vector(Rotation);
|
|
|
|
if( ROBulletWhipAttachment(Other) != none )
|
|
{
|
|
|
|
bHitWhipAttachment=true;
|
|
|
|
if(!Other.Base.bDeleteMe)
|
|
{
|
|
Other = Instigator.HitPointTrace(TempHitLocation, HitNormal, HitLocation + (65535 * X), HitPoints, HitLocation,, 1);
|
|
|
|
if( Other == none || HitPoints.Length == 0 )
|
|
return;
|
|
|
|
HitPawn = KFPawn(Other);
|
|
|
|
if (Role == ROLE_Authority)
|
|
{
|
|
if ( HitPawn != none )
|
|
{
|
|
// Hit detection debugging
|
|
/*log("Bullet hit "$HitPawn.PlayerReplicationInfo.PlayerName);
|
|
HitPawn.HitStart = HitLocation;
|
|
HitPawn.HitEnd = HitLocation + (65535 * X);*/
|
|
|
|
if( !HitPawn.bDeleteMe )
|
|
HitPawn.ProcessLocationalDamage(Damage, Instigator, TempHitLocation, MomentumTransfer * X, MyDamageType,HitPoints);
|
|
|
|
Damage/=1.25;
|
|
Velocity*=0.85;
|
|
|
|
IgnoreImpactPawn = HitPawn;
|
|
|
|
if( Level.NetMode!=NM_Client )
|
|
PlayhitNoise(Pawn(Other)!=none && Pawn(Other).ShieldStrength>0);
|
|
|
|
// Hit detection debugging
|
|
/*if( Level.NetMode == NM_Standalone)
|
|
HitPawn.DrawBoneLocation();*/
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if( Level.NetMode!=NM_Client )
|
|
PlayhitNoise(Pawn(Other)!=none && Pawn(Other).ShieldStrength>0);
|
|
|
|
if( Physics==PHYS_Projectile && Pawn(Other)!=None && Vehicle(Other)==None )
|
|
{
|
|
IgnoreImpactPawn = Pawn(Other);
|
|
if( IgnoreImpactPawn.IsHeadShot(HitLocation, X, 1.0) )
|
|
Other.TakeDamage(Damage * HeadShotDamageMult, Instigator, HitLocation, MomentumTransfer * X, DamageTypeHeadShot);
|
|
else Other.TakeDamage(Damage, Instigator, HitLocation, MomentumTransfer * X, MyDamageType);
|
|
Damage/=1.25;
|
|
Velocity*=0.85;
|
|
Return;
|
|
}
|
|
else if( ExtendedZCollision(Other)!=None && Pawn(Other.Owner)!=None )
|
|
{
|
|
if( Other.Owner==IgnoreImpactPawn )
|
|
Return;
|
|
IgnoreImpactPawn = Pawn(Other.Owner);
|
|
if ( IgnoreImpactPawn.IsHeadShot(HitLocation, X, 1.0))
|
|
Other.TakeDamage(Damage * HeadShotDamageMult, Instigator, HitLocation, MomentumTransfer * X, DamageTypeHeadShot);
|
|
else Other.TakeDamage(Damage, Instigator, HitLocation, MomentumTransfer * X, MyDamageType);
|
|
Damage/=1.25;
|
|
Velocity*=0.85;
|
|
Return;
|
|
}
|
|
if( Level.NetMode!=NM_DedicatedServer && SkeletalMesh(Other.Mesh)!=None && Other.DrawType==DT_Mesh && Pawn(Other)!=None )
|
|
{ // Attach victim to the wall behind if it dies.
|
|
End = Other.Location+X*600;
|
|
if( Other.Trace(HL,HN,End,Other.Location,False)!=None )
|
|
Spawn(Class'BodyAttacher',Other,,HitLocation).AttachEndPoint = HL-HN;
|
|
}
|
|
//Stick(Other,HitLocation);
|
|
if( Level.NetMode!=NM_Client )
|
|
{
|
|
if (Pawn(Other) != none && Pawn(Other).IsHeadShot(HitLocation, X, 1.0))
|
|
Pawn(Other).TakeDamage(Damage * HeadShotDamageMult, Instigator, HitLocation, MomentumTransfer * X, DamageTypeHeadShot);
|
|
else Other.TakeDamage(Damage, Instigator, HitLocation, MomentumTransfer * X, MyDamageType);
|
|
}
|
|
}
|
|
|
|
function PlayhitNoise( bool bArmored )
|
|
{
|
|
if( bArmored )
|
|
PlaySound(Arrow_hitarmor); // implies hit a target with shield/armor
|
|
else PlaySound(Arrow_hitflesh);
|
|
}
|
|
|
|
simulated function HitWall( vector HitNormal, actor Wall )
|
|
{
|
|
speed = VSize(Velocity);
|
|
|
|
if ( Role==ROLE_Authority && Wall!=none )
|
|
{
|
|
if ( !Wall.bStatic && !Wall.bWorldGeometry )
|
|
{
|
|
if ( Instigator == None || Instigator.Controller == None )
|
|
{
|
|
Wall.SetDelayedDamageInstigatorController(InstigatorController);
|
|
}
|
|
|
|
Wall.TakeDamage( Damage, instigator, Location, MomentumTransfer * Normal(Velocity), MyDamageType);
|
|
HurtWall = Wall;
|
|
}
|
|
else
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
MakeNoise(1.0);
|
|
}
|
|
|
|
PlaySound(Arrow_hitwall[Rand(3)],,2.5*TransientSoundVolume);
|
|
|
|
if ( Level.NetMode != NM_DedicatedServer )
|
|
{
|
|
Spawn(class'ROBulletHitEffect',,, Location, rotator(-HitNormal));
|
|
}
|
|
|
|
if( Instigator!=None && Level.NetMode!=NM_Client )
|
|
{
|
|
MakeNoise(0.3);
|
|
}
|
|
|
|
//Stick(Wall, Location+HitNormal);
|
|
}
|
|
|
|
simulated function Landed(vector HitNormal)
|
|
{
|
|
HitWall(HitNormal, None);
|
|
}
|
|
|
|
simulated function Stick(actor HitActor, vector HitLocation)
|
|
{
|
|
local name NearestBone;
|
|
local float dist;
|
|
|
|
SetPhysics(PHYS_None);
|
|
|
|
if (pawn(HitActor) != none)
|
|
{
|
|
NearestBone = GetClosestBone(HitLocation, HitLocation, dist , 'CHR_Spine2' , 15 );
|
|
HitActor.AttachToBone(self,NearestBone);
|
|
}
|
|
else SetBase(HitActor);
|
|
|
|
ImpactActor = HitActor;
|
|
|
|
if (Base==None)
|
|
Destroy();
|
|
else GoToState('OnWall');
|
|
}
|
|
|
|
simulated function PhysicsVolumeChange( PhysicsVolume Volume )
|
|
{
|
|
if( Volume.bWaterVolume && !PhysicsVolume.bWaterVolume )
|
|
{
|
|
if ( Trail != None )
|
|
Trail.mRegen=False;
|
|
Velocity*=0.65;
|
|
}
|
|
}
|
|
|
|
simulated function Destroyed()
|
|
{
|
|
if (Trail !=None)
|
|
Trail.mRegen = False;
|
|
Super.Destroyed();
|
|
}
|
|
|
|
defaultproperties
|
|
{
|
|
DamageTypeHeadShot=Class'KFMod.DamTypeM99HeadShot'
|
|
Arrow_hitwallRef(0)="KFWeaponSound.bullethitflesh2"
|
|
Arrow_hitwallRef(1)="KFWeaponSound.bullethitflesh3"
|
|
Arrow_hitwallRef(2)="KFWeaponSound.bullethitflesh4"
|
|
Arrow_ricoRef(0)="KFWeaponSound.bullethitmetal"
|
|
Arrow_ricoRef(1)="KFWeaponSound.bullethitmetal3"
|
|
Arrow_hitarmorRef="KFWeaponSound.bullethitflesh4"
|
|
Arrow_hitfleshRef="KFWeaponSound.bullethitflesh4"
|
|
HeadShotDamageMult=2.250000
|
|
Speed=28000.000000
|
|
MaxSpeed=200000.000000
|
|
Damage=675.000000
|
|
MomentumTransfer=150000.000000
|
|
MyDamageType=Class'KFMod.DamTypeM99SniperRifle'
|
|
ExplosionDecal=Class'KFMod.ShotgunDecal'
|
|
CullDistance=3000.000000
|
|
AmbientSoundRef="PatchSounds.ArrowZip"
|
|
LifeSpan=2.000000
|
|
//MeshRef="KFWeaponModels.XbowBolt"
|
|
DrawScale=15.000000
|
|
AmbientGlow=30
|
|
Style=STY_Alpha
|
|
bUnlit=False
|
|
bFullVolume=True
|
|
bNetTemporary=False
|
|
CollisionRadius=0
|
|
CollisionHeight=0
|
|
}
|