1
0
KF2-Dev-Scripts/KFGameContent/Classes/KFWeap_AutoTurret.uc

666 lines
18 KiB
Ucode
Raw Normal View History

2022-05-11 15:13:25 +00:00
//=============================================================================
// KFWeap_AutoTurret
//=============================================================================
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFWeap_AutoTurret extends KFWeap_ThrownBase;
`define AUTOTURRET_MIC_LED_INDEX 2
const DETONATE_FIREMODE = 5; // NEW - IronSights Key
var(Animations) const editconst name DetonateAnim;
var(Animations) const editconst name DetonateLastAnim;
/** Sound to play upon successful detonation */
var() AkEvent DetonateAkEvent;
/** Sound to play upon attempted but unsuccessful detonation */
var() AkEvent DryFireAkEvent;
/** Strenght applied to forward dir to get the throwing velocity */
var const float ThrowStrength;
/** Max num of turrets that can be deployed */
var const byte MaxTurretsDeployed;
/** Offset to spawn the dron (screen coordinates) */
var const vector TurretSpawnOffset;
var transient byte NumDeployedTurrets;
var transient KFPlayerController KFPC;
/** If the turret is in a state available for throw another to fix some animation issues. */
var transient bool bTurretReadyToUse;
var repnotify float CurrentAmmoPercentage;
const TransitionParamName = 'transition_full_to_empty';
const EmptyParamName = 'Blinking_0_off___1_on';
replication
{
if( bNetDirty )
NumDeployedTurrets, CurrentAmmoPercentage, bTurretReadyToUse;
}
simulated event ReplicatedEvent(name VarName)
{
if (VarName == nameof(CurrentAmmoPercentage))
{
UpdateMaterialColor(CurrentAmmoPercentage);
}
else
{
Super.ReplicatedEvent(VarName);
}
}
simulated event PreBeginPlay()
{
local class<KFWeap_AutoTurretWeapon> WeaponClass;
super.PreBeginPlay();
WeaponClass = class<KFWeap_AutoTurretWeapon> (DynamicLoadObject(class'KFPawn_AutoTurret'.default.WeaponDefinition.default.WeaponClassPath, class'Class'));
WeaponClass.static.TriggerAsyncContentLoad(WeaponClass);
}
simulated event PostBeginPlay()
{
super.PostBeginPlay();
if (Role == ROLE_Authority)
{
KFPC = KFPlayerController(Instigator.Controller);
NumDeployedTurrets = KFPC.DeployedTurrets.Length;
}
}
/** Route ironsight player input to detonate */
simulated function SetIronSights(bool bNewIronSights)
{
if ( !Instigator.IsLocallyControlled() )
{
return;
}
if ( bNewIronSights )
{
StartFire(DETONATE_FIREMODE);
}
else
{
StopFire(DETONATE_FIREMODE);
}
}
/** Overridded to add spawned turret to list of spawned turrets */
simulated function Projectile ProjectileFire()
{
local vector SpawnLocation, SpawnDirection;
local KFPawn_AutoTurret SpawnedActor;
if (Role == ROLE_Authority && CurrentFireMode == DEFAULT_FIREMODE)
{
GetTurretSpawnLocationAndDir(SpawnLocation, SpawnDirection);
SpawnedActor = Spawn(class'KFPawn_AutoTurret', self,, SpawnLocation + (TurretSpawnOffset >> Rotation), Rotation,,true);
if( SpawnedActor != none )
{
SpawnedActor.OwnerWeapon = self;
SpawnedActor.SetPhysics(PHYS_Falling);
SpawnedActor.Velocity = SpawnDirection * ThrowStrength;
SpawnedActor.UpdateInstigator(Instigator);
SpawnedActor.UpdateWeaponUpgrade(CurrentWeaponUpgradeIndex);
SpawnedActor.SetTurretState(ETS_Throw);
KFPC.DeployedTurrets.AddItem( SpawnedActor );
NumDeployedTurrets = KFPC.DeployedTurrets.Length;
bForceNetUpdate = true;
}
return none;
}
else
{
return super.ProjectileFire();
}
return none;
}
simulated function GetTurretSpawnLocationAndDir(out vector SpawnLocation, out vector SpawnDirection)
{
local vector StartTrace, EndTrace, RealStartLoc, AimDir;
local ImpactInfo TestImpact;
local vector DirA, DirB;
local Quat Q;
// This is where we would start an instant trace. (what CalcWeaponFire uses)
StartTrace = GetSafeStartTraceLocation();
AimDir = Vector(GetAdjustedAim( StartTrace ));
// this is the location where the projectile is spawned.
RealStartLoc = GetPhysicalFireStartLoc(AimDir);
if( StartTrace != RealStartLoc )
{
// if projectile is spawned at different location of crosshair,
// then simulate an instant trace where crosshair is aiming at, Get hit info.
EndTrace = StartTrace + AimDir * GetTraceRange();
TestImpact = CalcWeaponFire( StartTrace, EndTrace );
// Store the original aim direction without correction
DirB = AimDir;
// Then we realign projectile aim direction to match where the crosshair did hit.
AimDir = Normal(TestImpact.HitLocation - RealStartLoc);
// Store the desired corrected aim direction
DirA = AimDir;
// Clamp the maximum aim adjustment for the AimDir so you don't get wierd
// cases where the projectiles velocity is going WAY off of where you
// are aiming. This can happen if you are really close to what you are
// shooting - Ramm
if ( (DirA dot DirB) < MaxAimAdjust_Cos )
{
Q = QuatFromAxisAndAngle(Normal(DirB cross DirA), MaxAimAdjust_Angle);
AimDir = QuatRotateVector(Q,DirB);
}
}
SpawnDirection = AimDir;
SpawnLocation = RealStartLoc;
}
/** Detonates the oldest turret */
simulated function Detonate()
{
// auto switch weapon when out of ammo and after detonating the last deployed turret
if( Role == ROLE_Authority )
{
if( KFPC.DeployedTurrets.Length > 0 )
{
KFPawn_AutoTurret(KFPC.DeployedTurrets[0]).SetTurretState(ETS_Detonate);
}
SetReadyToUse(true);
if( !HasAnyAmmo() && NumDeployedTurrets == 0 )
{
if( CanSwitchWeapons() )
{
Instigator.Controller.ClientSwitchToBestWeapon(false);
}
}
}
}
/** Removes a turret from the list using either an index or an actor and updates NumDeployedTurrets */
function RemoveDeployedTurret( optional int Index = INDEX_NONE, optional Actor TurretActor )
{
if( Index == INDEX_NONE )
{
if( TurretActor != none )
{
Index = KFPC.DeployedTurrets.Find( TurretActor );
}
}
if( Index != INDEX_NONE )
{
KFPC.DeployedTurrets.Remove( Index, 1 );
NumDeployedTurrets = KFPC.DeployedTurrets.Length;
bForceNetUpdate = true;
}
}
function SetOriginalValuesFromPickup( KFWeapon PickedUpWeapon )
{
local int i;
super.SetOriginalValuesFromPickup( PickedUpWeapon );
if (PickedUpWeapon.Instigator.Controller != none && PickedUpWeapon.Instigator.Controller != KFPC)
{
KFPC.DeployedTurrets = KFPlayerController(PickedUpWeapon.Instigator.Controller).DeployedTurrets;
}
NumDeployedTurrets = KFPC.DeployedTurrets.Length;
bForceNetUpdate = true;
for( i = 0; i < NumDeployedTurrets; ++i )
{
// charge alerts (beep, light) need current instigator
KFPC.DeployedTurrets[i].Instigator = Instigator;
KFPC.DeployedTurrets[i].SetOwner(self);
if( Instigator.Controller != none )
{
KFPawn_AutoTurret(KFPC.DeployedTurrets[i]).InstigatorController = Instigator.Controller;
}
}
}
/**
* Returns true if this weapon uses a secondary ammo pool
*/
static simulated event bool UsesAmmo()
{
return true;
}
simulated function bool HasAmmo( byte FireModeNum, optional int Amount )
{
if( FireModeNum == DETONATE_FIREMODE )
{
return NumDeployedTurrets > 0;
}
return super.HasAmmo( FireModeNum, Amount );
}
simulated function BeginFire( byte FireModeNum )
{
// Clear any pending detonate if we pressed the main fire
// That prevents strange holding right click behaviour and sound issues
if (FireModeNum == DEFAULT_FIREMODE)
{
ClearPendingFire(DETONATE_FIREMODE);
}
if (FireModeNum == DETONATE_FIREMODE && NumDeployedTurrets > 0)
{
if (bTurretReadyToUse)
{
PrepareAndDetonate();
}
}
else
{
if (FireModeNum == DEFAULT_FIREMODE
&& NumDeployedTurrets >= MaxTurretsDeployed
&& HasAmmo(THROW_FIREMODE))
{
if (!bTurretReadyToUse)
{
return;
}
PrepareAndDetonate();
}
else if (HasAmmo(THROW_FIREMODE) == false)
{
PlaySoundBase( DryFireAkEvent, true );
}
super.BeginFire( FireModeNum );
}
}
simulated function PrepareAndDetonate()
{
local name DetonateAnimName;
local float AnimDuration;
local bool bInSprintState;
DetonateAnimName = ShouldPlayLastAnims() ? DetonateLastAnim : DetonateAnim;
AnimDuration = MySkelMesh.GetAnimLength( DetonateAnimName );
bInSprintState = IsInState( 'WeaponSprinting' );
if( WorldInfo.NetMode != NM_DedicatedServer )
{
if( NumDeployedTurrets > 0 )
{
PlaySoundBase( DetonateAkEvent, true );
}
else
{
PlaySoundBase( DryFireAkEvent, true );
}
if( bInSprintState )
{
AnimDuration *= 0.25f;
PlayAnimation( DetonateAnimName, AnimDuration );
}
else
{
PlayAnimation( DetonateAnimName );
}
}
if( Role == ROLE_Authority )
{
Detonate();
}
IncrementFlashCount();
if( bInSprintState )
{
SetTimer( AnimDuration * 0.8f, false, nameof(PlaySprintStart) );
}
else
{
SetTimer( AnimDuration * 0.5f, false, nameof(GotoActiveState) );
}
}
// do nothing, as we have no alt fire mode
simulated function AltFireMode();
/** Allow weapons with abnormal state transitions to always use zed time resist*/
simulated function bool HasAlwaysOnZedTimeResist()
{
return true;
}
/*********************************************************************************************
* State Active
* A Weapon this is being held by a pawn should be in the active state. In this state,
* a weapon should loop any number of idle animations, as well as check the PendingFire flags
* to see if a shot has been fired.
*********************************************************************************************/
simulated state Active
{
/** Overridden to prevent playing fidget if play has no more ammo */
simulated function bool CanPlayIdleFidget(optional bool bOnReload)
{
if( !HasAmmo(0) )
{
return false;
}
return super.CanPlayIdleFidget( bOnReload );
}
}
/*********************************************************************************************
* State WeaponDetonating
* The weapon is in this state while detonating a charge
*********************************************************************************************/
simulated function GotoActiveState();
simulated state WeaponDetonating
{
ignores AllowSprinting;
simulated event BeginState( name PreviousStateName )
{
PrepareAndDetonate();
}
simulated function GotoActiveState()
{
GotoState('Active');
}
}
/*********************************************************************************************
* State WeaponThrowing
* Handles throwing weapon (similar to state GrenadeFiring)
*********************************************************************************************/
simulated state WeaponThrowing
{
/** Never refires. Must re-enter this state instead. */
simulated function bool ShouldRefire()
{
return false;
}
simulated function EndState(Name NextStateName)
{
local KFPerk InstigatorPerk;
Super.EndState(NextStateName);
//Targeted fix for Demolitionist w/ the C4. It should remain in zed time while waiting on
// the fake reload to be triggered. This will return 0 for other perks.
InstigatorPerk = GetPerk();
if( InstigatorPerk != none )
{
SetZedTimeResist( InstigatorPerk.GetZedTimeModifier(self) );
}
}
}
/*********************************************************************************************
* State WeaponEquipping
* The Weapon is in this state while transitioning from Inactive to Active state.
* Typically, the weapon will remain in this state while its selection animation is being played.
* While in this state, the weapon cannot be fired.
*********************************************************************************************/
simulated state WeaponEquipping
{
simulated event BeginState( name PreviousStateName )
{
super.BeginState( PreviousStateName );
// perform a "reload" if we refilled our ammo from empty while it was unequipped
if( !HasAmmo(THROW_FIREMODE) && HasSpareAmmo() )
{
PerformArtificialReload();
}
StopFire(DETONATE_FIREMODE);
}
}
/*********************************************************************************************
* State WeaponPuttingDown
* Putting down weapon in favor of a new one.
* Weapon is transitioning to the Inactive state.
*
* Detonating while putting down causes C4 not to be put down, which causes problems, so let's
* just ignore SetIronSights, which causes detonation
*********************************************************************************************/
simulated state WeaponPuttingDown
{
ignores SetIronSights;
simulated event BeginState( name PreviousStateName )
{
super.BeginState( PreviousStateName );
StopFire(DETONATE_FIREMODE);
}
}
/*********************************************************************************************
* @name Trader
*********************************************************************************************/
/** Returns trader filter index based on weapon type */
static simulated event EFilterTypeUI GetTraderFilter()
{
return FT_Explosive;
}
function CheckTurretAmmo()
{
local float Percentage;
local KFWeapon Weapon;
local KFPawn KFP;
if (Role == Role_Authority)
{
if (KFPC.DeployedTurrets.Length > 0)
{
Weapon = KFWeapon(KFPawn_AutoTurret(KFPC.DeployedTurrets[0]).Weapon);
if (Weapon != none)
{
Percentage = float(Weapon.AmmoCount[0]) / Weapon.MagazineCapacity[0];
if (Percentage != CurrentAmmoPercentage)
{
CurrentAmmoPercentage = Percentage;
bNetDirty = true;
if (WorldInfo.NetMode == NM_Standalone)
{
UpdateMaterialColor(CurrentAmmoPercentage);
}
else
{
KFP = KFPawn(Instigator);
KFP.OnWeaponSpecialAction( 1 + (CurrentAmmoPercentage * 100) );
}
}
}
}
}
}
function SetReadyToUse(bool bReady)
{
if (bTurretReadyToUse != bReady)
{
bTurretReadyToUse = bReady;
bNetDirty = true;
}
}
simulated event Tick(float DeltaTime)
{
super.Tick(DeltaTime);
if (Role == Role_Authority)
{
CheckTurretAmmo();
}
}
simulated function UpdateMaterialColor(float Percentage)
{
if (NumDeployedTurrets == 0)
{
WeaponMICs[`AUTOTURRET_MIC_LED_INDEX].SetScalarParameterValue(EmptyParamName, 0);
}
else if (Percentage >= 0)
{
WeaponMICs[`AUTOTURRET_MIC_LED_INDEX].SetScalarParameterValue(TransitionParamName, 1.0f - Percentage);
WeaponMICs[`AUTOTURRET_MIC_LED_INDEX].SetScalarParameterValue(EmptyParamName, Percentage == 0 ? 1 : 0);
}
}
simulated function SetWeaponUpgradeLevel(int WeaponUpgradeLevel)
{
local Actor Turret;
local KFPawn_AutoTurret TurretPawn;
super.SetWeaponUpgradeLevel(WeaponUpgradeLevel);
if (KFPC != none)
{
foreach KFPC.DeployedTurrets(Turret)
{
TurretPawn = KFPawn_AutoTurret(Turret);
if (TurretPawn != none)
{
TurretPawn.UpdateWeaponUpgrade(WeaponUpgradeLevel);
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// Trader
//
///////////////////////////////////////////////////////////////////////////////////////////
/** Allows weapon to calculate its own stats for display in trader */
static simulated event SetTraderWeaponStats( out array<STraderItemWeaponStats> WeaponStats )
{
super.SetTraderWeaponStats(WeaponStats);
WeaponStats.Length = 4;
WeaponStats[0].StatType = TWS_Damage;
WeaponStats[0].StatValue = class'KFWeap_AutoTurretWeapon'.static.CalculateTraderWeaponStatDamage();
WeaponStats[1].StatType = TWS_Penetration;
WeaponStats[1].StatValue = class'KFWeap_AutoTurretWeapon'.default.PenetrationPower[DEFAULT_FIREMODE];
WeaponStats[2].StatType = TWS_Range;
// This is now set in native since EffectiveRange has been moved to KFWeaponDefinition
// WeaponStats[2].StatValue = CalculateTraderWeaponStatRange();
WeaponStats[3].StatType = TWS_RateOfFire;
WeaponStats[3].StatValue = class'KFWeap_AutoTurretWeapon'.static.CalculateTraderWeaponStatFireRate();
}
defaultproperties
{
// start in detonate mode so that an attempt to detonate before any charges are thrown results in
// the proper third-person anim
CurrentFireMode=DETONATE_FIREMODE
// Zooming/Position
PlayerViewOffset=(X=6.0,Y=2,Z=-4)
FireOffset=(X=0,Y=0)
TurretSpawnOffset=(X=0, Y=15, Z=-50)
// Content
PackageKey="AutoTurret"
FirstPersonMeshName="Wep_1P_AutoTurret_MESH.Wep_1stP_AutoTurret_Rig"
FirstPersonAnimSetNames(0)="Wep_1P_AutoTurret_ANIM.Wep_1P_AutoTurret_ANIM"
PickupMeshName="wep_3p_autoturret_mesh.Wep_AutoTurret_Pickup"
AttachmentArchetypeName="WEP_AutoTurret_ARCH.Wep_AutoTurret_3P"
// Anim
FireAnim=C4_Throw
FireLastAnim=C4_Throw_Last
DetonateAnim=Detonate
DetonateLastAnim=Detonate_Last
// Ammo
MagazineCapacity[0]=1
SpareAmmoCapacity[0]=3
InitialSpareMags[0]=1
AmmoPickupScale[0]=1.0
// THROW_FIREMODE
FireInterval(THROW_FIREMODE)=0.25
FireModeIconPaths(THROW_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Drone'
// DETONATE_FIREMODE
FiringStatesArray(DETONATE_FIREMODE)=WeaponDetonating
WeaponFireTypes(DETONATE_FIREMODE)=EWFT_Custom
AmmoCost(DETONATE_FIREMODE)=0
// BASH_FIREMODE
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_AutoTurret'
InstantHitDamage(BASH_FIREMODE)=26
// Inventory / Grouping
InventoryGroup=IG_Equipment
GroupPriority=11
WeaponSelectTexture=Texture2D'WEP_UI_AutoTurret_TEX.UI_WeaponSelect_AutoTurret'
InventorySize=3
DetonateAkEvent=AkEvent'ww_wep_autoturret.Play_WEP_AutoTurret_Detonate_Trigger'
DryFireAkEvent=AkEvent'ww_wep_autoturret.Play_WEP_AutoTurret_Dry_Fire'
// Weapon Upgrade stat boosts
//WeaponUpgrades[1]=(IncrementDamage=1.05f,IncrementWeight=1)
//WeaponUpgrades[2]=(IncrementDamage=1.1f,IncrementWeight=2)
//WeaponUpgrades[3]=(IncrementDamage=1.15f,IncrementWeight=3)
AssociatedPerkClasses(0)=class'KFPerk_Commando'
MaxTurretsDeployed=1
NumDeployedTurrets=0
ThrowStrength=1350.0f
bTurretReadyToUse=true
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Damage1, Scale=1.15f), (Stat=EWUS_Weight, Add=1)))
WeaponUpgrades[2]=(Stats=((Stat=EWUS_Damage0, Scale=1.3f), (Stat=EWUS_Damage1, Scale=1.3f), (Stat=EWUS_Weight, Add=2)))
NumBloodMapMaterials=3
}