2017-10-20 02:00:49 +00:00
// Base perk.
Class Ext _PerkBase extends Info
NotPlaceable
Abstract
Config ( ServerExt )
DependsOn ( ExtWebAdmin _UI ) ;
var array < FWebAdminConfigInfo > WebConfigs ;
var ExtPerkManager PerkManager ;
var Controller PlayerOwner ;
2020-06-26 00:52:31 +00:00
var ( ) localized string PerkName ;
2017-10-20 02:00:49 +00:00
var ( ) Texture2D PerkIcon ;
var ( ) class < KFPerk > BasePerk ; // KF perk that this perk is based on.
var ( ) class < KFWeapon > PrimaryMelee , PrimaryWeapon ;
var ( ) class < KFWeaponDefinition > PrimaryWeaponDef , SecondaryWeaponDef , KnifeWeaponDef , GrenadeWeaponDef ;
var ( ) class < KFProj _Grenade > GrenadeClass , PerkGrenade , SuperGrenade ;
var ( ) int HealExpUpNum , WeldExpUpNum ; // Efficiency of healing and welding XP up.
// For trader.
var ( ) array < class < KFWeaponDefinition > > AutoBuyLoadOutPath ;
// Config init stuff.
var config int ConfigVersion ;
var const int CurrentConfigVer ;
// Variables.
var config int FirstLevelExp , // How much EXP needed for first level.
LevelUpExpCost , // How much EXP needed for every level up.
LevelUpIncCost , // How much EXP increase needed for each level up.
MinimumLevel ,
MaximumLevel ,
StarPointsPerLevel ,
MinLevelForPrestige , // Minimum level required for perk prestige.
PrestigeSPIncrease , // Starpoint increase per prestige levelup.
2020-07-06 21:12:25 +00:00
MaxPrestige ,
MinimalDataLevel ; // Maximum prestige level.
2017-10-20 02:00:49 +00:00
var config float PrestigeXPReduce ; // Amount of XP cost is reduced for each prestige.
var config array < string > TraitClasses ;
var array < float > Modifiers ;
var int CurrentLevel , // Current level player is on.
CurrentEXP , // Current amount of EXP user has.
NextLevelEXP , // Experience needed for next level.
CurrentSP , // Current amount of star points.
LastLevelEXP , // Number of XP was needed for last level.
CurrentPrestige ; // Current prestige level.
struct FPerkStat
{
var config int MaxValue , CostPerValue ;
var config float Progress ;
var config name StatType ;
var transient int CurrentValue , OldValue ;
var transient float DisplayValue ;
var transient string UIName ;
} ;
var config array < FPerkStat > PerkStats ;
struct FDefPerkStat
{
var int MaxValue , CostPerValue ;
var float Progress ;
var name StatType ;
var bool bHiddenConfig ; // Hide this config by default.
} ;
var ( ) array < FDefPerkStat > DefPerkStats ;
var ( ) array < class < Ext _TraitBase > > DefTraitList ;
struct FPlayerTrait
{
var class < Ext _TraitBase > TraitType ;
var byte CurrentLevel ;
var Ext _TraitDataStore Data ;
} ;
var array < FPlayerTrait > PerkTraits ;
// Server -> Client replication variables
var byte RepState ;
var int RepIndex ;
var transient float NextAuthTime ;
var int ToxicDartDamage ;
var byte EnemyHealthRange ;
var ( ) array < float > EnemyDistDraw ;
var bool bOwnerNetClient , bClientAuthorized , bPerkNetReady , bHasNightVision , bCanBeGrabbed , bExplosiveWeld , bExplodeOnContact , bNapalmFire , bFireExplode , bToxicDart , bTacticalReload , bHeavyArmor , bHasSWATEnforcer ;
2020-09-01 08:07:53 +00:00
var localized string StatSpeed ;
var localized string StatDamage ;
var localized string StatRecoil ;
var localized string StatSpread ;
var localized string StatRate ;
var localized string StatReload ;
var localized string StatHealth ;
var localized string StatKnockDown ;
var localized string StatWelder ;
var localized string StatHeal ;
var localized string StatMag ;
var localized string StatSpare ;
var localized string StatOffDamage ;
var localized string StatSelfDamage ;
var localized string StatArmor ;
var localized string StatPoisonDmg ;
var localized string StatSonicDmg ;
var localized string StatFireDmg ;
var localized string StatAllDmg ;
var localized string StatHeadDamage ;
var localized string StatHealRecharge ;
2020-09-07 11:49:46 +00:00
reliable client simulated function string UIName ( FDefPerkStat DefPerkStat )
2020-09-01 08:07:53 +00:00
{
2020-11-28 20:12:58 +00:00
switch ( DefPerkStat . StatType )
2020-09-01 08:07:53 +00:00
{
2020-11-28 19:53:57 +00:00
case name ( "Speed" ) : return StatSpeed ;
case name ( "Damage" ) : return StatDamage ;
case name ( "Recoil" ) : return StatRecoil ;
case name ( "Spread" ) : return StatSpread ;
case name ( "Rate" ) : return StatRate ;
case name ( "Reload" ) : return StatReload ;
case name ( "Health" ) : return StatHealth ;
case name ( "KnockDown" ) : return StatKnockDown ;
case name ( "Welder" ) : return StatWelder ;
case name ( "Heal" ) : return StatHeal ;
case name ( "Mag" ) : return StatMag ;
case name ( "Spare" ) : return StatSpare ;
case name ( "OffDamage" ) : return StatOffDamage ;
2020-09-01 08:07:53 +00:00
case name ( "SelfDamage" ) : return StatSelfDamage ;
2020-11-28 19:53:57 +00:00
case name ( "Armor" ) : return StatArmor ;
case name ( "PoisonDmg" ) : return StatPoisonDmg ;
case name ( "SonicDmg" ) : return StatSonicDmg ;
case name ( "FireDmg" ) : return StatFireDmg ;
case name ( "AllDmg" ) : return StatAllDmg ;
2020-09-01 08:07:53 +00:00
case name ( "HeadDamage" ) : return StatHeadDamage ;
case name ( "HealRecharge" ) : return StatHealRecharge ;
}
return "" ;
}
2017-10-20 02:00:49 +00:00
replication
{
// Things the server should send to the client.
2020-11-28 20:04:55 +00:00
if ( true )
2017-10-20 02:00:49 +00:00
CurrentLevel , CurrentPrestige , CurrentEXP , NextLevelEXP , CurrentSP , LastLevelEXP , bHasNightVision , MinLevelForPrestige , PrestigeSPIncrease , MaxPrestige , bTacticalReload , EnemyHealthRange ;
}
2020-11-28 20:04:55 +00:00
simulated final function bool IsWeaponOnPerk ( KFWeapon W )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( class < KFPerk _Survivalist > ( BasePerk ) != None )
2017-10-22 02:06:31 +00:00
return true ;
2020-06-21 19:06:43 +00:00
2020-11-28 20:12:58 +00:00
//if (W.AllowedForAllPerks())
2020-06-21 19:06:43 +00:00
// return true;
2017-10-22 02:06:31 +00:00
2017-10-20 02:00:49 +00:00
return W != None && W . GetWeaponPerkClass ( BasePerk ) == BasePerk ;
}
2020-11-28 20:04:55 +00:00
simulated static function string GetPerkIconPath ( int Level )
2017-10-20 02:00:49 +00:00
{
2020-01-09 11:05:13 +00:00
return "img://" $PathName ( default . PerkIcon ) ;
2017-10-20 02:00:49 +00:00
}
simulated function PostBeginPlay ( )
{
local int i , j ;
local class < Ext _TraitBase > T ;
2020-11-28 20:12:58 +00:00
if ( WorldInfo . NetMode == NM _Client )
2017-10-20 02:00:49 +00:00
{
PerkStats . Length = 0 ; // Prevent client desync with client settings.
PlayerOwner = GetALocalPlayerController ( ) ;
SetTimer ( 0.01 , false , 'InitPerk' ) ;
}
else
{
RemoteRole = ROLE _None ; // Make sure these actors get replicated in order to client.
PlayerOwner = Controller ( Owner ) ;
2020-11-28 20:12:58 +00:00
if ( PlayerOwner == None )
2017-10-20 02:00:49 +00:00
{
` Log(Self@"spawned without owner.");
Destroy ( ) ;
return ;
}
bOwnerNetClient = ( PlayerController ( Owner ) != None && LocalPlayer ( PlayerController ( Owner ) . Player ) == None ) ;
// Load trait classes.
j = 0 ;
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < TraitClasses . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
T = class < Ext _TraitBase > ( DynamicLoadObject ( TraitClasses [ i ] , Class 'Class' ) ) ;
2020-11-28 20:12:58 +00:00
if ( T == None || ! T . Static . IsEnabled ( Self ) )
2017-10-20 02:00:49 +00:00
continue ;
PerkTraits . Length = j + 1 ;
PerkTraits [ j ] . TraitType = T ;
++ j ;
}
// Setup serverside stat info (for XML log files).
2020-11-28 20:12:58 +00:00
for ( j = 0 ; j < PerkStats . Length ; ++ j )
2017-10-20 02:00:49 +00:00
{
i = DefPerkStats . Find ( 'StatType' , PerkStats [ j ] . StatType ) ;
2020-11-28 20:12:58 +00:00
if ( i >= 0 )
2020-09-01 08:07:53 +00:00
PerkStats [ j ] . UIName = UIName ( DefPerkStats [ i ] ) ;
2017-10-20 02:00:49 +00:00
else
{
// Fallback to parent perk for trying to find name.
i = Class 'Ext_PerkBase' . Default . DefPerkStats . Find ( 'StatType' , PerkStats [ j ] . StatType ) ;
2020-11-28 20:12:58 +00:00
if ( i >= 0 )
2020-09-01 08:07:53 +00:00
PerkStats [ j ] . UIName = UIName ( Class 'Ext_PerkBase' . Default . DefPerkStats [ i ] ) ;
2017-10-20 02:00:49 +00:00
else PerkStats [ j ] . UIName = string ( PerkStats [ j ] . StatType ) ; // Fallback to stat name then...
}
}
}
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
simulated function InitPerk ( )
{
2020-11-28 20:12:58 +00:00
if ( PlayerOwner == None )
2017-10-20 02:00:49 +00:00
PlayerOwner = GetALocalPlayerController ( ) ;
2020-11-28 20:12:58 +00:00
if ( PerkManager == None )
2017-10-20 02:00:49 +00:00
{
foreach DynamicActors ( class 'ExtPerkManager' , PerkManager )
{
PerkManager . RegisterPerk ( Self ) ;
break ;
}
}
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
simulated function Destroyed ( )
{
local int i ;
2020-11-28 20:12:58 +00:00
if ( PerkManager != None )
2017-10-20 02:00:49 +00:00
PerkManager . UnregisterPerk ( Self ) ;
2020-11-28 20:12:58 +00:00
if ( WorldInfo . NetMode != NM _Client )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
2017-10-20 02:00:49 +00:00
PerkTraits [ i ] . TraitType . Static . CleanupTrait ( ExtPlayerController ( Owner ) , Self , PerkTraits [ i ] . Data ) ;
}
}
// For HUD UI
simulated final function string GetLevelString ( )
{
return ( CurrentPrestige > 0 ? ( string ( CurrentPrestige ) $ "-" $string ( CurrentLevel ) ) : string ( CurrentLevel ) ) ;
}
// For progress bar on HUD
simulated final function float GetProgressPercent ( )
{
return FClamp ( float ( CurrentEXP - LastLevelEXP ) / FMax ( float ( NextLevelEXP - LastLevelEXP ) , 1. f ) , 0. f , 1. f ) ;
}
// Whetever if user can use prestige now.
simulated final function bool CanPrestige ( )
{
return ( MinLevelForPrestige >= 0 && CurrentPrestige < MaxPrestige ) ? CurrentLevel >= MinLevelForPrestige : false ;
}
// Whetever to save this perk status or not
final function bool HasAnyProgress ( )
{
return ( CurrentEXP > 0 || CurrentPrestige > 0 ) ;
}
2020-11-28 20:04:55 +00:00
reliable client simulated function ClientReceiveStat ( int Index , int MaxValue , int CostPerValue , name Type , int CurValue , float Progress )
2017-10-20 02:00:49 +00:00
{
local int i ;
2020-11-28 20:12:58 +00:00
if ( WorldInfo . NetMode == NM _Client )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkStats . Length <= Index )
2017-10-20 02:00:49 +00:00
PerkStats . Length = Index + 1 ;
PerkStats [ Index ] . MaxValue = MaxValue ;
PerkStats [ Index ] . CostPerValue = CostPerValue ;
PerkStats [ Index ] . StatType = Type ;
PerkStats [ Index ] . CurrentValue = CurValue ;
PerkStats [ Index ] . DisplayValue = 0. f ;
PerkStats [ Index ] . Progress = Progress ;
}
i = DefPerkStats . Find ( 'StatType' , Type ) ;
2020-11-28 20:12:58 +00:00
if ( i >= 0 )
2020-09-01 08:07:53 +00:00
PerkStats [ Index ] . UIName = UIName ( DefPerkStats [ i ] ) ;
2017-10-20 02:00:49 +00:00
else
{
// Fallback to parent perk for trying to find name.
i = Class 'Ext_PerkBase' . Default . DefPerkStats . Find ( 'StatType' , Type ) ;
2020-11-28 20:12:58 +00:00
if ( i >= 0 )
2020-09-01 08:07:53 +00:00
PerkStats [ Index ] . UIName = UIName ( Class 'Ext_PerkBase' . Default . DefPerkStats [ i ] ) ;
2017-10-20 02:00:49 +00:00
else PerkStats [ Index ] . UIName = string ( Type ) ; // Fallback to stat name then...
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
reliable client simulated function ClientSetStatValue ( int Index , int NewValue )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkStats . Length <= Index )
2017-10-20 02:00:49 +00:00
PerkStats . Length = Index + 1 ;
PerkStats [ Index ] . CurrentValue = NewValue ;
2020-11-28 20:12:58 +00:00
if ( bPerkNetReady )
2017-10-20 02:00:49 +00:00
ApplyEffects ( ) ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
reliable client simulated function ClientReceiveTrait ( int Index , class < Ext _TraitBase > TC , byte Lvl )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkTraits . Length <= Index )
2017-10-20 02:00:49 +00:00
PerkTraits . Length = Index + 1 ;
PerkTraits [ Index ] . TraitType = TC ;
PerkTraits [ Index ] . CurrentLevel = Lvl ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
reliable client simulated function ClientReceiveTraitData ( int Index , string Data )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( WorldInfo . NetMode == NM _Client )
2017-10-20 02:00:49 +00:00
PerkTraits [ Index ] . TraitType . Static . ClientSetRepData ( Data ) ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
reliable client simulated function ClientReceiveTraitLvl ( int Index , byte NewLevel )
2017-10-20 02:00:49 +00:00
{
PerkTraits [ Index ] . CurrentLevel = NewLevel ;
}
2020-11-28 20:04:55 +00:00
final function SetPerkStat ( name Type , int Value )
2017-10-20 02:00:49 +00:00
{
local int i ;
i = PerkStats . Find ( 'StatType' , Type ) ;
2020-11-28 20:12:58 +00:00
if ( i >= 0 )
2017-10-20 02:00:49 +00:00
PerkStats [ i ] . CurrentValue = Value ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function int GetPerkStat ( name Type )
2017-10-20 02:00:49 +00:00
{
local int i ;
i = PerkStats . Find ( 'StatType' , Type ) ;
2020-11-28 20:12:58 +00:00
if ( i == - 1 )
2017-10-20 02:00:49 +00:00
return 0 ;
return PerkStats [ i ] . CurrentValue ;
}
2020-11-28 20:04:55 +00:00
function bool EarnedEXP ( int EXP )
2017-10-20 02:00:49 +00:00
{
local int n ;
bForceNetUpdate = true ;
CurrentEXP += EXP ;
2020-11-28 20:12:58 +00:00
while ( CurrentEXP >= NextLevelEXP && CurrentLevel < MaximumLevel && n < 20 )
2017-10-20 02:00:49 +00:00
{
++ n ;
LastLevelEXP = NextLevelEXP ;
NextLevelEXP = GetNeededExp ( ++ CurrentLevel ) ;
}
2020-11-28 20:12:58 +00:00
if ( n > 0 )
2017-10-20 02:00:49 +00:00
{
CurrentSP += ( n * ( StarPointsPerLevel + CurrentPrestige * PrestigeSPIncrease ) ) ;
2020-11-28 20:12:58 +00:00
if ( PerkManager . PRIOwner != None && PerkManager . CurrentPerk == Self )
2017-10-20 02:00:49 +00:00
UpdatePRILevel ( ) ;
// TODO - broadcast level up messages.
2020-11-28 20:12:58 +00:00
if ( ExtPlayerController ( PlayerOwner ) != None )
2017-10-20 02:00:49 +00:00
ExtPlayerController ( PlayerOwner ) . ReceiveLevelUp ( Self , CurrentLevel ) ;
}
return true ;
}
final function UpdatePRILevel ( )
{
PerkManager . PRIOwner . SetLevelProgress ( CurrentLevel , CurrentPrestige , MinimumLevel , MaximumLevel ) ;
}
// XML output
2020-11-28 20:04:55 +00:00
function OutputXML ( ExtStatWriter Data )
2017-10-20 02:00:49 +00:00
{
local int i ;
Data . StartIntendent ( "perk" , "class" , string ( Class . Name ) ) ;
Data . WriteValue ( "perkname" , PerkName ) ;
Data . WriteValue ( "level" , string ( CurrentLevel ) ) ;
Data . WriteValue ( "prestige" , string ( CurrentPrestige ) ) ;
Data . WriteValue ( "exp" , string ( CurrentEXP ) ) ;
Data . WriteValue ( "points" , string ( CurrentSP ) ) ;
Data . WriteValue ( "exptilnext" , string ( NextLevelEXP ) ) ;
Data . WriteValue ( "exponprev" , string ( LastLevelEXP ) ) ;
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkStats . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkStats [ i ] . CurrentValue > 0 )
2017-10-20 02:00:49 +00:00
{
Data . StartIntendent ( "stat" , "type" , string ( PerkStats [ i ] . StatType ) ) ;
Data . WriteValue ( "name" , GetStatUIStr ( i ) ) ;
Data . WriteValue ( "value" , string ( PerkStats [ i ] . CurrentValue ) ) ;
Data . WriteValue ( "progress" , string ( PerkStats [ i ] . DisplayValue ) ) ;
Data . EndIntendent ( ) ;
}
}
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel > 0 )
2017-10-20 02:00:49 +00:00
{
Data . StartIntendent ( "trait" , "class" , string ( PerkTraits [ i ] . TraitType . Name ) ) ;
Data . WriteValue ( "name" , PerkTraits [ i ] . TraitType . Default . TraitName ) ;
Data . WriteValue ( "level" , string ( PerkTraits [ i ] . CurrentLevel ) ) ;
Data . EndIntendent ( ) ;
}
}
Data . EndIntendent ( ) ;
}
// Data saving.
2020-11-28 20:04:55 +00:00
function SaveData ( ExtSaveDataBase Data )
2017-10-20 02:00:49 +00:00
{
local int i , j ;
// Write current EXP.
Data . SaveInt ( CurrentEXP , 3 ) ;
// Write current prestige
Data . SaveInt ( CurrentPrestige , 3 ) ;
// Count number of given stats
j = 0 ;
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkStats . Length ; ++ i )
if ( PerkStats [ i ] . CurrentValue > 0 )
2017-10-20 02:00:49 +00:00
++ j ;
// Then perk stats.
Data . SaveInt ( j ) ;
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkStats . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkStats [ i ] . CurrentValue > 0 )
2017-10-20 02:00:49 +00:00
{
Data . SaveStr ( string ( PerkStats [ i ] . StatType ) ) ;
Data . SaveInt ( PerkStats [ i ] . CurrentValue , 1 ) ;
}
}
// Count bought traits.
j = 0 ;
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
if ( PerkTraits [ i ] . CurrentLevel > 0 )
2017-10-20 02:00:49 +00:00
++ j ;
// Then traits.
Data . SaveInt ( j ) ;
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel > 0 )
2017-10-20 02:00:49 +00:00
{
Data . SaveStr ( string ( PerkTraits [ i ] . TraitType ) ) ;
Data . SaveInt ( PerkTraits [ i ] . CurrentLevel ) ;
}
}
}
// Data loading.
2020-11-28 20:04:55 +00:00
function LoadData ( ExtSaveDataBase Data )
2017-10-20 02:00:49 +00:00
{
local int i , j , l , n ;
local string S ;
CurrentEXP = Data . ReadInt ( 3 ) ;
2020-11-28 20:12:58 +00:00
// if (MinimalDataLevel > 0)
2020-07-06 21:12:25 +00:00
// {
// i = GetNeededExp(MinimalDataLevel-1)
2020-11-28 20:12:58 +00:00
// if (i > CurrentEXP)
2020-07-06 21:12:25 +00:00
// CurrentEXP = i
// }
2017-10-20 02:00:49 +00:00
2020-11-28 20:12:58 +00:00
if ( Data . GetArVer ( ) >= 1 )
2017-10-20 02:00:49 +00:00
CurrentPrestige = Data . ReadInt ( 3 ) ;
l = Data . ReadInt ( ) ; // Perk stats length.
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < l ; ++ i )
2017-10-20 02:00:49 +00:00
{
S = Data . ReadStr ( ) ;
n = Data . ReadInt ( 1 ) ;
2020-11-28 20:12:58 +00:00
for ( j = 0 ; j < PerkStats . Length ; ++ j )
if ( S ~ = string ( PerkStats [ j ] . StatType ) )
2017-10-20 02:00:49 +00:00
{
PerkStats [ j ] . CurrentValue = n ;
break ;
}
}
l = Data . ReadInt ( ) ; // Traits stats length.
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < l ; ++ i )
2017-10-20 02:00:49 +00:00
{
S = Data . ReadStr ( ) ;
n = Data . ReadInt ( ) ;
2020-11-28 20:12:58 +00:00
for ( j = 0 ; j < PerkTraits . Length ; ++ j )
if ( S ~ = string ( PerkTraits [ j ] . TraitType ) )
2017-10-20 02:00:49 +00:00
{
PerkTraits [ j ] . CurrentLevel = n ;
break ;
}
}
}
2020-11-28 20:04:55 +00:00
final function int CalcLevelForExp ( int InExp )
2017-10-20 02:00:49 +00:00
{
local int i , a , b ;
// Fast method to calc level for a player.
b = MaximumLevel + 1 ;
a = Min ( MinimumLevel , b ) ;
2020-11-28 20:12:58 +00:00
while ( true )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( a == b || ( a + 1 ) == b )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( a < MaximumLevel && InExp >= GetNeededExp ( a ) )
2017-10-20 02:00:49 +00:00
++ a ;
break ;
}
i = a + ( ( b - a ) >> 1 ) ;
2020-11-28 20:12:58 +00:00
if ( InExp < GetNeededExp ( i ) ) // Lower!
2017-10-20 02:00:49 +00:00
b = i ;
else a = i ; // Higher!
}
return Clamp ( a , MinimumLevel , MaximumLevel ) ;
}
// Initialize perk after stats have been loaded.
function SetInitialLevel ( )
{
local int i , a , b ;
local byte MT , j ;
2020-11-28 20:12:58 +00:00
if ( MinimalDataLevel > 0 )
2020-07-06 21:12:25 +00:00
{
i = GetNeededExp ( MinimalDataLevel - 1 ) ;
2020-11-28 20:12:58 +00:00
if ( i > CurrentEXP )
2020-07-06 21:12:25 +00:00
CurrentEXP = i ;
}
2017-10-20 02:00:49 +00:00
// Set to initial level player is on after configures has loaded.
CurrentLevel = CalcLevelForExp ( CurrentEXP ) ;
CurrentSP = CurrentLevel * ( StarPointsPerLevel + CurrentPrestige * PrestigeSPIncrease ) ;
NextLevelEXP = GetNeededExp ( CurrentLevel ) ;
LastLevelEXP = ( CurrentLevel > MinimumLevel ? GetNeededExp ( CurrentLevel - 1 ) : 0 ) ;
// Now verify the points player used on individual stats.
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkStats . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkStats [ i ] . CurrentValue > 0 )
2017-10-20 02:00:49 +00:00
{
PerkStats [ i ] . CurrentValue = Min ( PerkStats [ i ] . CurrentValue , PerkStats [ i ] . MaxValue ) ;
a = PerkStats [ i ] . CurrentValue * PerkStats [ i ] . CostPerValue ;
2020-11-28 20:12:58 +00:00
if ( CurrentSP > a )
2017-10-20 02:00:49 +00:00
CurrentSP -= a ;
2020-11-28 20:12:58 +00:00
else if ( CurrentSP <= 0 ) // No points at all for this.
2017-10-20 02:00:49 +00:00
PerkStats [ i ] . CurrentValue = 0 ;
else // Nope, reduce the stat!
{
a = CurrentSP / PerkStats [ i ] . CostPerValue ;
PerkStats [ i ] . CurrentValue = a ;
CurrentSP -= ( a * PerkStats [ i ] . CostPerValue ) ;
}
}
}
// Then verify trait levels and costs.
MT = 0 ;
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel > 0 )
2017-10-20 02:00:49 +00:00
{
PerkTraits [ i ] . CurrentLevel = Min ( PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . TraitType . Default . NumLevels ) ;
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . TraitType . Default . LoadPriority > 0 )
2017-10-20 02:00:49 +00:00
MT = Max ( MT , PerkTraits [ i ] . TraitType . Default . LoadPriority ) ;
else
{
2020-11-28 20:12:58 +00:00
if ( ! PerkTraits [ i ] . TraitType . Static . MeetsRequirements ( PerkTraits [ i ] . CurrentLevel - 1 , Self ) )
2017-10-20 02:00:49 +00:00
a = 0 ;
else
{
2020-11-28 20:12:58 +00:00
for ( a = 0 ; a < PerkTraits [ i ] . CurrentLevel ; ++ a )
2017-10-20 02:00:49 +00:00
{
b = PerkTraits [ i ] . TraitType . Static . GetTraitCost ( a ) ;
2020-11-28 20:12:58 +00:00
if ( b > CurrentSP )
2017-10-20 02:00:49 +00:00
break ;
CurrentSP -= b ;
}
}
PerkTraits [ i ] . CurrentLevel = a ;
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel > 0 && PerkTraits [ i ] . Data == None )
PerkTraits [ i ] . Data = PerkTraits [ i ] . TraitType . Static . Initializefor ( Self , ExtPlayerController ( Owner ) ) ;
2017-10-20 02:00:49 +00:00
}
}
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel == 0 && PerkTraits [ i ] . Data != None )
2017-10-20 02:00:49 +00:00
PerkTraits [ i ] . TraitType . Static . CleanupTrait ( ExtPlayerController ( Owner ) , Self , PerkTraits [ i ] . Data ) ;
}
// Delayed loads.
2020-11-28 20:12:58 +00:00
for ( j = 1 ; j <= MT ; ++ j )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel > 0 && PerkTraits [ i ] . TraitType . Default . LoadPriority == j )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( ! PerkTraits [ i ] . TraitType . Static . MeetsRequirements ( PerkTraits [ i ] . CurrentLevel - 1 , Self ) )
2017-10-20 02:00:49 +00:00
a = 0 ;
else
{
2020-11-28 20:12:58 +00:00
for ( a = 0 ; a < PerkTraits [ i ] . CurrentLevel ; ++ a )
2017-10-20 02:00:49 +00:00
{
b = PerkTraits [ i ] . TraitType . Static . GetTraitCost ( a ) ;
2020-11-28 20:12:58 +00:00
if ( b > CurrentSP )
2017-10-20 02:00:49 +00:00
break ;
CurrentSP -= b ;
}
}
PerkTraits [ i ] . CurrentLevel = a ;
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel > 0 && PerkTraits [ i ] . Data == None )
PerkTraits [ i ] . Data = PerkTraits [ i ] . TraitType . Static . Initializefor ( Self , ExtPlayerController ( Owner ) ) ;
2017-10-20 02:00:49 +00:00
}
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel == 0 && PerkTraits [ i ] . Data != None )
2017-10-20 02:00:49 +00:00
PerkTraits [ i ] . TraitType . Static . CleanupTrait ( ExtPlayerController ( Owner ) , Self , PerkTraits [ i ] . Data ) ;
}
}
ApplyEffects ( ) ;
2020-11-28 20:12:58 +00:00
if ( PerkManager . CurrentPerk == Self )
2017-10-20 02:00:49 +00:00
ActivateTraits ( ) ;
}
// Check the needed amount of EXP for a perk.
2020-11-28 20:04:55 +00:00
function int GetNeededExp ( int LevelNum )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( LevelNum < MinimumLevel || LevelNum >= MaximumLevel )
2017-10-20 02:00:49 +00:00
return 0 ;
LevelNum -= MinimumLevel ;
LevelNum = ( FirstLevelExp + ( LevelNum * LevelUpExpCost ) + ( LevelNum * LevelNum * LevelUpIncCost ) ) ;
2020-11-28 20:12:58 +00:00
if ( CurrentPrestige > 0 && PrestigeXPReduce > 0 )
2017-10-20 02:00:49 +00:00
LevelNum *= ( 1. f / ( 1. f + PrestigeXPReduce * CurrentPrestige ) ) ;
return LevelNum ;
}
// Configure initialization.
static function CheckConfig ( )
{
local int i ;
local class < Ext _TraitBase > T ;
2020-11-28 20:12:58 +00:00
if ( Default . ConfigVersion != Default . CurrentConfigVer )
2017-10-20 02:00:49 +00:00
{
UpdateConfigs ( Default . ConfigVersion ) ;
Default . ConfigVersion = Default . CurrentConfigVer ;
StaticSaveConfig ( ) ;
}
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < Default . TraitClasses . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
T = class < Ext _TraitBase > ( DynamicLoadObject ( Default . TraitClasses [ i ] , Class 'Class' ) ) ;
2020-11-28 20:12:58 +00:00
if ( T != None )
2017-10-20 02:00:49 +00:00
T . Static . CheckConfig ( ) ;
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
static function UpdateConfigs ( int OldVer )
2017-10-20 02:00:49 +00:00
{
local int i , j ;
2020-11-28 20:12:58 +00:00
if ( OldVer == 0 )
2017-10-20 02:00:49 +00:00
{
Default . FirstLevelExp = 400 ;
Default . LevelUpExpCost = 500 ;
Default . LevelUpIncCost = 65 ;
Default . MinimumLevel = 0 ;
Default . MaximumLevel = 150 ;
Default . StarPointsPerLevel = 15 ;
// Prestige.
Default . MinLevelForPrestige = 140 ;
Default . PrestigeSPIncrease = 1 ;
Default . MaxPrestige = 20 ;
2020-07-06 21:12:25 +00:00
Default . MinimalDataLevel = 0 ;
2017-10-20 02:00:49 +00:00
Default . PrestigeXPReduce = 0.05 ;
Default . PerkStats . Length = 0 ;
AddStatsCfg ( 0 ) ;
Default . TraitClasses . Length = Default . DefTraitList . Length ;
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < Default . DefTraitList . Length ; ++ i )
2017-10-20 02:00:49 +00:00
Default . TraitClasses [ i ] = PathName ( Default . DefTraitList [ i ] ) ;
}
else
{
// Add progress.
2020-11-28 20:12:58 +00:00
if ( OldVer == 1 )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < Default . PerkStats . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
j = Default . DefPerkStats . Find ( 'StatType' , Default . PerkStats [ i ] . StatType ) ;
2020-11-28 20:12:58 +00:00
if ( j >= 0 )
2017-10-20 02:00:49 +00:00
Default . PerkStats [ i ] . Progress = Default . DefPerkStats [ j ] . Progress ;
}
// Add off-perk damage stat.
AddStatsCfg ( 12 ) ;
}
2020-11-28 20:12:58 +00:00
else if ( OldVer <= 3 )
2017-10-20 02:00:49 +00:00
AddStatsCfg ( 13 ) ; // Add self damage.
2020-11-28 20:12:58 +00:00
else if ( OldVer <= 4 )
2017-10-20 02:00:49 +00:00
AddStatsCfg ( 15 ) ; // Add poison damage.
2020-11-28 20:12:58 +00:00
else if ( OldVer <= 7 )
2017-10-20 02:00:49 +00:00
AddStatsCfg ( 16 ) ; // Add sonic/fire damage.
2020-11-28 20:12:58 +00:00
else if ( OldVer <= 12 )
2017-10-20 02:00:49 +00:00
AddStatsCfg ( 18 ) ; // Add all damage.
2020-11-28 20:12:58 +00:00
else if ( OldVer <= 13 )
2020-07-07 14:04:37 +00:00
AddStatsCfg ( 19 ) ; // Add HeadDamage and HealRecharge
2020-11-28 20:12:58 +00:00
if ( OldVer <= 5 )
2017-10-20 02:00:49 +00:00
{
// Add prestige
Default . MinLevelForPrestige = 140 ;
Default . PrestigeSPIncrease = 1 ;
Default . MaxPrestige = 20 ;
Default . PrestigeXPReduce = 0.05 ;
}
Default . TraitClasses . Length = Default . DefTraitList . Length ;
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < Default . DefTraitList . Length ; ++ i )
2017-10-20 02:00:49 +00:00
Default . TraitClasses [ i ] = PathName ( Default . DefTraitList [ i ] ) ;
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
static final function AddStatsCfg ( int StartRange )
2017-10-20 02:00:49 +00:00
{
local int i , j ;
j = Default . PerkStats . Length ;
2020-11-28 20:12:58 +00:00
for ( i = StartRange ; i < Default . DefPerkStats . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( Default . DefPerkStats [ i ] . bHiddenConfig || Default . PerkStats . Find ( 'StatType' , Default . DefPerkStats [ i ] . StatType ) >= 0 ) // Don't add if already found for some reason.
2017-10-20 02:00:49 +00:00
continue ;
Default . PerkStats . Length = j + 1 ;
Default . PerkStats [ j ] . MaxValue = Default . DefPerkStats [ i ] . MaxValue ;
Default . PerkStats [ j ] . CostPerValue = Default . DefPerkStats [ i ] . CostPerValue ;
Default . PerkStats [ j ] . StatType = Default . DefPerkStats [ i ] . StatType ;
Default . PerkStats [ j ] . Progress = Default . DefPerkStats [ i ] . Progress ;
++ j ;
}
}
// WebAdmin UI stuff.
2020-11-28 20:04:55 +00:00
static function InitWebAdmin ( ExtWebAdmin _UI UI )
2017-10-20 02:00:49 +00:00
{
local class < Ext _TraitBase > T ;
local int i ;
UI . AddSettingsPage ( "Perk " $Default . PerkName , Default . Class , Default . WebConfigs , GetValue , ApplyValue ) ;
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < Default . TraitClasses . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
T = class < Ext _TraitBase > ( DynamicLoadObject ( Default . TraitClasses [ i ] , Class 'Class' ) ) ;
2020-11-28 20:12:58 +00:00
if ( T == None || UI . HasConfigfor ( T ) )
2017-10-20 02:00:49 +00:00
continue ;
T . Static . InitWebAdmin ( UI ) ;
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
static function string GetValue ( name PropName , int ElementIndex )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
switch ( PropName )
2017-10-20 02:00:49 +00:00
{
case 'FirstLevelExp' :
return string ( Default . FirstLevelExp ) ;
case 'LevelUpExpCost' :
return string ( Default . LevelUpExpCost ) ;
case 'LevelUpIncCost' :
return string ( Default . LevelUpIncCost ) ;
case 'MinimumLevel' :
return string ( Default . MinimumLevel ) ;
case 'MaximumLevel' :
return string ( Default . MaximumLevel ) ;
case 'StarPointsPerLevel' :
return string ( Default . StarPointsPerLevel ) ;
case 'TraitClasses' :
return ElementIndex == - 1 ? string ( Default . TraitClasses . Length ) : Default . TraitClasses [ ElementIndex ] ;
case 'PerkStats' :
return ElementIndex == - 1 ? string ( Default . PerkStats . Length ) : Default . PerkStats [ ElementIndex ] . StatType$ "," $Default . PerkStats [ ElementIndex ] . MaxValue$ "," $Default . PerkStats [ ElementIndex ] . CostPerValue$ "," $Default . PerkStats [ ElementIndex ] . Progress ;
case 'MinLevelForPrestige' :
return string ( Default . MinLevelForPrestige ) ;
case 'PrestigeSPIncrease' :
return string ( Default . PrestigeSPIncrease ) ;
2020-07-06 21:12:25 +00:00
case 'MinimalDataLevel' :
return string ( Default . MinimalDataLevel ) ;
2017-10-20 02:00:49 +00:00
case 'MaxPrestige' :
return string ( Default . MaxPrestige ) ;
case 'PrestigeXPReduce' :
return string ( Default . PrestigeXPReduce ) ;
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
static function ApplyValue ( name PropName , int ElementIndex , string Value )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
switch ( PropName )
2017-10-20 02:00:49 +00:00
{
case 'FirstLevelExp' :
Default . FirstLevelExp = int ( Value ) ; break ;
case 'LevelUpExpCost' :
Default . LevelUpExpCost = int ( Value ) ; break ;
2020-07-06 21:12:25 +00:00
case 'MinimalDataLevel' :
Default . MinimalDataLevel = int ( Value ) ; break ;
2017-10-20 02:00:49 +00:00
case 'LevelUpIncCost' :
Default . LevelUpIncCost = int ( Value ) ; break ;
case 'MinimumLevel' :
Default . MinimumLevel = int ( Value ) ; break ;
case 'MaximumLevel' :
Default . MaximumLevel = int ( Value ) ; break ;
case 'StarPointsPerLevel' :
Default . StarPointsPerLevel = int ( Value ) ; break ;
case 'TraitClasses' :
2020-11-28 20:12:58 +00:00
if ( Value == "#DELETE" )
2017-10-20 02:00:49 +00:00
Default . TraitClasses . Remove ( ElementIndex , 1 ) ;
else
{
2020-11-28 20:12:58 +00:00
if ( ElementIndex >= Default . TraitClasses . Length )
2017-10-20 02:00:49 +00:00
Default . TraitClasses . Length = ElementIndex + 1 ;
Default . TraitClasses [ ElementIndex ] = Value ;
}
break ;
case 'PerkStats' :
2020-11-28 20:12:58 +00:00
if ( Value == "#DELETE" )
2017-10-20 02:00:49 +00:00
Default . PerkStats . Remove ( ElementIndex , 1 ) ;
else
{
2020-11-28 20:12:58 +00:00
if ( ElementIndex >= Default . PerkStats . Length )
2017-10-20 02:00:49 +00:00
Default . PerkStats . Length = ElementIndex + 1 ;
Default . PerkStats [ ElementIndex ] = ParsePerkStatStr ( Value ) ;
}
break ;
case 'MinLevelForPrestige' :
Default . MinLevelForPrestige = int ( Value ) ; break ;
case 'PrestigeSPIncrease' :
Default . PrestigeSPIncrease = int ( Value ) ; break ;
case 'MaxPrestige' :
Default . MaxPrestige = int ( Value ) ; break ;
case 'PrestigeXPReduce' :
Default . PrestigeXPReduce = float ( Value ) ; break ;
default :
return ;
}
StaticSaveConfig ( ) ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
static final function FPerkStat ParsePerkStatStr ( string S )
2017-10-20 02:00:49 +00:00
{
local FPerkStat Res ;
local int i ;
i = InStr ( S , "," ) ;
2020-11-28 20:12:58 +00:00
if ( i == - 1 )
2017-10-20 02:00:49 +00:00
return Res ;
Res . StatType = name ( Left ( S , i ) ) ;
S = Mid ( S , i + 1 ) ;
i = InStr ( S , "," ) ;
2020-11-28 20:12:58 +00:00
if ( i == - 1 )
2017-10-20 02:00:49 +00:00
return Res ;
Res . MaxValue = int ( Left ( S , i ) ) ;
S = Mid ( S , i + 1 ) ;
i = InStr ( S , "," ) ;
2020-11-28 20:12:58 +00:00
if ( i == - 1 )
2017-10-20 02:00:49 +00:00
return Res ;
Res . CostPerValue = int ( Left ( S , i ) ) ;
Res . Progress = float ( Mid ( S , i + 1 ) ) ;
return Res ;
}
// Amount and iStat values are verified already by ServerExtMut.
2020-11-28 20:04:55 +00:00
function bool IncrementStat ( int iStat , int Amount )
2017-10-20 02:00:49 +00:00
{
PerkStats [ iStat ] . CurrentValue += Amount ;
2020-11-28 20:12:58 +00:00
if ( bOwnerNetClient )
2017-10-20 02:00:49 +00:00
ClientSetStatValue ( iStat , PerkStats [ iStat ] . CurrentValue ) ;
PerkManager . bStatsDirty = true ;
ApplyEffects ( ) ;
bForceNetUpdate = true ;
return true ;
}
simulated function ApplyEffects ( )
{
local int i ;
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkStats . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkStats [ i ] . CurrentValue != PerkStats [ i ] . OldValue )
2017-10-20 02:00:49 +00:00
{
PerkStats [ i ] . OldValue = PerkStats [ i ] . CurrentValue ;
PerkStats [ i ] . DisplayValue = ApplyEffect ( PerkStats [ i ] . StatType , PerkStats [ i ] . CurrentValue , PerkStats [ i ] . Progress / 100. f ) ;
}
}
}
// Notify that player just spawned.
2020-11-28 20:04:55 +00:00
function ApplyEffectsTo ( KFPawn _Human P )
2017-10-20 02:00:49 +00:00
{
local int i ;
local bool bSec ;
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel > 0 )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . TraitType . Default . bPostApplyEffect )
2017-10-20 02:00:49 +00:00
bSec = true ;
else PerkTraits [ i ] . TraitType . Static . ApplyEffectOn ( P , Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
}
}
2020-11-28 20:12:58 +00:00
if ( bSec )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel > 0 && PerkTraits [ i ] . TraitType . Default . bPostApplyEffect )
2017-10-20 02:00:49 +00:00
PerkTraits [ i ] . TraitType . Static . ApplyEffectOn ( P , Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
}
}
}
// Player joined/perk changed.
function ActivateTraits ( )
{
local int i ;
local KFPawn _Human KFP ;
local bool bSec ;
KFP = KFPawn _Human ( PlayerOwner . Pawn ) ;
2020-11-28 20:12:58 +00:00
if ( KFP != None && ! KFP . IsAliveAndWell ( ) )
2017-10-20 02:00:49 +00:00
KFP = None ;
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel > 0 )
2017-10-20 02:00:49 +00:00
{
PerkTraits [ i ] . TraitType . Static . TraitActivate ( Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
2020-11-28 20:12:58 +00:00
if ( KFP != None )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . TraitType . Default . bPostApplyEffect )
2017-10-20 02:00:49 +00:00
bSec = true ;
else PerkTraits [ i ] . TraitType . Static . ApplyEffectOn ( KFP , Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
}
}
}
2020-11-28 20:12:58 +00:00
if ( bSec )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel > 0 && PerkTraits [ i ] . TraitType . Default . bPostApplyEffect )
2017-10-20 02:00:49 +00:00
PerkTraits [ i ] . TraitType . Static . ApplyEffectOn ( KFP , Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
}
}
}
// Player disconnected/perk changed.
function DeactivateTraits ( )
{
local int i ;
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel > 0 )
2017-10-20 02:00:49 +00:00
PerkTraits [ i ] . TraitType . Static . TraitDeActivate ( Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
}
}
simulated unreliable client function ClientAuth ( )
{
2020-11-28 20:12:58 +00:00
if ( Owner == None )
2017-10-20 02:00:49 +00:00
SetOwner ( PlayerOwner ) ;
ServerAck ( ) ;
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
unreliable server function ServerAck ( )
{
2020-11-28 20:12:58 +00:00
if ( ! bClientAuthorized )
2017-10-20 02:00:49 +00:00
{
bClientAuthorized = true ;
RepState = 0 ;
RepIndex = 0 ;
SetTimer ( 0.01 + FRand ( ) * 0.025 , true , 'ReplicateTimer' ) ;
}
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
function ReplicateTimer ( )
{
2020-11-28 20:12:58 +00:00
switch ( RepState )
2017-10-20 02:00:49 +00:00
{
case 0 : // Send all perk stats
2020-11-28 20:12:58 +00:00
if ( RepIndex >= PerkStats . Length )
2017-10-20 02:00:49 +00:00
{
++ RepState ;
RepIndex = 0 ;
}
else
{
ClientReceiveStat ( RepIndex , PerkStats [ RepIndex ] . MaxValue , PerkStats [ RepIndex ] . CostPerValue , PerkStats [ RepIndex ] . StatType , PerkStats [ RepIndex ] . CurrentValue , PerkStats [ RepIndex ] . Progress ) ;
++ RepIndex ;
}
break ;
case 1 : // Send all traits
2020-11-28 20:12:58 +00:00
if ( RepIndex >= PerkTraits . Length )
2017-10-20 02:00:49 +00:00
++ RepState ;
else
{
ClientReceiveTrait ( RepIndex , PerkTraits [ RepIndex ] . TraitType , PerkTraits [ RepIndex ] . CurrentLevel ) ;
ClientReceiveTraitData ( RepIndex , PerkTraits [ RepIndex ] . TraitType . Static . GetRepData ( ) ) ;
++ RepIndex ;
}
break ;
default :
ClearTimer ( 'ReplicateTimer' ) ;
bPerkNetReady = true ;
ClientIsReady ( ) ; // Notify client were ready.
}
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
simulated reliable client function ClientIsReady ( )
{
bPerkNetReady = true ;
ApplyEffects ( ) ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
simulated function string GetStatUIStr ( int iStat )
2017-10-20 02:00:49 +00:00
{
local string S ;
local bool bLoop ;
S = string ( Abs ( PerkStats [ iStat ] . DisplayValue * 100. f ) ) ;
bLoop = true ;
// Chop off float digits that aren't needed.
2020-11-28 20:12:58 +00:00
while ( bLoop )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
switch ( Right ( S , 1 ) )
2017-10-20 02:00:49 +00:00
{
case "0" :
S = Left ( S , Len ( S ) - 1 ) ;
break ;
case "." :
S = Left ( S , Len ( S ) - 1 ) ;
bLoop = false ;
break ;
default :
bLoop = false ;
}
}
return Repl ( PerkStats [ iStat ] . UIName , "&" , S ) ;
}
2020-11-28 20:04:55 +00:00
final function UnloadStats ( optional byte Mode )
2017-10-20 02:00:49 +00:00
{
local int i , j ;
local KFPawn _Human KFP ;
PerkManager . bStatsDirty = true ;
2020-11-28 20:12:58 +00:00
if ( Mode <= 1 )
2017-10-20 02:00:49 +00:00
{
// Reset stats.
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkStats . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkStats [ i ] . CurrentValue > 0 )
2017-10-20 02:00:49 +00:00
{
CurrentSP += ( PerkStats [ i ] . CurrentValue * PerkStats [ i ] . CostPerValue ) ;
PerkStats [ i ] . CurrentValue = 0 ;
2020-11-28 20:12:58 +00:00
if ( bOwnerNetClient )
2017-10-20 02:00:49 +00:00
ClientSetStatValue ( i , 0 ) ;
}
}
ApplyEffects ( ) ;
}
2020-11-28 20:12:58 +00:00
if ( Mode == 0 || Mode == 2 )
2017-10-20 02:00:49 +00:00
{
KFP = KFPawn _Human ( PlayerOwner . Pawn ) ;
2020-11-28 20:12:58 +00:00
if ( KFP != None && ! KFP . IsAliveAndWell ( ) )
2017-10-20 02:00:49 +00:00
KFP = None ;
// Reset traits.
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel > 0 )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
for ( j = 0 ; j < PerkTraits [ i ] . CurrentLevel ; ++ j )
2017-10-20 02:00:49 +00:00
CurrentSP += PerkTraits [ i ] . TraitType . Static . GetTraitCost ( j ) ;
2020-11-28 20:12:58 +00:00
if ( PerkManager . CurrentPerk == Self )
2017-10-20 02:00:49 +00:00
{
PerkTraits [ i ] . TraitType . Static . TraitDeActivate ( Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
2020-11-28 20:12:58 +00:00
if ( KFP != None )
2017-10-20 02:00:49 +00:00
PerkTraits [ i ] . TraitType . Static . CancelEffectOn ( KFP , Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
}
PerkTraits [ i ] . TraitType . Static . CleanupTrait ( ExtPlayerController ( Owner ) , Self , PerkTraits [ i ] . Data ) ;
PerkTraits [ i ] . CurrentLevel = 0 ;
2020-11-28 20:12:58 +00:00
if ( bOwnerNetClient )
2017-10-20 02:00:49 +00:00
ClientReceiveTraitLvl ( i , 0 ) ;
}
}
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function FullReset ( optional bool bNotPrestige )
2017-10-20 02:00:49 +00:00
{
UnloadStats ( ) ;
// Set minimum values.
CurrentEXP = 0 ;
2020-11-28 20:12:58 +00:00
if ( ! bNotPrestige )
2017-10-20 02:00:49 +00:00
CurrentPrestige = 0 ;
CurrentLevel = MinimumLevel ;
CurrentSP = CurrentLevel * ( StarPointsPerLevel + CurrentPrestige * PrestigeSPIncrease ) ;
NextLevelEXP = GetNeededExp ( CurrentLevel ) ;
LastLevelEXP = 0 ;
2020-11-28 20:12:58 +00:00
if ( PerkManager . CurrentPerk == Self && PerkManager . PRIOwner != None )
2017-10-20 02:00:49 +00:00
{
PerkManager . PRIOwner . SetLevelProgress ( CurrentLevel , CurrentPrestige , MinimumLevel , MaximumLevel ) ;
PerkManager . PRIOwner . bForceNetUpdate = true ;
}
bForceNetUpdate = true ;
}
2020-11-28 20:04:55 +00:00
function bool PreventDeath ( KFPawn _Human Player , Controller Killer , Class < DamageType > DamType )
2017-10-20 02:00:49 +00:00
{
local int i ;
// Doing 2 passes of this so that things don't go out of order (spawn retaliation effect when you get redeemed etc)
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel > 0 && PerkTraits [ i ] . TraitType . Default . bHighPriorityDeath && PerkTraits [ i ] . TraitType . Static . PreventDeath ( Player , Killer , DamType , Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) )
2017-10-20 02:00:49 +00:00
return true ;
}
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel > 0 && ! PerkTraits [ i ] . TraitType . Default . bHighPriorityDeath && PerkTraits [ i ] . TraitType . Static . PreventDeath ( Player , Killer , DamType , Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) )
2017-10-20 02:00:49 +00:00
return true ;
}
return false ;
}
simulated function PlayerDied ( )
{
local int i ;
2020-11-28 20:12:58 +00:00
if ( WorldInfo . NetMode != NM _Client )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel > 0 )
2017-10-20 02:00:49 +00:00
PerkTraits [ i ] . TraitType . Static . PlayerDied ( Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
}
}
}
// Stat modifier functions.
2020-11-28 20:04:55 +00:00
simulated function float ApplyEffect ( name Type , float Value , float Progress )
2017-10-20 02:00:49 +00:00
{
local bool bActivePerk ;
bActivePerk = ( PerkManager != None && PerkManager . CurrentPerk == Self ) ;
2020-11-28 20:12:58 +00:00
switch ( Type )
2017-10-20 02:00:49 +00:00
{
case 'Speed' :
Modifiers [ 0 ] = 1. f + ( Value * Progress ) ;
break ;
case 'Damage' :
Modifiers [ 1 ] = 1. f + ( Value * Progress ) ;
break ;
case 'Recoil' :
Modifiers [ 2 ] = 1. f / ( 1. f + Value * Progress ) ;
break ;
case 'Spread' :
Modifiers [ 3 ] = 1. f / ( 1. f + Value * Progress ) ;
break ;
case 'Rate' :
Modifiers [ 4 ] = 1. f / ( 1. f + Value * Progress ) ;
break ;
case 'Reload' :
Modifiers [ 5 ] = 1. f / ( 1. f + Value * Progress ) ;
break ;
case 'Health' :
Modifiers [ 6 ] = 1. f + ( Value * Progress ) ;
2020-11-28 20:12:58 +00:00
if ( bActivePerk && PlayerOwner . Pawn != None )
2017-10-20 02:00:49 +00:00
{
PlayerOwner . Pawn . HealthMax = PlayerOwner . Pawn . Default . Health ;
ModifyHealth ( PlayerOwner . Pawn . HealthMax ) ;
}
break ;
case 'KnockDown' :
Modifiers [ 7 ] = FMin ( 1. f + ( Value * Progress ) , 2. f ) ;
return ( Modifiers [ 7 ] - 1. f ) ;
case 'Welder' :
Modifiers [ 8 ] = 1. f + ( Value * Progress ) ;
break ;
case 'Heal' :
Modifiers [ 9 ] = 1. f + ( Value * Progress ) ;
break ;
case 'Mag' :
Modifiers [ 10 ] = 1. f + ( Value * Progress ) ;
2020-11-28 20:12:58 +00:00
if ( bActivePerk && WorldInfo . NetMode != NM _Client && PlayerOwner . Pawn != None && PlayerOwner . Pawn . InvManager != None )
2017-10-20 02:00:49 +00:00
UpdateAmmoStatus ( PlayerOwner . Pawn . InvManager ) ;
break ;
case 'Spare' :
Modifiers [ 11 ] = 1. f + ( Value * Progress ) ;
2020-11-28 20:12:58 +00:00
if ( bActivePerk && WorldInfo . NetMode != NM _Client && PlayerOwner . Pawn != None && PlayerOwner . Pawn . InvManager != None )
2017-10-20 02:00:49 +00:00
UpdateAmmoStatus ( PlayerOwner . Pawn . InvManager ) ;
break ;
case 'OffDamage' :
Modifiers [ 12 ] = 1. f + ( Value * Progress ) ;
break ;
case 'SelfDamage' :
Modifiers [ 13 ] = 1. f / ( 1. f + Value * Progress ) ;
break ;
case 'Armor' :
Modifiers [ 14 ] = ( Value * Progress * 100. f ) ;
2020-11-28 20:12:58 +00:00
if ( bActivePerk && KFPawn _Human ( PlayerOwner . Pawn ) != None )
2017-10-20 02:00:49 +00:00
{
KFPawn _Human ( PlayerOwner . Pawn ) . MaxArmor = KFPawn _Human ( PlayerOwner . Pawn ) . Default . MaxArmor ;
ModifyArmor ( KFPawn _Human ( PlayerOwner . Pawn ) . MaxArmor ) ;
}
return FMin ( Value * Progress , 1.55 ) ;
case 'PoisonDmg' :
Modifiers [ 15 ] = 1. f / ( 1. f + Value * Progress ) ;
break ;
case 'SonicDmg' :
Modifiers [ 16 ] = 1. f / ( 1. f + Value * Progress ) ;
break ;
case 'FireDmg' :
Modifiers [ 17 ] = 1. f / ( 1. f + Value * Progress ) ;
break ;
case 'AllDmg' :
Modifiers [ 18 ] = 1. f / ( 1. f + Value * Progress ) ;
break ;
2020-07-06 17:45:02 +00:00
case 'HeadDamage' :
Modifiers [ 19 ] = Value * Progress ;
break ;
2020-07-07 14:04:37 +00:00
case 'HealRecharge' :
Modifiers [ 20 ] = 1. f / ( 1. f + Value * Progress ) ;
break ;
2017-10-20 02:00:49 +00:00
}
return ( Value * Progress ) ;
}
2020-11-28 20:04:55 +00:00
simulated function ModifyDamageGiven ( out int InDamage , optional Actor DamageCauser , optional KFPawn _Monster MyKFPM , optional KFPlayerController DamageInstigator , optional class < KFDamageType > DamageType , optional int HitZoneIdx )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( BasePerk == None || ( DamageType != None && DamageType . Default . ModifierPerkList . Find ( BasePerk ) >= 0 ) || ( KFWeapon ( DamageCauser ) != None && IsWeaponOnPerk ( KFWeapon ( DamageCauser ) ) ) )
2020-07-06 17:45:02 +00:00
{
2020-11-28 20:12:58 +00:00
if ( HitZoneIdx == 0 )
2020-07-06 17:45:02 +00:00
InDamage *= ( Modifiers [ 1 ] + Modifiers [ 19 ] ) ;
else
InDamage *= Modifiers [ 1 ] ;
}
2020-11-28 20:12:58 +00:00
else if ( DamageType == None || DamageType . Name != 'KFDT_SuicideExplosive' )
2017-10-20 02:00:49 +00:00
InDamage *= Modifiers [ 12 ] ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
simulated function ModifyDamageTaken ( out int InDamage , optional class < DamageType > DamageType , optional Controller InstigatedBy )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( InDamage > 0 )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( ( InstigatedBy == None || InstigatedBy == PlayerOwner ) && class < KFDamageType > ( DamageType ) != None )
2017-10-20 02:00:49 +00:00
InDamage *= Modifiers [ 13 ] ;
2020-11-28 20:12:58 +00:00
else if ( Modifiers [ 15 ] < 1 && class < KFDT _Toxic > ( DamageType ) != None )
2017-10-20 02:00:49 +00:00
InDamage = Max ( InDamage * Modifiers [ 15 ] , 1 ) ; // Do at least 1 damage.
2020-11-28 20:12:58 +00:00
else if ( Modifiers [ 16 ] < 1 && class < KFDT _Sonic > ( DamageType ) != None )
2017-10-20 02:00:49 +00:00
InDamage = Max ( InDamage * Modifiers [ 16 ] , 1 ) ;
2020-11-28 20:12:58 +00:00
else if ( Modifiers [ 17 ] < 1 && class < KFDT _Fire > ( DamageType ) != None )
2017-10-20 02:00:49 +00:00
InDamage = Max ( InDamage * Modifiers [ 17 ] , 1 ) ;
2020-11-28 20:12:58 +00:00
if ( Modifiers [ 18 ] < 1 && InstigatedBy != None && InstigatedBy != PlayerOwner )
2017-10-20 02:00:49 +00:00
InDamage = Max ( InDamage * Modifiers [ 18 ] , 1 ) ;
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
simulated function ModifyRecoil ( out float CurrentRecoilModifier , KFWeapon KFW )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( IsWeaponOnPerk ( KFW ) )
2017-10-20 02:00:49 +00:00
CurrentRecoilModifier *= Modifiers [ 2 ] ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
simulated function ModifySpread ( out float InSpread )
2017-10-20 02:00:49 +00:00
{
InSpread *= Modifiers [ 3 ] ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
simulated function ModifyRateOfFire ( out float InRate , KFWeapon KFW )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( IsWeaponOnPerk ( KFW ) )
2017-10-20 02:00:49 +00:00
InRate *= Modifiers [ 4 ] ;
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
simulated function float GetReloadRateScale ( KFWeapon KFW )
{
return ( IsWeaponOnPerk ( KFW ) ? Modifiers [ 5 ] : 1. f ) ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function ModifyHealth ( out int InHealth )
2017-10-20 02:00:49 +00:00
{
InHealth *= Modifiers [ 6 ] ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function ModifyArmor ( out byte MaxArmor )
2017-10-20 02:00:49 +00:00
{
MaxArmor = Min ( MaxArmor + Modifiers [ 14 ] , 255 ) ;
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
function float GetKnockdownPowerModifier ( )
{
return Modifiers [ 7 ] ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function float GetStunPowerModifier ( optional class < DamageType > DamageType , optional byte HitZoneIdx )
2017-10-20 02:00:49 +00:00
{
return Modifiers [ 7 ] ;
}
2020-11-28 20:04:55 +00:00
simulated function ModifyMeleeAttackSpeed ( out float InDuration ) ;
2017-10-20 02:00:49 +00:00
2020-11-28 20:04:55 +00:00
function AddDefaultInventory ( KFPawn P )
2017-10-20 02:00:49 +00:00
{
local int i ;
2020-11-28 20:12:58 +00:00
if ( PrimaryWeapon != None )
2017-10-20 02:00:49 +00:00
P . DefaultInventory . AddItem ( PrimaryWeapon ) ;
P . DefaultInventory . AddItem ( PrimaryMelee ) ;
2020-11-28 20:12:58 +00:00
if ( KFInventoryManager ( P . InvManager ) != None )
2017-10-20 02:00:49 +00:00
KFInventoryManager ( P . InvManager ) . MaxCarryBlocks = KFInventoryManager ( P . InvManager ) . Default . MaxCarryBlocks + Modifiers [ 10 ] ;
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( PerkTraits [ i ] . CurrentLevel > 0 )
2017-10-20 02:00:49 +00:00
PerkTraits [ i ] . TraitType . Static . AddDefaultInventory ( P , Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
}
}
2020-11-28 20:04:55 +00:00
simulated function ModifyWeldingRate ( out float FastenRate , out float UnfastenRate )
2017-10-20 02:00:49 +00:00
{
FastenRate *= Modifiers [ 8 ] ;
UnfastenRate *= Modifiers [ 8 ] ;
}
2020-11-28 20:04:55 +00:00
function bool RepairArmor ( Pawn HealTarget )
2017-10-20 02:00:49 +00:00
{
return false ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function bool ModifyHealAmount ( out float HealAmount )
2017-10-20 02:00:49 +00:00
{
HealAmount *= Modifiers [ 9 ] ;
return false ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
simulated function ModifyMagSizeAndNumber ( KFWeapon KFW , out int MagazineCapacity , optional array < Class < KFPerk > > WeaponPerkClass , optional bool bSecondary = false , optional name WeaponClassname )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( MagazineCapacity > 2 && ( KFW == None ? WeaponPerkClass . Find ( BasePerk ) >= 0 : IsWeaponOnPerk ( KFW ) ) ) // Skip boomstick for this.
2017-10-20 02:00:49 +00:00
MagazineCapacity = Min ( MagazineCapacity * Modifiers [ 10 ] , 255 ) ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
simulated function ModifySpareAmmoAmount ( KFWeapon KFW , out int PrimarySpareAmmo , optional const out STraderItem TraderItem , optional bool bSecondary )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( KFW == None ? TraderItem . AssociatedPerkClasses . Find ( BasePerk ) >= 0 : IsWeaponOnPerk ( KFW ) )
2017-10-20 02:00:49 +00:00
PrimarySpareAmmo *= Modifiers [ 11 ] ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
simulated function bool ShouldMagSizeModifySpareAmmo ( KFWeapon KFW , optional Class < KFPerk > WeaponPerkClass )
2017-10-20 02:00:49 +00:00
{
return ( KFW == None ? WeaponPerkClass == BasePerk : IsWeaponOnPerk ( KFW ) ) ;
}
2020-11-28 20:04:55 +00:00
final function UpdateAmmoStatus ( InventoryManager Inv )
2017-10-20 02:00:49 +00:00
{
local KFWeapon W ;
foreach Inv . InventoryActors ( class 'KFWeapon' , W )
{
2021-01-09 10:26:05 +00:00
// if (IsWeaponOnPerk(W))
W . ReInitializeAmmoCounts ( PerkManager ) ;
2017-10-20 02:00:49 +00:00
}
}
2020-11-28 20:04:55 +00:00
simulated function ModifyHealerRechargeTime ( out float RechargeRate )
2020-07-07 14:04:37 +00:00
{
RechargeRate *= Modifiers [ 20 ] ;
}
2017-10-20 02:00:49 +00:00
simulated function DrawSpecialPerkHUD ( Canvas C )
{
2020-11-28 20:12:58 +00:00
if ( EnemyHealthRange > 0 && PlayerOwner != None && KFPawn _Human ( PlayerOwner . Pawn ) != None )
2017-10-20 02:00:49 +00:00
DrawEnemyHealth ( C ) ;
}
2020-11-28 20:04:55 +00:00
simulated final function DrawEnemyHealth ( Canvas C )
2017-10-20 02:00:49 +00:00
{
local KFPawn _Monster KFPM ;
local vector X , CameraLocation ;
X = vector ( PlayerOwner . Pawn . GetViewRotation ( ) ) ;
CameraLocation = PlayerOwner . Pawn . GetPawnViewLocation ( ) ;
foreach WorldInfo . AllPawns ( class 'KFPawn_Monster' , KFPM , CameraLocation , EnemyDistDraw [ EnemyHealthRange - 1 ] )
{
2020-11-28 20:12:58 +00:00
if ( KFPM . IsAliveAndWell ( ) && ` TimeSince(KFPM.Mesh.LastRenderTime)<0.1f && KFPM.CanShowHealth() && KFPM.GetTeamNum()!=0 && (X Dot (KFPM.Location - CameraLocation))>0)
2017-10-20 02:00:49 +00:00
DrawZedHealthbar ( C , KFPM , CameraLocation ) ;
}
}
2020-11-28 20:04:55 +00:00
simulated final function DrawZedHealthbar ( Canvas C , KFPawn _Monster KFPM , vector CameraLocation )
2017-10-20 02:00:49 +00:00
{
local vector ScreenPos , TargetLocation ;
local float HealthBarLength , HealthbarHeight , HealthScale ;
HealthbarLength = FMin ( 50. f * ( float ( C . SizeX ) / 1024. f ) , 50. f ) * class 'KFGFxHudWrapper' . Default . FriendlyHudScale ;
HealthbarHeight = FMin ( 6. f * ( float ( C . SizeX ) / 1024. f ) , 6. f ) * class 'KFGFxHudWrapper' . Default . FriendlyHudScale ;
HealthScale = FClamp ( float ( KFPM . Health ) / float ( KFPM . HealthMax ) , 0. f , 1. f ) ;
2020-11-28 20:12:58 +00:00
if ( KFPM . bCrawler && KFPM . Floor . Z <= - 0.7 f && KFPM . Physics == PHYS _Spider )
2017-10-20 02:00:49 +00:00
{
TargetLocation = KFPM . Location + vect ( 0 , 0 , - 1 ) * KFPM . GetCollisionHeight ( ) * 1.2 ;
}
else
{
TargetLocation = KFPM . Location + vect ( 0 , 0 , 1 ) * KFPM . GetCollisionHeight ( ) * 1.2 ;
}
ScreenPos = C . Project ( TargetLocation ) ;
2020-11-28 20:12:58 +00:00
if ( ScreenPos . X < 0 || ScreenPos . X > C . SizeX || ScreenPos . Y < 0 || ScreenPos . Y > C . SizeY || ! FastTrace ( TargetLocation , CameraLocation ) )
2017-10-20 02:00:49 +00:00
return ;
C . EnableStencilTest ( true ) ;
C . SetDrawColor ( 0 , 0 , 0 , 255 ) ;
C . SetPos ( ScreenPos . X - HealthBarLength * 0.5 , ScreenPos . Y ) ;
C . DrawTileStretched ( class 'KFPerk_Commando' . Default . WhiteMaterial , HealthbarLength , HealthbarHeight , 0 , 0 , 32 , 32 ) ;
C . SetDrawColor ( 237 , 8 , 0 , 255 ) ;
C . SetPos ( ScreenPos . X - HealthBarLength * 0.5 + 1.0 , ScreenPos . Y + 1.0 ) ;
C . DrawTileStretched ( class 'KFPerk_Commando' . Default . WhiteMaterial , ( HealthBarLength - 2.0 ) * HealthScale , HealthbarHeight - 2.0 , 0 , 0 , 32 , 32 ) ;
C . EnableStencilTest ( false ) ;
}
2020-11-28 20:04:55 +00:00
function PlayerKilled ( KFPawn _Monster Victim , class < DamageType > DamageType ) ;
2017-10-20 02:00:49 +00:00
2020-11-28 20:04:55 +00:00
function ModifyBloatBileDoT ( out float DoTScaler )
2017-10-20 02:00:49 +00:00
{
DoTScaler = Modifiers [ 15 ] ;
}
2020-11-28 20:04:55 +00:00
simulated function bool GetIsUberAmmoActive ( KFWeapon KFW )
2017-10-20 02:00:49 +00:00
{
return false ;
}
2020-11-28 20:04:55 +00:00
function UpdatePerkHeadShots ( ImpactInfo Impact , class < DamageType > DamageType , int NumHit ) ;
2017-10-20 02:00:49 +00:00
2020-11-28 20:04:55 +00:00
function CheckForAirborneAgent ( KFPawn HealTarget , class < DamageType > DamType , int HealAmount ) ;
2017-10-20 02:00:49 +00:00
2020-11-28 20:04:55 +00:00
simulated function float GetZedTimeModifier ( KFWeapon W )
2017-10-20 02:00:49 +00:00
{
return 0. f ;
}
2020-11-28 20:04:55 +00:00
simulated function bool GetUsingTactialReload ( KFWeapon KFW )
2017-10-20 02:00:49 +00:00
{
return ( bTacticalReload && IsWeaponOnPerk ( KFW ) ) ;
}
2020-11-28 20:04:55 +00:00
simulated function float GetIronSightSpeedModifier ( KFWeapon KFW )
2017-10-20 02:00:49 +00:00
{
return 1. f ;
}
2017-10-20 07:02:53 +00:00
function OnWaveEnded ( ) ;
function NotifyZedTimeStarted ( ) ;
2020-11-28 20:04:55 +00:00
simulated function float GetZedTimeExtensions ( byte Level )
2017-10-20 07:02:53 +00:00
{
return 1. f ;
}
2017-10-20 02:00:49 +00:00
defaultproperties
{
2020-07-07 14:04:37 +00:00
CurrentConfigVer = 14
2017-10-20 02:00:49 +00:00
bOnlyRelevantToOwner = true
bCanBeGrabbed = true
NetUpdateFrequency = 1
GrenadeClass = class 'KFProj_FragGrenade'
PerkGrenade = class 'KFProj_FragGrenade'
SuperGrenade = class 'ExtProj_SUPERGrenade'
HealExpUpNum = 12
WeldExpUpNum = 180
ToxicDartDamage = 15
NetPriority = 4
SecondaryWeaponDef = class 'KFWeapDef_9mm'
KnifeWeaponDef = class 'KFWeapDef_Knife_Commando'
GrenadeWeaponDef = class 'KFWeapDef_Grenade_Support'
DefTraitList . Add ( class 'Ext_TraitGrenadeUpg' )
DefTraitList . Add ( class 'Ext_TraitNightvision' )
DefTraitList . Add ( class 'Ext_TraitAmmoReg' )
DefTraitList . Add ( class 'Ext_TraitHealthReg' )
DefTraitList . Add ( class 'Ext_TraitArmorReg' )
DefTraitList . Add ( class 'Ext_TraitCarryCap' )
DefTraitList . Add ( class 'Ext_TraitGrenadeCap' )
DefTraitList . Add ( class 'Ext_TraitMedicPistol' )
DefTraitList . Add ( class 'Ext_TraitZED_Summon' )
DefTraitList . Add ( class 'Ext_TraitZED_Health' )
DefTraitList . Add ( class 'Ext_TraitZED_Damage' )
DefTraitList . Add ( class 'Ext_TraitZED_SummonExt' )
DefTraitList . Add ( class 'Ext_TraitGhost' )
DefTraitList . Add ( class 'Ext_TraitRetali' )
DefTraitList . Add ( class 'Ext_TraitDuracell' )
DefTraitList . Add ( class 'Ext_TraitRagdoll' )
DefTraitList . Add ( class 'Ext_TraitAutoFire' )
DefTraitList . Add ( class 'Ext_TraitBunnyHop' )
DefTraitList . Add ( class 'Ext_TraitKnockback' )
WebConfigs . Add ( ( PropType = 0 , PropName = "FirstLevelExp" , UIName = "First Level XP" , UIDesc = "EXP required for the FIRST level" ) )
WebConfigs . Add ( ( PropType = 0 , PropName = "LevelUpExpCost" , UIName = "Level Up XP" , UIDesc = "EXP cost for every next level (Level * ThisValue" ) )
WebConfigs . Add ( ( PropType = 0 , PropName = "LevelUpIncCost" , UIName = "Level Up Inc XP" , UIDesc = "Increased EXP cost for every level ((Level^2) * ThisValue)" ) )
WebConfigs . Add ( ( PropType = 0 , PropName = "MinimumLevel" , UIName = "Minimum Level" , UIDesc = "The minimum level of players" ) )
WebConfigs . Add ( ( PropType = 0 , PropName = "MaximumLevel" , UIName = "Maximum Level" , UIDesc = "The maximum level of players" ) )
WebConfigs . Add ( ( PropType = 0 , PropName = "StarPointsPerLevel" , UIName = "Star Points Per Lvl" , UIDesc = "Number of star points players earn per level" ) )
WebConfigs . Add ( ( PropType = 2 , PropName = "TraitClasses" , UIName = "Trait Classes" , UIDesc = "The class names of traits players can buy" , NumElements = - 1 ) )
WebConfigs . Add ( ( PropType = 2 , PropName = "PerkStats" , UIName = "Perk Stats" , UIDesc = "List of perk stats (format in: StatName,Max Stat,Cost Per Stat,Progress Per Level)" , NumElements = - 1 ) )
WebConfigs . Add ( ( PropType = 0 , PropName = "MinLevelForPrestige" , UIName = "Min Level For Prestige" , UIDesc = "Minimum level required to prestige the perk (-1 = disabled)" ) )
WebConfigs . Add ( ( PropType = 0 , PropName = "PrestigeSPIncrease" , UIName = "Prestige SP Increase" , UIDesc = "Star points increase per level for every prestige" ) )
WebConfigs . Add ( ( PropType = 0 , PropName = "MaxPrestige" , UIName = "Max Prestige" , UIDesc = "Maximum prestige level" ) )
WebConfigs . Add ( ( PropType = 0 , PropName = "PrestigeXPReduce" , UIName = "Prestige XP Reduce" , UIDesc = "Percent amount of XP cost is reduced for each prestige (1.0 = 1/2, or 50 % of XP)" ) )
2020-07-06 21:12:25 +00:00
// WebConfigs.Add((PropType=0,PropName="MinimalDataLevel",UIName="Minimal Real Level",UIDesc="Minimal level for new players or who loads from saves"))
2017-10-20 02:00:49 +00:00
2020-06-26 06:32:40 +00:00
// TODO: localize
2020-09-01 08:07:53 +00:00
DefPerkStats ( 0 ) = ( MaxValue = 50 , CostPerValue = 1 , StatType = "Speed" , Progress = 0.4 )
DefPerkStats ( 1 ) = ( MaxValue = 1000 , CostPerValue = 1 , StatType = "Damage" , Progress = 0.5 )
DefPerkStats ( 2 ) = ( MaxValue = 90 , CostPerValue = 1 , StatType = "Recoil" , Progress = 1 )
DefPerkStats ( 3 ) = ( MaxValue = 80 , CostPerValue = 1 , StatType = "Spread" , Progress = 0.75 )
DefPerkStats ( 4 ) = ( MaxValue = 1000 , CostPerValue = 1 , StatType = "Rate" , Progress = 0.5 )
DefPerkStats ( 5 ) = ( MaxValue = 1000 , CostPerValue = 1 , StatType = "Reload" , Progress = 0.5 )
DefPerkStats ( 6 ) = ( MaxValue = 150 , CostPerValue = 1 , StatType = "Health" , Progress = 1 )
DefPerkStats ( 7 ) = ( MaxValue = 100 , CostPerValue = 1 , StatType = "KnockDown" , Progress = 1 )
DefPerkStats ( 8 ) = ( MaxValue = 200 , CostPerValue = 1 , StatType = "Welder" , bHiddenConfig = true , Progress = 0.5 )
DefPerkStats ( 9 ) = ( MaxValue = 400 , CostPerValue = 1 , StatType = "Heal" , bHiddenConfig = true , Progress = 0.5 )
DefPerkStats ( 10 ) = ( MaxValue = 400 , CostPerValue = 1 , StatType = "Mag" , Progress = 1 )
DefPerkStats ( 11 ) = ( MaxValue = 500 , CostPerValue = 1 , StatType = "Spare" , Progress = 1 )
DefPerkStats ( 12 ) = ( MaxValue = 1000 , CostPerValue = 1 , StatType = "OffDamage" , Progress = 0.25 )
DefPerkStats ( 13 ) = ( MaxValue = 1000 , CostPerValue = 1 , StatType = "SelfDamage" , Progress = 1 , bHiddenConfig = true )
DefPerkStats ( 14 ) = ( MaxValue = 150 , CostPerValue = 1 , StatType = "Armor" , Progress = 1 )
DefPerkStats ( 15 ) = ( MaxValue = 1000 , CostPerValue = 1 , StatType = "PoisonDmg" , Progress = 1.5 , bHiddenConfig = true )
DefPerkStats ( 16 ) = ( MaxValue = 1000 , CostPerValue = 1 , StatType = "SonicDmg" , Progress = 1.5 , bHiddenConfig = true )
DefPerkStats ( 17 ) = ( MaxValue = 1000 , CostPerValue = 1 , StatType = "FireDmg" , Progress = 1.5 , bHiddenConfig = true )
DefPerkStats ( 18 ) = ( MaxValue = 500 , CostPerValue = 1 , StatType = "AllDmg" , Progress = 0.25 )
DefPerkStats ( 19 ) = ( MaxValue = 500 , CostPerValue = 1 , StatType = "HeadDamage" , Progress = 1 , bHiddenConfig = true )
DefPerkStats ( 20 ) = ( MaxValue = 200 , CostPerValue = 1 , StatType = "HealRecharge" , Progress = 0.5 , bHiddenConfig = true )
2017-10-20 02:00:49 +00:00
Modifiers . Add ( 1. f )
Modifiers . Add ( 1. f )
Modifiers . Add ( 1. f )
Modifiers . Add ( 1. f )
Modifiers . Add ( 1. f )
Modifiers . Add ( 1. f )
Modifiers . Add ( 1. f )
Modifiers . Add ( 1. f )
Modifiers . Add ( 1. f )
Modifiers . Add ( 1. f )
Modifiers . Add ( 1. f )
Modifiers . Add ( 1. f )
Modifiers . Add ( 1. f )
Modifiers . Add ( 1. f )
Modifiers . Add ( 0. f )
Modifiers . Add ( 1. f )
Modifiers . Add ( 1. f )
Modifiers . Add ( 1. f )
Modifiers . Add ( 1. f )
2020-07-06 21:12:25 +00:00
Modifiers . Add ( 0. f )
2020-07-07 14:04:37 +00:00
Modifiers . Add ( 1. f )
2017-10-20 02:00:49 +00:00
EnemyDistDraw . Add ( 500 )
EnemyDistDraw . Add ( 700 )
EnemyDistDraw . Add ( 1000 )
EnemyDistDraw . Add ( 1600 )
}