rott/kf_sources/KFMod/Classes/M99Bullet.uc
2026-07-14 20:27:09 +07:00

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
}