877 lines
29 KiB
Ucode
877 lines
29 KiB
Ucode
//=============================================================================
|
|
// KFPerk_Support
|
|
//=============================================================================
|
|
// Support Perk
|
|
//=============================================================================
|
|
// Killing Floor 2
|
|
// Copyright (C) 2015 Tripwire Interactive LLC
|
|
// - Christian "schneidzekk" Schneider
|
|
//=============================================================================
|
|
class KFPerk_Support extends KFPerk
|
|
hidecategories(Mobile, Object, Debug, Advanced, Physics, Actor, Attachment, Display)
|
|
native;
|
|
|
|
//`include(KFOnlineStats.uci)
|
|
|
|
struct native sSuppliedPawnInfo
|
|
{
|
|
var KFPawn_Human SuppliedPawn;
|
|
var bool bSuppliedAmmo;
|
|
var bool bSuppliedArmor;
|
|
};
|
|
|
|
/** Passives */
|
|
var private const PerkSkill Ammo; // Increased ammo
|
|
var private const PerkSkill WeldingProficiency; // Welding speed modifier
|
|
var private const PerkSkill ShotgunDamage; // Shotgun dmg modifier
|
|
var private const PerkSkill ShotgunPenetration; // Shotgun extra penetration Use INTs only
|
|
var private const PerkSkill Strength;
|
|
|
|
var private Array<sSuppliedPawnInfo> SuppliedPawnList;
|
|
var private const float BarrageFiringRate;
|
|
var private const float ResupplyMaxSpareAmmoModifier;
|
|
var private const AkEvent ReceivedAmmoSound;
|
|
var private const AkEvent ReceivedArmorSound;
|
|
var private const AkEvent ReceivedAmmoAndArmorSound;
|
|
|
|
var private const array<name> HighCapMagExemptList;
|
|
|
|
var private const array<Name> AdditionalOnPerkDTNames;
|
|
|
|
var private const int DoorRepairXP[4]; // Door repair XP per-difficulty
|
|
|
|
enum ESupportPerkSkills
|
|
{
|
|
ESupportHighCapMags,
|
|
ESupportTacticalReload,
|
|
ESupportFortitude,
|
|
ESupportSalvo,
|
|
ESupportAPShot,
|
|
ESupportTightChoke,
|
|
ESupportResupply,
|
|
ESupportConcussionRounds,
|
|
ESupportPerforate,
|
|
ESupportBarrage,
|
|
};
|
|
|
|
/*********************************************************************************************
|
|
* @name Perk init and spawning
|
|
******************************************************************************************** */
|
|
/**
|
|
* @brief(Server) Modify Instigator settings based on selected perk
|
|
*/
|
|
function ApplySkillsToPawn()
|
|
{
|
|
local KFGameReplicationInfo KFGRI;
|
|
|
|
Super.ApplySkillsToPawn();
|
|
|
|
KFGRI = KFGameReplicationInfo(WorldInfo.GRI);
|
|
|
|
if (KFGRI == none && KFGRI.bTraderIsOpen)
|
|
{
|
|
return;
|
|
}
|
|
//ResetSupplier();
|
|
}
|
|
|
|
/**
|
|
* We need to separate this from ApplySkillsToPawn() to avoid resetting weight limits (and losing weapons)
|
|
* every time a skill or level is changed
|
|
*/
|
|
function ApplyWeightLimits()
|
|
{
|
|
local KFInventoryManager KFIM;
|
|
|
|
KFIM = KFInventoryManager(OwnerPawn.InvManager);
|
|
if( KFIM != none )
|
|
{
|
|
`QALog( "Strength Mod" @ GetPercentage(KFIM.MaxCarryBlocks, KFIM.default.MaxCarryBlocks + GetExtraStrength( CurrentLevel )), bLogPerk );
|
|
KFIM.MaxCarryBlocks = KFIM.default.MaxCarryBlocks + GetExtraStrength( CurrentLevel );
|
|
CheckForOverWeight( KFIM );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Calculates the additional carry blocks per perk level
|
|
*
|
|
* @param Level Current perk level
|
|
* @return additional blocks
|
|
*/
|
|
simulated private final static function float GetExtraStrength( int Level )
|
|
{
|
|
return default.Strength.Increment * FFloor( float( Level ) / 5.f );
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Sets up the supplier skill
|
|
*/
|
|
simulated final private function ResetSupplier()
|
|
{
|
|
if( MyPRI != none && IsSupplierActive() )
|
|
{
|
|
if( SuppliedPawnList.Length > 0 )
|
|
{
|
|
SuppliedPawnList.Remove( 0, SuppliedPawnList.Length );
|
|
}
|
|
|
|
MyPRI.PerkSupplyLevel = IsResupplyActive() ? 2 : 1;
|
|
|
|
if( InteractionTrigger != none )
|
|
{
|
|
InteractionTrigger.Destroy();
|
|
InteractionTrigger = none;
|
|
}
|
|
|
|
if( CheckOwnerPawn() )
|
|
{
|
|
InteractionTrigger = Spawn( class'KFUsablePerkTrigger', OwnerPawn,, OwnerPawn.Location, OwnerPawn.Rotation,, true );
|
|
InteractionTrigger.SetBase( OwnerPawn );
|
|
InteractionTrigger.SetInteractionIndex( IMT_ReceiveAmmo );
|
|
OwnerPC.SetPendingInteractionMessage();
|
|
}
|
|
}
|
|
else if( InteractionTrigger != none )
|
|
{
|
|
InteractionTrigger.Destroy();
|
|
}
|
|
}
|
|
|
|
/*********************************************************************************************
|
|
* @name Passives
|
|
********************************************************************************************* */
|
|
/**
|
|
* @brief Modifes the damage dealt
|
|
*
|
|
* @param InDamage damage
|
|
* @param DamageCauser weapon or projectile (optional)
|
|
* @param MyKFPM the zed damaged (optional)
|
|
* @param DamageInstigator responsible controller (optional)
|
|
* @param class DamageType the damage type used (optional)
|
|
*/
|
|
simulated function ModifyDamageGiven( out int InDamage, optional Actor DamageCauser, optional KFPawn_Monster MyKFPM, optional KFPlayerController DamageInstigator, optional class<KFDamageType> DamageType, optional int HitZoneIdx )
|
|
{
|
|
local KFWeapon KFW;
|
|
local float TempDamage;
|
|
|
|
TempDamage = InDamage;
|
|
`QALog( GetFuncName() @ "BaseDamage =" @ InDamage, bLogPerk );
|
|
|
|
|
|
TempDamage = InDamage;
|
|
|
|
if( DamageCauser != none )
|
|
{
|
|
KFW = GetWeaponFromDamageCauser( DamageCauser );
|
|
}
|
|
|
|
if( ((KFW != none && IsWeaponOnPerk( KFW,, self.class )) || (DamageType != none && IsDamageTypeOnPerk( DamageType ))) &&
|
|
!ClassIsChildOf( DamageType, class'KFDT_Explosive' ) )
|
|
{
|
|
TempDamage += InDamage * GetPassiveValue( ShotgunDamage, CurrentLevel );
|
|
`QALog( GetFuncName() @ "+ Extra Shotgun Damage =" @ TempDamage, bLogPerk );
|
|
|
|
if( IsSalvoActive() )
|
|
{
|
|
TempDamage += InDamage * GetSkillValue( PerkSkills[ESupportSalvo] );
|
|
`QALog( GetFuncName() @ "+ Salvo Damage =" @ TempDamage, bLogPerk );
|
|
}
|
|
}
|
|
|
|
`QALog( "Total Damage Given" @ Damagetype @ KFW @ GetPercentage( InDamage, Round(TempDamage) ), bLogPerk );
|
|
InDamage = Round( TempDamage );
|
|
}
|
|
|
|
/** Welding Proficiency - faster welding/unwelding */
|
|
/**
|
|
* @brief Modifies the welding speed
|
|
*
|
|
* @param FastenRate how much faster do we weld
|
|
* @param UnfastenRate how much faster do we unweld
|
|
*
|
|
*/
|
|
simulated function ModifyWeldingRate( out float FastenRate, out float UnfastenRate )
|
|
{
|
|
local float WeldingModifier;
|
|
|
|
WeldingModifier = GetPassiveValue( WeldingProficiency, CurrentLevel );
|
|
FastenRate *= WeldingModifier;
|
|
UnFastenRate *= WeldingModifier;
|
|
`QALog( "Welding Modifier" @ WeldingModifier, bLogPerk );
|
|
}
|
|
|
|
/**
|
|
* @brief the higher the level the more can we penetrate
|
|
*
|
|
* @param Level current perk level
|
|
* @param DamageType the use weapon's damage type
|
|
* @param bForce
|
|
* @return the additional penetrations
|
|
*/
|
|
simulated function float GetPenetrationModifier( byte Level, class<KFDamageType> DamageType, optional bool bForce )
|
|
{
|
|
local float PenetrationPower;
|
|
// Only buff damage types that are associated with support
|
|
if( !bForce && (DamageType == none || !IsDamageTypeOnPerk( Damagetype )) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
PenetrationPower = IsAPShotActive() ? GetSkillValue( PerkSkills[ESupportAPShot] ) : 0.f;
|
|
PenetrationPower = IsPerforateActive() ? GetSkillValue( PerkSkills[ESupportPerforate] ) : PenetrationPower;
|
|
`QALog( "PenetrationPower" @ PenetrationPower + GetPassiveValue( ShotgunPenetration, Level ), bLogPerk );
|
|
|
|
return PenetrationPower + GetPassiveValue( ShotgunPenetration, Level );
|
|
}
|
|
|
|
simulated function bool IgnoresPenetrationDmgReduction()
|
|
{
|
|
return IsPerforateActive();
|
|
}
|
|
|
|
/*********************************************************************************************
|
|
* @name Selectable skills
|
|
********************************************************************************************* */
|
|
/**
|
|
* @brief Modifies mag capacity and count
|
|
*
|
|
* @param KFW the weapon
|
|
* @param MagazineCapacity modified mag capacity
|
|
* @param WeaponPerkClass the weapon's associated perk class (optional)
|
|
*/
|
|
simulated function ModifyMagSizeAndNumber( KFWeapon KFW, out int MagazineCapacity, optional array< Class<KFPerk> > WeaponPerkClass, optional bool bSecondary=false, optional name WeaponClassName)
|
|
{
|
|
local float TempCapacity;
|
|
|
|
TempCapacity = MagazineCapacity;
|
|
|
|
// FAMAS needs its secondary ammo affected
|
|
if( (!bSecondary || IsFAMAS(KFW)) && IsWeaponOnPerk( KFW, WeaponPerkClass, self.class ) && (KFW == none || !KFW.bNoMagazine) &&
|
|
HighCapMagExemptList.Find(WeaponClassName) == INDEX_NONE )
|
|
{
|
|
if( IsHighCapMagsMagActive() )
|
|
{
|
|
TempCapacity += MagazineCapacity * GetSkillValue( PerkSkills[ESupportHighCapMags] );
|
|
}
|
|
}
|
|
|
|
MagazineCapacity = Round(TempCapacity);
|
|
}
|
|
|
|
/**
|
|
* @brief Modifies starting spare ammo
|
|
*
|
|
* @param KFW The weapon
|
|
* @param PrimarySpareAmmo ammo amount
|
|
* @param TraderItem the weapon's associated trader item info
|
|
*/
|
|
simulated function ModifySpareAmmoAmount( KFWeapon KFW, out int PrimarySpareAmmo, optional const out STraderItem TraderItem, optional bool bSecondary )
|
|
{
|
|
local float TempSpareAmmoAmount;
|
|
local array< class<KFPerk> > WeaponPerkClass;
|
|
|
|
if(KFW == none)
|
|
{
|
|
WeaponPerkClass = TraderItem.AssociatedPerkClasses;
|
|
}
|
|
else
|
|
{
|
|
WeaponPerkClass = KFW.GetAssociatedPerkClasses();
|
|
}
|
|
|
|
if( IsWeaponOnPerk( KFW, WeaponPerkClass, self.class ) )
|
|
{
|
|
TempSpareAmmoAmount = PrimarySpareAmmo;
|
|
TempSpareAmmoAmount += PrimarySpareAmmo * GetPassiveValue( Ammo, CurrentLevel );
|
|
PrimarySpareAmmo = Round( TempSpareAmmoAmount );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Modifies the max spare ammo
|
|
*
|
|
* @param KFW The weapon
|
|
* @param PrimarySpareAmmo ammo amount
|
|
* @param TraderItem the weapon's associated trader item info
|
|
*/
|
|
simulated function ModifyMaxSpareAmmoAmount( KFWeapon KFW, out int MaxSpareAmmo, optional const out STraderItem TraderItem, optional bool bSecondary=false )
|
|
{
|
|
local float TempMaxSpareAmmoAmount;
|
|
local array< class<KFPerk> > WeaponPerkClass;
|
|
|
|
if(KFW == none)
|
|
{
|
|
WeaponPerkClass = TraderItem.AssociatedPerkClasses;
|
|
}
|
|
else
|
|
{
|
|
WeaponPerkClass = KFW.GetAssociatedPerkClasses();
|
|
}
|
|
|
|
if( IsWeaponOnPerk( KFW, WeaponPerkClass, self.class ) && MaxSpareAmmo > 0 )
|
|
{
|
|
TempMaxSpareAmmoAmount = MaxSpareAmmo;
|
|
TempMaxSpareAmmoAmount += MaxSpareAmmo * GetPassiveValue( Ammo, CurrentLevel );
|
|
`QALog( "Ammo Passive, MaxSpareAmmo = +" @ (MaxSpareAmmo + MaxSpareAmmo * GetPassiveValue( Ammo, CurrentLevel )) / MaxSpareAmmo $ "%", bLogPerk );
|
|
|
|
if( IsResupplyActive() )
|
|
{
|
|
TempMaxSpareAmmoAmount += MaxSpareAmmo * GetResupplyMaxSpareAmmoModifier();
|
|
`QALog( "Resupply skill, MaxSpareAmmo = +" @ (MaxSpareAmmo + MaxSpareAmmo * GetResupplyMaxSpareAmmoModifier()) / MaxSpareAmmo $ "%", bLogPerk );
|
|
}
|
|
|
|
MaxSpareAmmo = Round( TempMaxSpareAmmoAmount );
|
|
}
|
|
}
|
|
|
|
simulated private static function float GetResupplyMaxSpareAmmoModifier()
|
|
{
|
|
return default.ResupplyMaxSpareAmmoModifier;
|
|
}
|
|
|
|
/**
|
|
* @brief Should the tactical reload skill adjust the reload speed
|
|
*
|
|
* @param KFW weapon in use
|
|
* @return true/false
|
|
*/
|
|
simulated function bool GetUsingTactialReload( KFWeapon KFW )
|
|
{
|
|
return IsTacticalReloadActive() && (IsWeaponOnPerk( KFW,, self.class ) || IsBackupWeapon( KFW ) || IsDual9mm( KFW ));
|
|
}
|
|
|
|
/**
|
|
* @brief modifies the players health
|
|
*
|
|
* @param InHealth health
|
|
*/
|
|
function ModifyHealth( out int InHealth )
|
|
{
|
|
local float TempHealth;
|
|
|
|
if( IsFortitudeActive() )
|
|
{
|
|
TempHealth = InHealth;
|
|
TempHealth += InHealth * GetSkillValue( PerkSkills[ESupportFortitude] );
|
|
InHealth = FCeil( TempHealth );
|
|
}
|
|
}
|
|
|
|
simulated function float GetTightChokeModifier()
|
|
{
|
|
local KFWeapon MyKFWeapon;
|
|
|
|
MyKFWeapon = GetOwnerWeapon();
|
|
if( IsTightChokeActive() && IsWeaponOnPerk(MyKFWeapon,, self.class) )
|
|
{
|
|
return GetSkillValue( PerkSkills[ESupportTightChoke] );
|
|
}
|
|
|
|
return super.GetTightChokeModifier();
|
|
}
|
|
|
|
/**
|
|
* @brief skills and weapons can modify the stumbling power
|
|
* @return stumbling power modifier
|
|
*/
|
|
function float GetStumblePowerModifier( optional KFPawn KFP, optional class<KFDamageType> DamageType, optional out float CooldownModifier, optional byte BodyPart )
|
|
{
|
|
if( IsWeaponOnPerk( GetOwnerWeapon(),, self.class ) && IsConcussionRoundsActive() )
|
|
{
|
|
return GetSkillValue( PerkSkills[ESupportConcussionRounds] );
|
|
}
|
|
|
|
return 0.f;
|
|
}
|
|
|
|
/**
|
|
* @brief General interaction with another pawn, here: give ammo
|
|
*
|
|
* @param KFPH Pawn to interact with
|
|
*/
|
|
simulated function Interact( KFPawn_Human KFPH )
|
|
{
|
|
local KFWeapon KFW;
|
|
local int Idx, MagCount;
|
|
local KFPlayerController KFPC;
|
|
local KFPlayerReplicationInfo UserPRI, OwnerPRI;
|
|
local bool bCanSupplyAmmo, bCanSupplyArmor;
|
|
local bool bReceivedAmmo, bReceivedArmor;
|
|
local sSuppliedPawnInfo SuppliedPawnInfo;
|
|
|
|
// Do nothing if supplier isn't active
|
|
if( !IsSupplierActive() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
bCanSupplyAmmo = true;
|
|
bCanSupplyArmor = true;
|
|
Idx = SuppliedPawnList.Find( 'SuppliedPawn', KFPH );
|
|
if( Idx != INDEX_NONE )
|
|
{
|
|
bCanSupplyAmmo = !SuppliedPawnList[Idx].bSuppliedAmmo;
|
|
bCanSupplyArmor = !SuppliedPawnList[Idx].bSuppliedArmor;
|
|
if( !bCanSupplyAmmo && !bCanSupplyArmor )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if( bCanSupplyAmmo )
|
|
{
|
|
foreach KFPH.InvManager.InventoryActors( class'KFWeapon', KFW )
|
|
{
|
|
if( KFW.static.DenyPerkResupply() )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// resupply 1 mag for every 5 initial mags
|
|
MagCount = Max( KFW.InitialSpareMags[0] / 1.5, 1 ); // 3, 1
|
|
`QALog( "Supply Ammo Primary Weapon " @ KFW @ MagCount * KFW.MagazineCapacity[0], bLogPerk );
|
|
bReceivedAmmo = (KFW.AddAmmo( MagCount * KFW.MagazineCapacity[0] * (IsResupplyActive() ? 1.3f : 1.0f) ) > 0 ) ? true : bReceivedAmmo;
|
|
|
|
if( KFW.CanRefillSecondaryAmmo() )
|
|
{
|
|
// resupply 1 mag for every 5 initial mags
|
|
`QALog( "Supply Ammo Secondary Weapon" @ KFW @ Max( KFW.InitialSpareMags[1] / 3, 1 ), bLogPerk );
|
|
|
|
// If our secondary ammo isn't mag-based (like the Eviscerator), restore a portion of max ammo instead
|
|
bReceivedAmmo = (KFW.AddSecondaryAmmo( Max(KFW.AmmoPickupScale[1] * (IsResupplyActive() ? 1.3f : 1.0f) * KFW.MagazineCapacity[1], 1) ) > 0) ? true : bReceivedAmmo;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( bCanSupplyArmor && IsResupplyActive() && KFPH.Armor != KFPH.GetMaxArmor() )
|
|
{
|
|
KFPH.AddArmor( KFPH.MaxArmor * GetSkillValue( PerkSkills[ESupportResupply] ) );
|
|
bReceivedArmor = true;
|
|
}
|
|
|
|
// Add to array (if necessary) and flag as supplied as needed
|
|
if( bReceivedArmor || bReceivedAmmo )
|
|
{
|
|
if( Idx == INDEX_NONE )
|
|
{
|
|
SuppliedPawnInfo.SuppliedPawn = KFPH;
|
|
SuppliedPawnInfo.bSuppliedAmmo = bReceivedAmmo;
|
|
SuppliedPawnInfo.bSuppliedArmor = bReceivedArmor;
|
|
Idx = SuppliedPawnList.Length;
|
|
SuppliedPawnList.AddItem( SuppliedPawnInfo );
|
|
}
|
|
else
|
|
{
|
|
SuppliedPawnList[Idx].bSuppliedAmmo = SuppliedPawnList[Idx].bSuppliedAmmo || bReceivedAmmo;
|
|
SuppliedPawnList[Idx].bSuppliedArmor = SuppliedPawnList[Idx].bSuppliedArmor || bReceivedArmor;
|
|
}
|
|
|
|
if( Role == ROLE_Authority )
|
|
{
|
|
KFPC = KFPlayerController( KFPH.Controller );
|
|
if( bReceivedAmmo )
|
|
{
|
|
OwnerPC.ReceiveLocalizedMessage( class'KFLocalMessage_Game', bReceivedArmor ? GMT_GaveAmmoAndArmorTo : GMT_GaveAmmoTo, KFPC.PlayerReplicationInfo );
|
|
KFPC.ReceiveLocalizedMessage( class'KFLocalMessage_Game', bReceivedArmor ? GMT_ReceivedAmmoAndArmorFrom : GMT_ReceivedAmmoFrom, OwnerPC.PlayerReplicationInfo );
|
|
}
|
|
else if( bReceivedArmor )
|
|
{
|
|
OwnerPC.ReceiveLocalizedMessage( class'KFLocalMessage_Game', GMT_GaveArmorTo, KFPC.PlayerReplicationInfo );
|
|
KFPC.ReceiveLocalizedMessage( class'KFLocalMessage_Game', GMT_ReceivedArmorFrom, OwnerPC.PlayerReplicationInfo );
|
|
}
|
|
|
|
UserPRI = KFPlayerReplicationInfo( KFPC.PlayerReplicationInfo );
|
|
OwnerPRI = KFPlayerReplicationInfo( OwnerPC.PlayerReplicationInfo );
|
|
if( UserPRI != none && OwnerPRI != none )
|
|
{
|
|
UserPRI.MarkSupplierOwnerUsed( OwnerPRI, SuppliedPawnList[Idx].bSuppliedAmmo, SuppliedPawnList[Idx].bSuppliedArmor );
|
|
}
|
|
}
|
|
}
|
|
else if( Role == ROLE_Authority )
|
|
{
|
|
KFPC = KFPlayerController( KFPH.Controller );
|
|
if( IsResupplyActive() )
|
|
{
|
|
KFPC.ReceiveLocalizedMessage( class'KFLocalMessage_Game', GMT_AmmoAndArmorAreFull, OwnerPC.PlayerReplicationInfo );
|
|
}
|
|
else
|
|
{
|
|
KFPC.ReceiveLocalizedMessage( class'KFLocalMessage_Game', GMT_AmmoIsFull, OwnerPC.PlayerReplicationInfo );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Can other pawns interact with us?
|
|
*
|
|
* @param MyKFPH the other pawn
|
|
* @return true/false
|
|
*/
|
|
simulated function bool CanInteract( KFPawn_HUman MyKFPH )
|
|
{
|
|
local int Idx;
|
|
|
|
if( IsSupplierActive() )
|
|
{
|
|
Idx = SuppliedPawnList.Find( 'SuppliedPawn', MyKFPH );
|
|
|
|
// Pawn hasn't gotten anything from us yet
|
|
if( Idx == INDEX_NONE )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Resupply is active and pawn hasn't gotten armor yet
|
|
if( IsResupplyActive() && !SuppliedPawnList[Idx].bSuppliedArmor )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Pawn hasn't gotten ammo
|
|
return !SuppliedPawnList[Idx].bSuppliedAmmo;
|
|
}
|
|
}
|
|
|
|
simulated static function AKEvent GetReceivedAmmoSound()
|
|
{
|
|
return default.ReceivedAmmoSound;
|
|
}
|
|
|
|
simulated static function AKEvent GetReceivedArmorSound()
|
|
{
|
|
return default.ReceivedArmorSound;
|
|
}
|
|
|
|
simulated static function AKEvent GetReceivedAmmoAndArmorSound()
|
|
{
|
|
return default.ReceivedAmmoAndArmorSound;
|
|
}
|
|
|
|
/**
|
|
* @brief Skills can modify the zed time time delation
|
|
*
|
|
* @param StateName used weapon's state
|
|
* @return time dilation modifier
|
|
*/
|
|
simulated function float GetZedTimeModifier( KFWeapon W )
|
|
{
|
|
local name StateName;
|
|
StateName = W.GetStateName();
|
|
|
|
// Blast Brawlers use a different state for shooting (combining melee + firing). Needs a special case for this
|
|
// FAMAS uses alt fire as common firing. Another special case added
|
|
if( IsWeaponOnPerk( W,, self.class ) && CouldBarrageActive() &&
|
|
(ZedTimeModifyingStates.Find( StateName ) != INDEX_NONE ||
|
|
(StateName == 'MeleeChainAttacking' && IsBlastBrawlers(W)) ||
|
|
(IsFAMAS(W) && StateName == 'FiringSecondaryState')))
|
|
{
|
|
return BarrageFiringRate;
|
|
}
|
|
|
|
return 0.f;
|
|
}
|
|
|
|
/**
|
|
* @brief Resets certain perk values on wave start/end
|
|
*/
|
|
function OnWaveStart()
|
|
{
|
|
Super.OnWaveStart();
|
|
ResetSupplier();
|
|
}
|
|
|
|
simulated static function GetPassiveStrings( out array<string> PassiveValues, out array<string> Increments, byte Level )
|
|
{
|
|
PassiveValues[0] = Round( (GetPassiveValue( default.WeldingProficiency, Level ) - 1) * 100) $ "%";
|
|
PassiveValues[1] = Round( GetPassiveValue( default.ShotgunDamage, Level ) * 100) $ "%";
|
|
PassiveValues[2] = Round( GetPassiveValue( default.ShotgunPenetration, Level ) * 100) $ "%";
|
|
PassiveValues[3] = Round( GetPassiveValue( default.Ammo, Level ) * 100) $ "%";
|
|
PassiveValues[4] = "";
|
|
PassiveValues[5] = "";
|
|
|
|
Increments[0] = "[" @ Left( string( default.WeldingProficiency.Increment * 100 ), InStr(string(default.WeldingProficiency.Increment * 100), ".") + 2 ) $ "% /" @ default.LevelString @ "]";
|
|
Increments[1] = "[" @ Left( string( default.ShotgunDamage.Increment * 100 ), InStr(string(default.ShotgunDamage.Increment * 100), ".") + 2 ) $ "% /" @ default.LevelString @ "]";
|
|
Increments[2] = "[" @ Left( string( default.ShotgunPenetration.Increment * 100 ), InStr(string(default.ShotgunPenetration.Increment * 100), ".") + 2 ) $ "% /" @ default.LevelString @ "]";
|
|
Increments[3] = "[" @ Left( string( default.Ammo.Increment * 100 ), InStr(string(default.Ammo.Increment * 100), ".") + 2 ) $ "% /" @ default.LevelString @ "]";
|
|
Increments[4] = "";
|
|
Increments[5] = "";
|
|
}
|
|
|
|
/**
|
|
* @brief DamageType on perk?
|
|
*
|
|
* @param KFDT The damage type
|
|
* @return true/false
|
|
*/
|
|
static function bool IsDamageTypeOnPerk( class<KFDamageType> KFDT )
|
|
{
|
|
if( KFDT != none && default.AdditionalOnPerkDTNames.Find( KFDT.name ) != INDEX_NONE )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return super.IsDamageTypeOnPerk( KFDT );
|
|
}
|
|
|
|
/*********************************************************************************************
|
|
* @name Getters
|
|
********************************************************************************************* */
|
|
/**
|
|
* @brief Checks if the supplier skill is active
|
|
*
|
|
* @return true if we have the skill enabled
|
|
*/
|
|
simulated function bool IsSupplierActive()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @brief Checks if the barrage skill is active and if we are in zed time
|
|
*
|
|
* @return true if we have the skill enabled
|
|
*/
|
|
private function bool IsBarrageActive()
|
|
{
|
|
return PerkSkills[ESupportBarrage].bActive && WorldInfo.TimeDilation < 1.f && IsPerkLevelAllowed(ESupportBarrage);
|
|
}
|
|
|
|
simulated private function bool CouldBarrageActive()
|
|
{
|
|
return PerkSkills[ESupportBarrage].bActive && IsPerkLevelAllowed(ESupportBarrage);
|
|
}
|
|
|
|
/**
|
|
* @brief Checks if the ammo skill is active
|
|
*
|
|
* @return true if we have the skill enabled
|
|
*/
|
|
simulated private function bool IsHighCapMagsMagActive()
|
|
{
|
|
return PerkSkills[ESupportHighCapMags].bActive && IsPerkLevelAllowed(ESupportHighCapMags);
|
|
}
|
|
|
|
/**
|
|
* @brief Checks if the fortitude skill is active
|
|
*
|
|
* @return true if we have the skill enabled
|
|
*/
|
|
private function bool IsFortitudeActive()
|
|
{
|
|
return PerkSkills[ESupportFortitude].bActive && IsPerkLevelAllowed(ESupportFortitude);
|
|
}
|
|
|
|
/**
|
|
* @brief Checks if the Salvo skill is active
|
|
*
|
|
* @return true if we have the skill enabled
|
|
*/
|
|
private function bool IsSalvoActive()
|
|
{
|
|
return PerkSkills[ESupportSalvo].bActive && IsPerkLevelAllowed(ESupportSalvo);
|
|
}
|
|
|
|
/**
|
|
* @brief Checks if the Armor Piercing Shot skill is active
|
|
*
|
|
* @return true if we have the skill enabled
|
|
*/
|
|
simulated private function bool IsAPShotActive()
|
|
{
|
|
return PerkSkills[ESupportAPShot].bActive && IsPerkLevelAllowed(ESupportAPShot);
|
|
}
|
|
|
|
/**
|
|
* @brief Checks if the Tight Choke skill is active
|
|
*
|
|
* @return true if we have the skill enabled
|
|
*/
|
|
simulated private function bool IsTightChokeActive()
|
|
{
|
|
return PerkSkills[ESupportTightChoke].bActive && IsPerkLevelAllowed(ESupportTightChoke);
|
|
}
|
|
|
|
/**
|
|
* @brief Checks if the tactical reload skill is active (client and server)
|
|
*
|
|
* @return true/false
|
|
*/
|
|
simulated private function bool IsTacticalReloadActive()
|
|
{
|
|
return PerkSkills[ESupportTacticalReload].bActive && IsPerkLevelAllowed(ESupportTacticalReload);
|
|
}
|
|
|
|
/**
|
|
* @brief Checks if the Concussion Rounds skill is active
|
|
*
|
|
* @return true/false
|
|
*/
|
|
private function bool IsConcussionRoundsActive()
|
|
{
|
|
return PerkSkills[ESupportConcussionRounds].bActive && IsPerkLevelAllowed(ESupportConcussionRounds);
|
|
}
|
|
|
|
/**
|
|
* @brief Checks if the Resupply skill is active
|
|
*
|
|
* @return true/false
|
|
*/
|
|
simulated private function bool IsResupplyActive()
|
|
{
|
|
return PerkSkills[ESupportResupply].bActive && IsPerkLevelAllowed(ESupportResupply);
|
|
}
|
|
|
|
/**
|
|
* @brief Checks if the Perforate skill is active
|
|
*
|
|
* @return true/false
|
|
*/
|
|
simulated private function bool IsPerforateActive()
|
|
{
|
|
return PerkSkills[ESupportPerforate].bActive && WorldInfo.TimeDilation < 1.f && IsPerkLevelAllowed(ESupportPerforate);
|
|
}
|
|
|
|
/**
|
|
* @brief Checks if we can repair doors
|
|
*
|
|
* @return true/false
|
|
*/
|
|
native function bool CanRepairDoors();
|
|
|
|
/**
|
|
*/
|
|
static function GetDoorRepairXP(out int XP, byte Difficulty)
|
|
{
|
|
XP = default.DoorRepairXP[Difficulty];
|
|
}
|
|
|
|
/*********************************************************************************************
|
|
* @name Logging / debug
|
|
********************************************************************************************* */
|
|
|
|
/** Log What type of reload the weapon would use given ammo count */
|
|
private simulated function name LogTacticalReload()
|
|
{
|
|
local KFWeapon KFW;
|
|
|
|
KFW = GetOwnerWeapon();
|
|
if( KFW != none )
|
|
{
|
|
return KFW.GetReloadAnimName( GetUsingTactialReload(KFW) );
|
|
}
|
|
|
|
return '';
|
|
}
|
|
/** QA Logging - Report Perk Info */
|
|
simulated function LogPerkSkills()
|
|
{
|
|
super.LogPerkSkills();
|
|
|
|
if( bLogPerk )
|
|
{
|
|
/** `log( "PASSIVE PERKS" );
|
|
`log( "-Welding Modifier:" @ (GetPassiveValue(WeldingProficiency, CurrentLevel) - 1) *100 $"%" );
|
|
`log( "-Shotgun Damage Modifier:" @ (GetPassiveValue(ShotgunDamage, CurrentLevel) - 1) *100 $"%" );
|
|
`log( "-Shotgun Penetration Modifier:" @ GetPassiveValue(default.ShotgunPenetration, CurrentLevel) );
|
|
`log( "-Grenade Damage Modifier:" @ GetPassiveValue(GrenadeDamage, CurrentLevel, 100.f)*100 $"%" );
|
|
|
|
`log( "Skill Tree" );
|
|
`log( "-Ammo:" @ PerkSkills[ESupportTacticalReload].bActive );
|
|
`log( "-Supplier:" @ IsSupplierActive()) ;
|
|
`log( "-Fortitude:" @ PerkSkills[ESupportFortitude].bActive );
|
|
`log( "-Regeneration:" @ PerkSkills[ESupportRegeneration].bActive );
|
|
`log( "-Bombard:" @ PerkSkills[ESupportBombard].bActive );
|
|
`log( "-Tactical Reload:" @ PerkSkills[ESupportTacticalReload].bActive @ LogTacticalReload() );
|
|
`log( "-Strength:" @ PerkSkills[ESupportStrength].bActive );
|
|
`log( "-Tenacity:" @ PerkSkills[ESupportTenacity].bActive );
|
|
`log( "-Safeguard:" @ PerkSkills[ESupportSafeguard].bActive );
|
|
`log( "-Barrage:" @ PerkSkills[ESupportBarrage].bActive );*/
|
|
}
|
|
}
|
|
|
|
simulated function PlayerDied()
|
|
{
|
|
super.PlayerDied();
|
|
|
|
if(InteractionTrigger != none)
|
|
{
|
|
InteractionTrigger.DestroyTrigger();
|
|
}
|
|
}
|
|
|
|
DefaultProperties
|
|
{
|
|
ProgressStatID=STATID_Sup_Progress
|
|
PerkBuildStatID=STATID_Sup_Build
|
|
|
|
PerkIcon=Texture2D'UI_PerkIcons_TEX.UI_PerkIcon_Support'
|
|
InteractIcon=Texture2D'UI_World_TEX.Support_Supplier_HUD'
|
|
|
|
PrimaryWeaponDef=class'KFWeapDef_MB500'
|
|
KnifeWeaponDef=class'KFWeapDef_Knife_Support'
|
|
GrenadeWeaponDef=class'KFWeapDef_Grenade_Support'
|
|
|
|
BarrageFiringRate=0.9f
|
|
ResupplyMaxSpareAmmoModifier=0.20 //0.15
|
|
|
|
ReceivedAmmoSound=AkEvent'WW_UI_PlayerCharacter.Play_UI_Pickup_Ammo'
|
|
ReceivedAmmoAndArmorSound=AkEvent'WW_UI_PlayerCharacter.Play_UI_Pickup_Armor'
|
|
ReceivedArmorSound=AkEvent'WW_UI_PlayerCharacter.Play_UI_Pickup_Armor'
|
|
|
|
Ammo=(Name="Ammo",Increment=0.01f,Rank=0,StartingValue=0.0,MaxValue=0.25f) //0.4
|
|
WeldingProficiency=(Name="Welding Proficiency",Increment=0.03f,Rank=0,StartingValue=1.f,MaxValue=1.75f) //1.5
|
|
ShotgunDamage=(Name="Shotgun Damage",Increment=0.01f,Rank=0,StartingValue=0.f,MaxValue=0.25f)
|
|
ShotgunPenetration=(Name="Shotgun Penetration",Increment=0.20,Rank=0,StartingValue=0.0f,MaxValue=5.0f) //6.25
|
|
Strength=(Name="Strength",Increment=1.f,Rank=0,StartingValue=0.f,MaxValue=5.f)
|
|
|
|
PerkSkills(ESupportHighCapMags)=(Name="HighCapMags",IconPath="UI_PerkTalent_TEX.support.UI_Talents_Support_HighCapacityMags",Increment=0.f,Rank=0,StartingValue=0.75,MaxValue=0.75) //0.5
|
|
PerkSkills(ESupportTacticalReload)=(Name="TacticalReload",IconPath="UI_PerkTalent_TEX.Support.UI_Talents_Support_TacticalReload",Increment=0.f,Rank=0,StartingValue=0.8f,MaxValue=0.f)
|
|
PerkSkills(ESupportFortitude)=(Name="Fortitude",IconPath="UI_PerkTalent_TEX.Support.UI_Talents_Support_Fortitude",Increment=0.f,Rank=0,StartingValue=0.5f,MaxValue=0.5f)
|
|
PerkSkills(ESupportSalvo)=(Name="Salvo",IconPath="UI_PerkTalent_TEX.Support.UI_Talents_Support_Salvo",Increment=0.f,Rank=0,StartingValue=0.3f,MaxValue=0.3f)
|
|
PerkSkills(ESupportAPShot)=(Name="APShot",IconPath="UI_PerkTalent_TEX.Support.UI_Talents_Support_ArmorPiercing",Increment=0.f,Rank=0,StartingValue=4.f,MaxValue=4.f) //3
|
|
PerkSkills(ESupportTightChoke)=(Name="TightChoke",IconPath="UI_PerkTalent_TEX.Support.UI_Talents_Support_TightChoke",Increment=0.f,Rank=0,StartingValue=0.5f,MaxValue=0.5f) //0.7
|
|
PerkSkills(ESupportResupply)=(Name="Resupply",IconPath="UI_PerkTalent_TEX.Support.UI_Talents_Support_ResupplyPack",Increment=0.f ,Rank=0,StartingValue=0.2f,MaxValue=0.2f)
|
|
PerkSkills(ESupportConcussionRounds)=(Name="ConcussionRounds",IconPath="UI_PerkTalent_TEX.Support.UI_Talents_Support_ConcussionRounds",Increment=0.f,Rank=0,StartingValue=1.5f,MaxValue=1.5f)
|
|
PerkSkills(ESupportPerforate)=(Name="Perforate",IconPath="UI_PerkTalent_TEX.Support.UI_Talents_Support_Penetrator",Increment=0.f,Rank=0,StartingValue=30.f,MaxValue=30.f)
|
|
PerkSkills(ESupportBarrage)=(Name="Barrage",IconPath="UI_PerkTalent_TEX.Support.UI_Talents_Support_Barrage",Increment=0.f,Rank=0,StartingValue=5.f,MaxValue=5.f)
|
|
|
|
SecondaryXPModifier[0]=8
|
|
SecondaryXPModifier[1]=8
|
|
SecondaryXPModifier[2]=8
|
|
SecondaryXPModifier[3]=8
|
|
|
|
DoorRepairXP[0]=18
|
|
DoorRepairXP[1]=24
|
|
DoorRepairXP[2]=30
|
|
DoorRepairXP[3]=42
|
|
|
|
// Skill tracking
|
|
HitAccuracyHandicap=-6.0
|
|
HeadshotAccuracyHandicap=-3.0
|
|
AutoBuyLoadOutPath=(class'KFWeapDef_MB500', class'KFWeapDef_DoubleBarrel', class'KFWeapDef_M4', class'KFWeapDef_AA12')
|
|
|
|
// Prestige Rewards
|
|
PrestigeRewardItemIconPaths[0]="WEP_SkinSet_Prestige01_Item_TEX.knives.SupportKnife_PrestigePrecious_Mint_large"
|
|
PrestigeRewardItemIconPaths[1]="WEP_SkinSet_Prestige02_Item_TEX.tier01.MB500_PrestigePrecious_Mint_large"
|
|
PrestigeRewardItemIconPaths[2]="WEP_skinset_prestige03_itemtex.tier02.Boomstick_PrestigePrecious_Mint_large"
|
|
PrestigeRewardItemIconPaths[3]="wep_skinset_prestige04_itemtex.tier03.M4_PrestigePrecious_Mint_large"
|
|
PrestigeRewardItemIconPaths[4]="WEP_SkinSet_Prestige05_Item_TEX.tier04.AA12_PrestigePrecious_Mint_large"
|
|
|
|
ZedTimeModifyingStates(0)="WeaponFiring"
|
|
ZedTimeModifyingStates(1)="WeaponBurstFiring"
|
|
ZedTimeModifyingStates(2)="WeaponSingleFiring"
|
|
ZedTimeModifyingStates(3)="WeaponAltFiring"
|
|
ZedTimeModifyingStates(4)="BlunderbussDeployAndDetonate"
|
|
|
|
HighCapMagExemptList(0)="KFWeap_Shotgun_DoubleBarrel"
|
|
HighCapMagExemptList(1)="KFWeap_HRG_Revolver_Buckshot"
|
|
HighCapMagExemptList(2)="KFWeap_HRG_Revolver_DualBuckshot"
|
|
HighCapMagExemptList(3)="KFWeap_Shotgun_ElephantGun"
|
|
|
|
AdditionalOnPerkDTNames(0)="KFDT_Ballistic_Shotgun_Medic"
|
|
AdditionalOnPerkDTNames(1)="KFDT_Ballistic_DragonsBreath"
|
|
AdditionalOnPerkDTNames(2)="KFDT_Ballistic_NailShotgun"
|
|
}
|