395 lines
12 KiB
Ucode
395 lines
12 KiB
Ucode
// KFMeleeFire
|
|
class KFMeleeFire extends WeaponFire;
|
|
|
|
var() int MeleeDamage;
|
|
|
|
var float ProxySize;
|
|
|
|
var int NumConHits; // Number of successful strikes before a combo.
|
|
var bool bComboTime; // Are we combo-ing?
|
|
var int LastComboStartTime;
|
|
var int LastConHitTime;
|
|
var float ComboConDecay;
|
|
|
|
var float StopFireTime;
|
|
var float f;
|
|
var float StartFireTime;
|
|
|
|
var int dmg;
|
|
var int i;
|
|
|
|
var Name IdleAnim;
|
|
var float IdleAnimRate;
|
|
var() float weaponRange;
|
|
|
|
var() float DamagedelayMin;
|
|
var float DamagedelayMax;
|
|
|
|
var bool bCanHit ;
|
|
var Vector EndTraceS;
|
|
|
|
var class<damageType> hitDamageClass;
|
|
|
|
var() vector ImpactShakeRotMag; // how far to rot view
|
|
var() vector ImpactShakeRotRate; // how fast to rot view
|
|
var() float ImpactShakeRotTime; // how much time to rot the instigator's view
|
|
var() vector ImpactShakeOffsetMag; // max view offset vertically
|
|
var() vector ImpactShakeOffsetRate; // how fast to offset view vertically
|
|
var() float ImpactShakeOffsetTime; // how much time to offset view
|
|
|
|
var Vector SpawnTrace;
|
|
var Bool bTrigger;
|
|
var Actor SpawnActor;
|
|
|
|
var array<sound> MeleeHitSounds; // Sound for this melee strike hitting a pawn (fleshy hits)
|
|
var() float MeleeHitVolume;
|
|
|
|
var class<KFMeleeHitEffect> HitEffectClass; // The class to spawn for the hit effect for this melee weapon hitting the world (not pawns)
|
|
|
|
var string FireSoundRef;
|
|
var string ReloadSoundRef;
|
|
var string NoAmmoSoundRef;
|
|
var array<string> MeleeHitSoundRefs;
|
|
|
|
var float WideDamageMinHitAngle; // The angle to do sweeping strikes in front of the player. If zero do no strikes
|
|
|
|
static function PreloadAssets(optional KFMeleeFire Spawned)
|
|
{
|
|
local int i;
|
|
|
|
default.FireSound = sound(DynamicLoadObject(default.FireSoundRef, class'Sound', true));
|
|
default.ReloadSound = sound(DynamicLoadObject(default.ReloadSoundRef, class'Sound', true));
|
|
default.NoAmmoSound = sound(DynamicLoadObject(default.NoAmmoSoundRef, class'Sound', true));
|
|
|
|
for ( i = 0; i < default.MeleeHitSoundRefs.Length; i++ )
|
|
{
|
|
default.MeleeHitSounds[i] = sound(DynamicLoadObject(default.MeleeHitSoundRefs[i], class'Sound', true));
|
|
}
|
|
|
|
if ( Spawned != none )
|
|
{
|
|
Spawned.FireSound = default.FireSound;
|
|
Spawned.ReloadSound = default.ReloadSound;
|
|
Spawned.NoAmmoSound = default.NoAmmoSound;
|
|
|
|
for ( i = 0; i < default.MeleeHitSoundRefs.Length; i++ )
|
|
{
|
|
Spawned.MeleeHitSounds[i] = default.MeleeHitSounds[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
static function bool UnloadAssets()
|
|
{
|
|
local int i;
|
|
|
|
default.FireSound = none;
|
|
default.ReloadSound = none;
|
|
default.NoAmmoSound = none;
|
|
|
|
for ( i = 0; i < default.MeleeHitSoundRefs.Length; i++ )
|
|
{
|
|
default.MeleeHitSounds[i] = none;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
simulated function PostBeginPlay()
|
|
{
|
|
if ( FireSound == none )
|
|
{
|
|
PreloadAssets(self);
|
|
}
|
|
|
|
super.PostBeginPlay();
|
|
}
|
|
|
|
simulated function Timer()
|
|
{
|
|
local Actor HitActor;
|
|
local vector StartTrace, EndTrace, HitLocation, HitNormal;
|
|
local rotator PointRot;
|
|
local int MyDamage;
|
|
local bool bBackStabbed;
|
|
local Pawn Victims;
|
|
local vector dir, lookdir;
|
|
local float DiffAngle, VictimDist;
|
|
|
|
MyDamage = MeleeDamage;
|
|
|
|
If( !KFWeapon(Weapon).bNoHit )
|
|
{
|
|
MyDamage = MeleeDamage;
|
|
StartTrace = Instigator.Location + Instigator.EyePosition();
|
|
|
|
if( Instigator.Controller!=None && PlayerController(Instigator.Controller)==None && Instigator.Controller.Enemy!=None )
|
|
{
|
|
PointRot = rotator(Instigator.Controller.Enemy.Location-StartTrace); // Give aimbot for bots.
|
|
}
|
|
else
|
|
{
|
|
PointRot = Instigator.GetViewRotation();
|
|
}
|
|
|
|
EndTrace = StartTrace + vector(PointRot)*weaponRange;
|
|
HitActor = Instigator.Trace( HitLocation, HitNormal, EndTrace, StartTrace, true);
|
|
|
|
//Instigator.ClearStayingDebugLines();
|
|
//Instigator.DrawStayingDebugLine( StartTrace, EndTrace,0, 255, 0);
|
|
|
|
if (HitActor!=None)
|
|
{
|
|
ImpactShakeView();
|
|
|
|
if( HitActor.IsA('ExtendedZCollision') && HitActor.Base != none &&
|
|
HitActor.Base.IsA('KFMonster') )
|
|
{
|
|
HitActor = HitActor.Base;
|
|
}
|
|
|
|
if ( (HitActor.IsA('KFMonster') || HitActor.IsA('KFHumanPawn')) && KFMeleeGun(Weapon).BloodyMaterial!=none )
|
|
{
|
|
Weapon.Skins[KFMeleeGun(Weapon).BloodSkinSwitchArray] = KFMeleeGun(Weapon).BloodyMaterial;
|
|
Weapon.texture = Weapon.default.Texture;
|
|
}
|
|
if( Level.NetMode==NM_Client )
|
|
{
|
|
Return;
|
|
}
|
|
|
|
if( HitActor.IsA('Pawn') && !HitActor.IsA('Vehicle')
|
|
&& (Normal(HitActor.Location-Instigator.Location) dot vector(HitActor.Rotation))>0 ) // Fixed in Balance Round 2
|
|
{
|
|
bBackStabbed = true;
|
|
|
|
MyDamage*=2; // Backstab >:P
|
|
}
|
|
|
|
if( (KFMonster(HitActor)!=none) )
|
|
{
|
|
// log(VSize(Instigator.Velocity));
|
|
|
|
KFMonster(HitActor).bBackstabbed = bBackStabbed;
|
|
|
|
HitActor.TakeDamage(MyDamage, Instigator, HitLocation, vector(PointRot), hitDamageClass) ;
|
|
|
|
if(MeleeHitSounds.Length > 0)
|
|
{
|
|
Weapon.PlaySound(MeleeHitSounds[Rand(MeleeHitSounds.length)],SLOT_None,MeleeHitVolume,,,,false);
|
|
}
|
|
|
|
if(VSize(Instigator.Velocity) > 300 && KFMonster(HitActor).Mass <= Instigator.Mass)
|
|
{
|
|
KFMonster(HitActor).FlipOver();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
HitActor.TakeDamage(MyDamage, Instigator, HitLocation, vector(PointRot), hitDamageClass) ;
|
|
Spawn(HitEffectClass,,, HitLocation, rotator(HitLocation - StartTrace));
|
|
//if( KFWeaponAttachment(Weapon.ThirdPersonActor)!=None )
|
|
// KFWeaponAttachment(Weapon.ThirdPersonActor).UpdateHit(HitActor,HitLocation,HitNormal);
|
|
|
|
//Weapon.IncrementFlashCount(ThisModeNum);
|
|
}
|
|
}
|
|
|
|
if( WideDamageMinHitAngle > 0 )
|
|
{
|
|
foreach Weapon.VisibleCollidingActors( class 'Pawn', Victims, (weaponRange * 2), StartTrace ) //, RadiusHitLocation
|
|
{
|
|
if( (HitActor != none && Victims == HitActor) || Victims.Health <= 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( Victims != Instigator )
|
|
{
|
|
VictimDist = VSizeSquared(Instigator.Location - Victims.Location);
|
|
|
|
//log("VictimDist = "$VictimDist$" Weaponrange = "$(weaponRange*Weaponrange));
|
|
|
|
//Instigator.ClearStayingDebugLines();
|
|
//Instigator.DrawStayingDebugLine( Instigator.Location, EndTrace,0, 255, 0);
|
|
|
|
if( VictimDist > (((weaponRange * 1.1) * (weaponRange * 1.1)) + (Victims.CollisionRadius * Victims.CollisionRadius)) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
lookdir = Normal(Vector(Instigator.GetViewRotation()));
|
|
dir = Normal(Victims.Location - Instigator.Location);
|
|
|
|
DiffAngle = lookdir dot dir;
|
|
|
|
if( DiffAngle > WideDamageMinHitAngle )
|
|
{
|
|
//Instigator.DrawStayingDebugLine( Victims.Location + vect(0,0,10), Instigator.Location,255, 0, 0);
|
|
//log("Shot would hit "$Victims$" DiffAngle = "$DiffAngle$" WideDamageMinHitAngle = "$WideDamageMinHitAngle$" for damage of: "$(MyDamage*DiffAngle));
|
|
Victims.TakeDamage(MyDamage*DiffAngle, Instigator, (Victims.Location + Victims.CollisionHeight * vect(0,0,0.7)), vector(PointRot), hitDamageClass) ;
|
|
|
|
if(MeleeHitSounds.Length > 0)
|
|
{
|
|
Victims.PlaySound(MeleeHitSounds[Rand(MeleeHitSounds.length)],SLOT_None,MeleeHitVolume,,,,false);
|
|
}
|
|
}
|
|
//else
|
|
//{
|
|
//Instigator.DrawStayingDebugLine( Victims.Location, Instigator.Location,255, 255, 0);
|
|
//log("Shot would miss "$Victims$" DiffAngle = "$DiffAngle$" WideDamageMinHitAngle = "$WideDamageMinHitAngle);
|
|
//}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function float GetFireSpeed()
|
|
{
|
|
if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none )
|
|
{
|
|
return KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.Static.GetFireSpeedMod(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), Weapon);
|
|
}
|
|
|
|
return 1.0;
|
|
}
|
|
simulated event ModeDoFire()
|
|
{
|
|
local float Rec;
|
|
|
|
if (!AllowFire())
|
|
return;
|
|
|
|
Rec = GetFireSpeed();
|
|
SetTimer(DamagedelayMin/Rec, False);
|
|
FireRate = default.FireRate/Rec;
|
|
FireAnimRate = default.FireAnimRate*Rec;
|
|
ReloadAnimRate = default.ReloadAnimRate*Rec;
|
|
|
|
if (MaxHoldTime > 0.0)
|
|
HoldTime = FMin(HoldTime, MaxHoldTime);
|
|
|
|
// server
|
|
if (Weapon.Role == ROLE_Authority)
|
|
{
|
|
Weapon.ConsumeAmmo(ThisModeNum, Load);
|
|
DoFireEffect();
|
|
|
|
HoldTime = 0; // if bot decides to stop firing, HoldTime must be reset first
|
|
if ( (Instigator == None) || (Instigator.Controller == None) )
|
|
return;
|
|
|
|
if ( AIController(Instigator.Controller) != None )
|
|
AIController(Instigator.Controller).WeaponFireAgain(BotRefireRate, true);
|
|
|
|
Instigator.DeactivateSpawnProtection();
|
|
}
|
|
|
|
// client
|
|
if (Instigator.IsLocallyControlled())
|
|
{
|
|
ShakeView();
|
|
PlayFiring();
|
|
FlashMuzzleFlash();
|
|
StartMuzzleSmoke();
|
|
ClientPlayForceFeedback(FireForce);
|
|
}
|
|
else // server
|
|
ServerPlayFiring();
|
|
|
|
Weapon.IncrementFlashCount(ThisModeNum);
|
|
|
|
// set the next firing time. must be careful here so client and server do not get out of sync
|
|
if (bFireOnRelease)
|
|
{
|
|
if (bIsFiring)
|
|
NextFireTime += MaxHoldTime + FireRate;
|
|
else
|
|
NextFireTime = Level.TimeSeconds + FireRate;
|
|
}
|
|
else
|
|
{
|
|
NextFireTime += FireRate;
|
|
NextFireTime = FMax(NextFireTime, Level.TimeSeconds);
|
|
}
|
|
|
|
Load = AmmoPerFire;
|
|
HoldTime = 0;
|
|
|
|
if (Instigator.PendingWeapon != Weapon && Instigator.PendingWeapon != None)
|
|
{
|
|
bIsFiring = false;
|
|
Weapon.PutDown();
|
|
}
|
|
|
|
if( Weapon.Owner != none && Weapon.Owner.Physics != PHYS_Falling )
|
|
{
|
|
Weapon.Owner.Velocity.x *= KFMeleeGun(Weapon).ChopSlowRate;
|
|
Weapon.Owner.Velocity.y *= KFMeleeGun(Weapon).ChopSlowRate;
|
|
}
|
|
}
|
|
|
|
function DoFireEffect()
|
|
{
|
|
local KFMeleeGun kf;
|
|
local int damage ;
|
|
|
|
if(KFMeleeGun(Weapon) == none)
|
|
return;
|
|
|
|
kf = KFMeleeGun(Weapon);
|
|
damage = MeleeDamage;
|
|
}
|
|
|
|
|
|
simulated function ShakeView()
|
|
{
|
|
local PlayerController P;
|
|
|
|
if (Instigator == None)
|
|
return;
|
|
|
|
P = PlayerController(Instigator.Controller);
|
|
if (P != None )
|
|
P.WeaponShakeView(ShakeRotMag, ShakeRotRate, ShakeRotTime, ShakeOffsetMag, ShakeOffsetRate, ShakeOffsetTime);
|
|
}
|
|
|
|
function SlowDown();
|
|
|
|
function SpeedUp();
|
|
|
|
function ResetRate();
|
|
|
|
function ImpactShakeView()
|
|
{
|
|
local PlayerController P;
|
|
|
|
P = PlayerController(Instigator.Controller);
|
|
if ( P != None )
|
|
P.WeaponShakeView(ImpactShakeRotMag, ImpactShakeRotRate, ImpactShakeRotTime,ImpactShakeOffsetMag,ImpactShakeOffsetRate,ImpactShakeOffsetTime);
|
|
}
|
|
|
|
defaultproperties
|
|
{
|
|
ProxySize=0.200000
|
|
IdleAnim="Idle"
|
|
IdleAnimRate=1.000000
|
|
weaponRange=70.000000
|
|
DamagedelayMin=0.300000
|
|
DamagedelayMax=0.400000
|
|
hitDamageClass=Class'KFMod.DamTypeMelee'
|
|
ImpactShakeRotMag=(X=50.000000,Y=50.000000,Z=50.000000)
|
|
ImpactShakeRotRate=(X=10000.000000,Y=10000.000000,Z=10000.000000)
|
|
ImpactShakeRotTime=2.000000
|
|
ImpactShakeOffsetMag=(X=10.000000,Y=10.000000,Z=10.000000)
|
|
ImpactShakeOffsetRate=(X=1000.000000,Y=1000.000000,Z=1000.000000)
|
|
ImpactShakeOffsetTime=2.000000
|
|
FireEndAnim=
|
|
FireForce="ShockRifleFire"
|
|
aimerror=100.000000
|
|
MeleeHitVolume=1.0
|
|
HitEffectClass=class'KFMeleeHitEffect'
|
|
}
|