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

455 lines
14 KiB
Ucode

//=============================================================================
// SeekerSixRocketLauncher
//=============================================================================
// Weapon class for the SeekerSix mini rocket launcher
//=============================================================================
// Killing Floor Source
// Copyright (C) 2013 Tripwire Interactive LLC
// - John "Ramm-Jaeger" Gibson
//=============================================================================
class SeekerSixRocketLauncher extends KFWeapon;
var() Material Counter0;
var() Material Counter1;
var() Material Counter2;
var() Material Counter3;
var() Material Counter4;
var() Material Counter5;
var() Material Counter6;
// Site reticles
var() Material SiteReticle;
var() Material SiteReticleLocked;
// References to site reticles
var string SiteReticleRef;
var string SiteReticleLockedRef;
var Pawn SeekTarget;
var float LockTime, UnLockTime, SeekCheckTime;
var bool bLockedOn, bBreakLock, bOldLockedOn;
var bool bTightSpread;
var(Seeking) float SeekCheckFreq, SeekRange;
var(Seeking) float LockRequiredTime, UnLockRequiredTime;
var(Seeking) float LockAim;
var sound LockOnSound; // Locked on sound
var sound LockLostSound; // Lost lock on sound
var string LockOnSoundRef;
var string LockLostSoundRef;
replication
{
reliable if (Role == ROLE_Authority && bNetOwner)
bLockedOn;
}
static function PreloadAssets(Inventory Inv, optional bool bSkipRefCount)
{
default.Counter0 = Material(DynamicLoadObject("KF_IJC_Halloween_Weapons2.SeekerSix_Counter.Counter0_Shader", class'Material', true));
default.Counter1 = Material(DynamicLoadObject("KF_IJC_Halloween_Weapons2.SeekerSix_Counter.Counter1_Shader", class'Material', true));
default.Counter2 = Material(DynamicLoadObject("KF_IJC_Halloween_Weapons2.SeekerSix_Counter.Counter2_Shader", class'Material', true));
default.Counter3 = Material(DynamicLoadObject("KF_IJC_Halloween_Weapons2.SeekerSix_Counter.Counter3_Shader", class'Material', true));
default.Counter4 = Material(DynamicLoadObject("KF_IJC_Halloween_Weapons2.SeekerSix_Counter.Counter4_Shader", class'Material', true));
default.Counter5 = Material(DynamicLoadObject("KF_IJC_Halloween_Weapons2.SeekerSix_Counter.Counter5_Shader", class'Material', true));
default.Counter6 = Material(DynamicLoadObject("KF_IJC_Halloween_Weapons2.SeekerSix_Counter.Counter6_Shader", class'Material', true));
default.SiteReticle = Material(DynamicLoadObject(default.SiteReticleRef, class'Material', true));
default.SiteReticleLocked = Material(DynamicLoadObject(default.SiteReticleLockedRef, class'Material', true));
if ( default.LockOnSoundRef != "" )
{
default.LockOnSound = sound(DynamicLoadObject(default.LockOnSoundRef, class'Sound', true));
}
if ( default.LockLostSoundRef != "" )
{
default.LockLostSound = sound(DynamicLoadObject(default.LockLostSoundRef, class'Sound', true));
}
if ( SeekerSixRocketLauncher(Inv) != none )
{
SeekerSixRocketLauncher(Inv).Counter0 = default.Counter0;
SeekerSixRocketLauncher(Inv).Counter1 = default.Counter1;
SeekerSixRocketLauncher(Inv).Counter2 = default.Counter2;
SeekerSixRocketLauncher(Inv).Counter3 = default.Counter3;
SeekerSixRocketLauncher(Inv).Counter4 = default.Counter4;
SeekerSixRocketLauncher(Inv).Counter5 = default.Counter5;
SeekerSixRocketLauncher(Inv).Counter6 = default.Counter6;
SeekerSixRocketLauncher(Inv).SiteReticle = default.SiteReticle;
SeekerSixRocketLauncher(Inv).SiteReticleLocked = default.SiteReticleLocked;
SeekerSixRocketLauncher(Inv).LockOnSound = default.LockOnSound;
SeekerSixRocketLauncher(Inv).LockLostSound = default.LockLostSound;
}
super.PreloadAssets(Inv, bSkipRefCount);
}
static function bool UnloadAssets()
{
if ( super.UnloadAssets() )
{
default.Counter0 = none;
default.Counter1 = none;
default.Counter2 = none;
default.Counter3 = none;
default.Counter4 = none;
default.Counter5 = none;
default.Counter6 = none;
default.LockOnSound = none;
default.LockLostSound = none;
default.SiteReticle = none;
default.SiteReticleLocked = none;
return true;
}
return false;
}
simulated function WeaponTick(float dt)
{
super.WeaponTick(dt);
if ( Level.NetMode!=NM_DedicatedServer)
{
if ((MagAmmoRemaining ) == 1)
Skins[2] = Counter1;
if ((MagAmmoRemaining ) == 2)
Skins[2] = Counter2;
if ((MagAmmoRemaining ) == 3)
Skins[2] = Counter3;
if ((MagAmmoRemaining ) == 4)
Skins[2] = Counter4;
if ((MagAmmoRemaining ) == 5)
Skins[2] = Counter5;
if ((MagAmmoRemaining ) == 6)
Skins[2] = Counter6;
if ((MagAmmoRemaining ) == 0)
Skins[2] = Counter0;
// Swap the site reticle if you are locked on
if( bOldLockedOn != bLockedOn )
{
bOldLockedOn = bLockedOn;
if( bLockedOn )
{
Skins[1] = SiteReticleLocked;
}
else
{
Skins[1] = SiteReticle;
}
}
}
}
// Handle locking on
function Tick(float dt)
{
local Pawn Other;
local Vector StartTrace;
local Rotator Aim;
local float BestDist, BestAim;
if (Instigator == None || Instigator.Weapon != self)
return;
if ( Role < ROLE_Authority )
return;
if ( !Instigator.IsHumanControlled() )
return;
if (Level.TimeSeconds > SeekCheckTime)
{
// if( !bAimingRifle )
// {
// return;
// }
if( MagAmmoRemaining < 1 || bIsReloading )
{
bLockedOn = false;
SeekTarget = None;
return;
}
if (bBreakLock)
{
bBreakLock = false;
bLockedOn = false;
SeekTarget = None;
}
StartTrace = Instigator.Location + Instigator.EyePosition();
Aim = Instigator.GetViewRotation();
BestAim = LockAim;
Other = Instigator.Controller.PickTarget(BestAim, BestDist, Vector(Aim), StartTrace, SeekRange);
if ( CanLockOnTo(Other) )
{
if (Other == SeekTarget)
{
LockTime += SeekCheckFreq;
if (!bLockedOn && LockTime >= LockRequiredTime)
{
bLockedOn = true;
PlaySound(LockOnSound,SLOT_None,2.0);
}
}
else
{
SeekTarget = Other;
LockTime = 0.0;
}
UnLockTime = 0.0;
}
else
{
if (SeekTarget != None)
{
UnLockTime += SeekCheckFreq;
if (UnLockTime >= UnLockRequiredTime)
{
SeekTarget = None;
if (bLockedOn)
{
bLockedOn = false;
PlaySound(LockLostSound,SLOT_None,2.0);
}
}
}
else
bLockedOn = false;
}
SeekCheckTime = Level.TimeSeconds + SeekCheckFreq;
}
}
// See if this weapon can lock on to the actor
function bool CanLockOnTo(Actor Other)
{
local Pawn P;
P = Pawn(Other);
if (P == None || P == Instigator || !P.bProjTarget)
return false;
if (!Level.Game.bTeamGame)
return true;
if ( (Instigator.Controller != None) && Instigator.Controller.SameTeamAs(P.Controller) )
return false;
return ( (P.PlayerReplicationInfo == None) || (P.PlayerReplicationInfo.Team != Instigator.PlayerReplicationInfo.Team) );
}
//=============================================================================
// Functions
//=============================================================================
function Projectile SpawnProjectile(Vector Start, Rotator Dir)
{
local SeekerSixRocketProjectile Rocket;
local SeekerSixSeekingRocketProjectile SeekingRocket;
bBreakLock = true;
if (bLockedOn && SeekTarget != None)
{
SeekingRocket = Spawn(class'SeekerSixSeekingRocketProjectile',,, Start, Dir);
SeekingRocket.Seeking = SeekTarget;
return SeekingRocket;
}
else
{
Rocket = Spawn(class'SeekerSixRocketProjectile',,, Start, Dir);
return Rocket;
}
}
// Allow this weapon to auto reload on alt fire
simulated function AltFire(float F)
{
if( MagAmmoRemaining < 1 && !bIsReloading &&
FireMode[1].NextFireTime <= Level.TimeSeconds )
{
// We're dry, ask the server to autoreload
ServerRequestAutoReload();
PlayOwnedSound(FireMode[1].NoAmmoSound,SLOT_None,2.0,,,,false);
}
super.AltFire(F);
}
simulated function bool ConsumeAmmo( int Mode, float Load, optional bool bAmountNeededIsMax )
{
local Inventory Inv;
local bool bOutOfAmmo;
local KFWeapon KFWeap;
if ( Super(Weapon).ConsumeAmmo(Mode, Load, bAmountNeededIsMax) )
{
if ( Load > 0 && (Mode == 0 || bReduceMagAmmoOnSecondaryFire) )
MagAmmoRemaining -= Load;
NetUpdateTime = Level.TimeSeconds - 1;
if ( FireMode[Mode].AmmoPerFire > 0 && InventoryGroup > 0 && !bMeleeWeapon && bConsumesPhysicalAmmo &&
(Ammo[0] == none || FireMode[0] == none || FireMode[0].AmmoPerFire <= 0 || Ammo[0].AmmoAmount < FireMode[0].AmmoPerFire) &&
(Ammo[1] == none || FireMode[1] == none || FireMode[1].AmmoPerFire <= 0 || Ammo[1].AmmoAmount < FireMode[1].AmmoPerFire) )
{
bOutOfAmmo = true;
for ( Inv = Instigator.Inventory; Inv != none; Inv = Inv.Inventory )
{
KFWeap = KFWeapon(Inv);
if ( Inv.InventoryGroup > 0 && KFWeap != none && !KFWeap.bMeleeWeapon && KFWeap.bConsumesPhysicalAmmo &&
((KFWeap.Ammo[0] != none && KFWeap.FireMode[0] != none && KFWeap.FireMode[0].AmmoPerFire > 0 &&KFWeap.Ammo[0].AmmoAmount >= KFWeap.FireMode[0].AmmoPerFire) ||
(KFWeap.Ammo[1] != none && KFWeap.FireMode[1] != none && KFWeap.FireMode[1].AmmoPerFire > 0 && KFWeap.Ammo[1].AmmoAmount >= KFWeap.FireMode[1].AmmoPerFire)) )
{
bOutOfAmmo = false;
break;
}
}
if ( bOutOfAmmo )
{
PlayerController(Instigator.Controller).Speech('AUTO', 3, "");
}
}
return true;
}
return false;
}
function float GetAIRating()
{
local AIController B;
B = AIController(Instigator.Controller);
if ( (B == None) || (B.Enemy == None) )
return AIRating;
return (AIRating + 0.0003 * FClamp(1500 - VSize(B.Enemy.Location - Instigator.Location),0,1000));
}
function byte BestMode()
{
return 0;
}
function bool RecommendRangedAttack()
{
return true;
}
//TODO: long ranged?
function bool RecommendLongRangedAttack()
{
return true;
}
function float SuggestAttackStyle()
{
return -1.0;
}
simulated function AddReloadedAmmo()
{
UpdateMagCapacity(Instigator.PlayerReplicationInfo);
if(AmmoAmount(0) >= MagCapacity)
MagAmmoRemaining = MagCapacity;
else
MagAmmoRemaining = AmmoAmount(0) ;
// Don't do this on a "Hold to reload" weapon, as it can update too quick actually and cause issues maybe - Ramm
if( !bHoldToReload )
{
ClientForceKFAmmoUpdate(MagAmmoRemaining,AmmoAmount(0));
}
}
defaultproperties
{
WeaponReloadAnim=Reload_IJC_SeekerSix
IdleAimAnim=Idle_Iron
SkinRefs(0)="KF_IJC_Halloween_Weapons2.SeekerSix.Seeker_Six_cmb"
SkinRefs(1)="KF_IJC_Halloween_Weapons2.SeekerSix.Seeker_Sight_Shader"
SleeveNum=3
SiteReticleRef="KF_IJC_Halloween_Weapons2.SeekerSix.Seeker_Sight_Shader"
SiteReticleLockedRef="KF_IJC_Halloween_Weapons2.SeekerSix.Seeker_Sight_Lock_Shader"
Weight=7.000000
MagCapacity=6
ReloadRate=3.13
ReloadAnim="Reload"
ReloadAnimRate=1.0
FireModeClass(0)=Class'KFMod.SeekerSixFire'
FireModeClass(1)=Class'KFMod.SeekerSixMultiFire'
PutDownAnim="PutDown"
SelectSoundRef="KF_FY_SeekerSixSND.WEP_SeekerSix_Foley_Select"
SelectForce="SwitchToAssaultRifle"
bModeZeroCanDryFire=True
AIRating=0.650000
CurrentRating=0.650000
Description="An advanced Horzine mini missile launcher. Fire one, or all six, lock on and let 'em rip!"
Priority=182
InventoryGroup=4
GroupOffset=16
PickupClass=Class'KFMod.SeekerSixPickup'
PlayerViewOffset=(X=35.000000,Y=20.000000,Z=-5.000000)
BobDamping=6.000000
AttachmentClass=Class'KFMod.SeekerSixAttachment'
IconCoords=(X1=253,Y1=146,X2=333,Y2=181)
ItemName="SeekerSix Rocket Launcher"
LightType=LT_None
LightBrightness=0.000000
LightRadius=0.000000
MeshRef="KF_IJC_Halloween_Weps_2.SeekerSix"
DrawScale=1.000000
AmbientGlow=0
ZoomTime=0.25
FastZoomOutTime=0.2
ZoomInRotation=(Pitch=-910,Yaw=0,Roll=2910)
bHasAimingMode=true
DisplayFOV=65.000000
StandardDisplayFOV=65.0
PlayerIronSightFOV=70
ZoomedDisplayFOV=60
HudImageRef="KF_IJC_HUD.WeaponSelect.SeekerSix_unselected"
SelectedHudImageRef="KF_IJC_HUD.WeaponSelect.SeekerSix"
TraderInfoTexture=texture'KF_IJC_HUD.Trader_Weapon_Icons.Trader_SeekerSix'
// Achievement Helpers
bIsTier3Weapon=true
SeekCheckFreq=0.25
SeekRange=25000
LockRequiredTime=0.75
UnLockRequiredTime=0.5
LockAim=0.95
LockOnSoundRef="KF_FY_SeekerSixSND.WEP_Seeker_LockOn_M"
LockLostSoundRef="KF_FY_SeekerSixSND.WEP_Seeker_LockOnLost_M"
AppID=258751
}