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

274 lines
6.6 KiB
Ucode

//=============================================================================
// Stun Nade Fire
//=============================================================================
class StunNadeFire extends RocketFire; // AssaultGrenade
const mNumGrenades = 8;
var float mCurrentRoll;
var float mBlend;
var float mRollInc;
var float mNextRoll;
var float mDrumRotationsPerSec;
var float mRollPerSec;
var StunNade mGun;
var int mCurrentSlot;
var int mNextEmptySlot;
var() float mScale;
var() float mScaleMultiplier;
var() float mSpeedMin;
var() float mSpeedMax;
var() float mHoldSpeedMin;
var() float mHoldSpeedMax;
var() float mHoldSpeedGainPerSec;
var() float mHoldClampMax;
var() float mWaitTime;
function PlayFiring()
{
if ( Weapon.Mesh != None )
{
if ( FireCount > 0 )
{
if ( Weapon.HasAnim(FireLoopAnim) )
{
Weapon.PlayAnim(FireLoopAnim, FireLoopAnimRate, 0.0);
}
else
{
Weapon.PlayAnim(FireAnim, FireAnimRate, TweenTime);
}
}
else
{
Weapon.PlayAnim(FireAnim, FireAnimRate, TweenTime);
}
}
Weapon.PlayOwnedSound(FireSound,SLOT_Interact,TransientSoundVolume,,TransientSoundRadius,Default.FireAnimRate/FireAnimRate,false);
ClientPlayForceFeedback(FireForce); // jdf
FireCount++;
}
function PostBeginPlay()
{
Super.PostBeginPlay();
mRollInc = -1.f * 65536.f / mNumGrenades;
mRollPerSec = 65536.f * mDrumRotationsPerSec;
mGun = StunNade(Weapon);
mHoldClampMax = (mHoldSpeedMax - mHoldSpeedMin) / mHoldSpeedGainPerSec;
}
// Client-side only: update the first person drum rotation
simulated function bool UpdateRoll(float dt)
{
return true;
}
simulated function ReturnToIdle()
{
}
function projectile SpawnProjectile(Vector Start, Rotator Dir)
{
local Grenade g;
local vector X, Y, Z;
local float pawnSpeed;
g = Weapon.Spawn(class'KFMod.StunProj', instigator,, Start, Dir);
if (g != None)
{
Weapon.GetViewAxes(X,Y,Z);
pawnSpeed = X dot Instigator.Velocity;
if ( Bot(Instigator.Controller) != None )
g.Speed = mHoldSpeedMax;
else
g.Speed = mHoldSpeedMin + HoldTime*mHoldSpeedGainPerSec;
g.Speed = FClamp(g.Speed, mHoldSpeedMin, mHoldSpeedMax);
g.Speed = pawnSpeed + g.Speed;
g.Velocity = g.Speed * Vector(Dir);
g.Damage *= DamageAtten;
}
return g;
}
function InitEffects()
{
}
function DoFireEffect()
{
local Vector StartProj, StartTrace, X,Y,Z;
local Rotator Aim;
local Vector HitLocation, HitNormal;
local Actor Other;
Instigator.MakeNoise(1.0);
Weapon.GetViewAxes(X,Y,Z);
StartTrace = Instigator.Location + Instigator.EyePosition();// + X*Instigator.CollisionRadius;
StartProj = StartTrace + X*ProjSpawnOffset.X;
if ( !Weapon.WeaponCentered() )
StartProj = StartProj + Weapon.Hand * Y*ProjSpawnOffset.Y + Z*ProjSpawnOffset.Z;
// check if projectile would spawn through a wall and adjust start location accordingly
Other = Weapon.Trace(HitLocation, HitNormal, StartProj, StartTrace, false);
if (Other != None)
{
StartProj = HitLocation;
}
Aim = AdjustAim(StartProj, AimError);
SpawnProjectile(StartProj, Aim);
}
event ModeDoFire()
{
if (!AllowFire())
return;
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();
}
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();
}
}
state Wait
{
function BeginState()
{
SetTimer(mWaitTime, false);
}
function Timer()
{
GotoState('LoadNext'); //goto idle if out of ammo?
}
}
state LoadNext
{
function BeginState()
{
if (Level.NetMode != NM_Client)
Weapon.PlaySound(ReloadSound,SLOT_None,,,512.0,,false);
ClientPlayForceFeedback(ReloadForce);
}
function ModeTick(float dt)
{
if ( Weapon.Mesh != Weapon.OldMesh )
GotoState('Idle');
else if (UpdateRoll(dt))
GotoState('Idle');
}
}
function PlayFireEnd()
{
if(weapon.ammoAmount(0) <= 0)
weapon.DoAutoSwitch() ;
}
defaultproperties
{
mBlend=1.000000
mDrumRotationsPerSec=0.400000
mScale=1.000000
mScaleMultiplier=0.900000
mSpeedMin=150.000000
mSpeedMax=1000.000000
mHoldSpeedMin=850.000000
mHoldSpeedMax=1600.000000
mHoldSpeedGainPerSec=750.000000
mWaitTime=0.500000
ProjSpawnOffset=(Y=-20.000000,Z=-7.000000)
bFireOnRelease=True
bWaitForRelease=True
PreFireTime=0.500000
FireLoopAnim="LoopThrow"
FireSound=Sound'KFWeaponSound.axe-swish'
FireRate=1.500000
AmmoClass=Class'KFMod.StunAmmo'
ShakeOffsetMag=(X=25.000000,Y=25.000000,Z=25.000000)
ShakeOffsetRate=(X=0.000000)
ProjectileClass=Class'KFMod.StunProj'
BotRefireRate=2.500000
FlashEmitterClass=None
SpreadStyle=SS_Random
}