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 ;
var ( ) string PerkName ;
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 string UIName ;
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 ;
replication
{
// Things the server should send to the client.
if ( true )
CurrentLevel , CurrentPrestige , CurrentEXP , NextLevelEXP , CurrentSP , LastLevelEXP , bHasNightVision , MinLevelForPrestige , PrestigeSPIncrease , MaxPrestige , bTacticalReload , EnemyHealthRange ;
}
simulated final function bool IsWeaponOnPerk ( KFWeapon W )
{
2017-10-22 02:06:31 +00:00
if ( class < KFPerk _Survivalist > ( BasePerk ) != None )
return true ;
2020-06-21 19:06:43 +00:00
//if( W.AllowedForAllPerks() )
// 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 ;
}
simulated static function string GetPerkIconPath ( int Level )
{
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 ;
if ( WorldInfo . NetMode == NM _Client )
{
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 ) ;
if ( PlayerOwner == None )
{
` Log(Self@"spawned without owner.");
Destroy ( ) ;
return ;
}
bOwnerNetClient = ( PlayerController ( Owner ) != None && LocalPlayer ( PlayerController ( Owner ) . Player ) == None ) ;
// Load trait classes.
j = 0 ;
for ( i = 0 ; i < TraitClasses . Length ; ++ i )
{
T = class < Ext _TraitBase > ( DynamicLoadObject ( TraitClasses [ i ] , Class 'Class' ) ) ;
if ( T == None || ! T . Static . IsEnabled ( Self ) )
continue ;
PerkTraits . Length = j + 1 ;
PerkTraits [ j ] . TraitType = T ;
++ j ;
}
// Setup serverside stat info (for XML log files).
for ( j = 0 ; j < PerkStats . Length ; ++ j )
{
i = DefPerkStats . Find ( 'StatType' , PerkStats [ j ] . StatType ) ;
if ( i >= 0 )
PerkStats [ j ] . UIName = DefPerkStats [ i ] . UIName ;
else
{
// Fallback to parent perk for trying to find name.
i = Class 'Ext_PerkBase' . Default . DefPerkStats . Find ( 'StatType' , PerkStats [ j ] . StatType ) ;
if ( i >= 0 )
PerkStats [ j ] . UIName = Class 'Ext_PerkBase' . Default . DefPerkStats [ i ] . UIName ;
else PerkStats [ j ] . UIName = string ( PerkStats [ j ] . StatType ) ; // Fallback to stat name then...
}
}
}
}
simulated function InitPerk ( )
{
if ( PlayerOwner == None )
PlayerOwner = GetALocalPlayerController ( ) ;
if ( PerkManager == None )
{
foreach DynamicActors ( class 'ExtPerkManager' , PerkManager )
{
PerkManager . RegisterPerk ( Self ) ;
break ;
}
}
}
simulated function Destroyed ( )
{
local int i ;
if ( PerkManager != None )
PerkManager . UnregisterPerk ( Self ) ;
if ( WorldInfo . NetMode != NM _Client )
{
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
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 ) ;
}
reliable client simulated function ClientReceiveStat ( int Index , int MaxValue , int CostPerValue , name Type , int CurValue , float Progress )
{
local int i ;
if ( WorldInfo . NetMode == NM _Client )
{
if ( PerkStats . Length <= Index )
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 ) ;
if ( i >= 0 )
PerkStats [ Index ] . UIName = DefPerkStats [ i ] . UIName ;
else
{
// Fallback to parent perk for trying to find name.
i = Class 'Ext_PerkBase' . Default . DefPerkStats . Find ( 'StatType' , Type ) ;
if ( i >= 0 )
PerkStats [ Index ] . UIName = Class 'Ext_PerkBase' . Default . DefPerkStats [ i ] . UIName ;
else PerkStats [ Index ] . UIName = string ( Type ) ; // Fallback to stat name then...
}
}
reliable client simulated function ClientSetStatValue ( int Index , int NewValue )
{
if ( PerkStats . Length <= Index )
PerkStats . Length = Index + 1 ;
PerkStats [ Index ] . CurrentValue = NewValue ;
if ( bPerkNetReady )
ApplyEffects ( ) ;
}
reliable client simulated function ClientReceiveTrait ( int Index , class < Ext _TraitBase > TC , byte Lvl )
{
if ( PerkTraits . Length <= Index )
PerkTraits . Length = Index + 1 ;
PerkTraits [ Index ] . TraitType = TC ;
PerkTraits [ Index ] . CurrentLevel = Lvl ;
}
reliable client simulated function ClientReceiveTraitData ( int Index , string Data )
{
if ( WorldInfo . NetMode == NM _Client )
PerkTraits [ Index ] . TraitType . Static . ClientSetRepData ( Data ) ;
}
reliable client simulated function ClientReceiveTraitLvl ( int Index , byte NewLevel )
{
PerkTraits [ Index ] . CurrentLevel = NewLevel ;
}
final function SetPerkStat ( name Type , int Value )
{
local int i ;
i = PerkStats . Find ( 'StatType' , Type ) ;
if ( i >= 0 )
PerkStats [ i ] . CurrentValue = Value ;
}
final function int GetPerkStat ( name Type )
{
local int i ;
i = PerkStats . Find ( 'StatType' , Type ) ;
if ( i == - 1 )
return 0 ;
return PerkStats [ i ] . CurrentValue ;
}
function bool EarnedEXP ( int EXP )
{
local int n ;
bForceNetUpdate = true ;
CurrentEXP += EXP ;
while ( CurrentEXP >= NextLevelEXP && CurrentLevel < MaximumLevel && n < 20 )
{
++ n ;
LastLevelEXP = NextLevelEXP ;
NextLevelEXP = GetNeededExp ( ++ CurrentLevel ) ;
}
if ( n > 0 )
{
CurrentSP += ( n * ( StarPointsPerLevel + CurrentPrestige * PrestigeSPIncrease ) ) ;
if ( PerkManager . PRIOwner != None && PerkManager . CurrentPerk == Self )
UpdatePRILevel ( ) ;
// TODO - broadcast level up messages.
if ( ExtPlayerController ( PlayerOwner ) != None )
ExtPlayerController ( PlayerOwner ) . ReceiveLevelUp ( Self , CurrentLevel ) ;
}
return true ;
}
final function UpdatePRILevel ( )
{
PerkManager . PRIOwner . SetLevelProgress ( CurrentLevel , CurrentPrestige , MinimumLevel , MaximumLevel ) ;
}
// XML output
function OutputXML ( ExtStatWriter Data )
{
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 ) ) ;
for ( i = 0 ; i < PerkStats . Length ; ++ i )
{
if ( PerkStats [ i ] . CurrentValue > 0 )
{
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 ( ) ;
}
}
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
{
if ( PerkTraits [ i ] . CurrentLevel > 0 )
{
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.
function SaveData ( ExtSaveDataBase Data )
{
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 ;
for ( i = 0 ; i < PerkStats . Length ; ++ i )
if ( PerkStats [ i ] . CurrentValue > 0 )
++ j ;
// Then perk stats.
Data . SaveInt ( j ) ;
for ( i = 0 ; i < PerkStats . Length ; ++ i )
{
if ( PerkStats [ i ] . CurrentValue > 0 )
{
Data . SaveStr ( string ( PerkStats [ i ] . StatType ) ) ;
Data . SaveInt ( PerkStats [ i ] . CurrentValue , 1 ) ;
}
}
// Count bought traits.
j = 0 ;
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
if ( PerkTraits [ i ] . CurrentLevel > 0 )
++ j ;
// Then traits.
Data . SaveInt ( j ) ;
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
{
if ( PerkTraits [ i ] . CurrentLevel > 0 )
{
Data . SaveStr ( string ( PerkTraits [ i ] . TraitType ) ) ;
Data . SaveInt ( PerkTraits [ i ] . CurrentLevel ) ;
}
}
}
// Data loading.
function LoadData ( ExtSaveDataBase Data )
{
local int i , j , l , n ;
local string S ;
CurrentEXP = Data . ReadInt ( 3 ) ;
2020-07-06 21:12:25 +00:00
// if(MinimalDataLevel > 0)
// {
// i = GetNeededExp(MinimalDataLevel-1)
// if(i > CurrentEXP)
// CurrentEXP = i
// }
2017-10-20 02:00:49 +00:00
if ( Data . GetArVer ( ) >= 1 )
CurrentPrestige = Data . ReadInt ( 3 ) ;
l = Data . ReadInt ( ) ; // Perk stats length.
for ( i = 0 ; i < l ; ++ i )
{
S = Data . ReadStr ( ) ;
n = Data . ReadInt ( 1 ) ;
for ( j = 0 ; j < PerkStats . Length ; ++ j )
if ( S ~ = string ( PerkStats [ j ] . StatType ) )
{
PerkStats [ j ] . CurrentValue = n ;
break ;
}
}
l = Data . ReadInt ( ) ; // Traits stats length.
for ( i = 0 ; i < l ; ++ i )
{
S = Data . ReadStr ( ) ;
n = Data . ReadInt ( ) ;
for ( j = 0 ; j < PerkTraits . Length ; ++ j )
if ( S ~ = string ( PerkTraits [ j ] . TraitType ) )
{
PerkTraits [ j ] . CurrentLevel = n ;
break ;
}
}
}
final function int CalcLevelForExp ( int InExp )
{
local int i , a , b ;
// Fast method to calc level for a player.
b = MaximumLevel + 1 ;
a = Min ( MinimumLevel , b ) ;
while ( true )
{
if ( a == b || ( a + 1 ) == b )
{
if ( a < MaximumLevel && InExp >= GetNeededExp ( a ) )
++ a ;
break ;
}
i = a + ( ( b - a ) >> 1 ) ;
if ( InExp < GetNeededExp ( i ) ) // Lower!
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-07-06 21:12:25 +00:00
if ( MinimalDataLevel > 0 )
{
i = GetNeededExp ( MinimalDataLevel - 1 ) ;
if ( i > CurrentEXP )
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.
for ( i = 0 ; i < PerkStats . Length ; ++ i )
{
if ( PerkStats [ i ] . CurrentValue > 0 )
{
PerkStats [ i ] . CurrentValue = Min ( PerkStats [ i ] . CurrentValue , PerkStats [ i ] . MaxValue ) ;
a = PerkStats [ i ] . CurrentValue * PerkStats [ i ] . CostPerValue ;
if ( CurrentSP > a )
CurrentSP -= a ;
else if ( CurrentSP <= 0 ) // No points at all for this.
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 ;
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
{
if ( PerkTraits [ i ] . CurrentLevel > 0 )
{
PerkTraits [ i ] . CurrentLevel = Min ( PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . TraitType . Default . NumLevels ) ;
if ( PerkTraits [ i ] . TraitType . Default . LoadPriority > 0 )
MT = Max ( MT , PerkTraits [ i ] . TraitType . Default . LoadPriority ) ;
else
{
if ( ! PerkTraits [ i ] . TraitType . Static . MeetsRequirements ( PerkTraits [ i ] . CurrentLevel - 1 , Self ) )
a = 0 ;
else
{
for ( a = 0 ; a < PerkTraits [ i ] . CurrentLevel ; ++ a )
{
b = PerkTraits [ i ] . TraitType . Static . GetTraitCost ( a ) ;
if ( b > CurrentSP )
break ;
CurrentSP -= b ;
}
}
PerkTraits [ i ] . CurrentLevel = a ;
if ( PerkTraits [ i ] . CurrentLevel > 0 && PerkTraits [ i ] . Data == None )
PerkTraits [ i ] . Data = PerkTraits [ i ] . TraitType . Static . InitializeFor ( Self , ExtPlayerController ( Owner ) ) ;
}
}
if ( PerkTraits [ i ] . CurrentLevel == 0 && PerkTraits [ i ] . Data != None )
PerkTraits [ i ] . TraitType . Static . CleanupTrait ( ExtPlayerController ( Owner ) , Self , PerkTraits [ i ] . Data ) ;
}
// Delayed loads.
for ( j = 1 ; j <= MT ; ++ j )
{
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
{
if ( PerkTraits [ i ] . CurrentLevel > 0 && PerkTraits [ i ] . TraitType . Default . LoadPriority == j )
{
if ( ! PerkTraits [ i ] . TraitType . Static . MeetsRequirements ( PerkTraits [ i ] . CurrentLevel - 1 , Self ) )
a = 0 ;
else
{
for ( a = 0 ; a < PerkTraits [ i ] . CurrentLevel ; ++ a )
{
b = PerkTraits [ i ] . TraitType . Static . GetTraitCost ( a ) ;
if ( b > CurrentSP )
break ;
CurrentSP -= b ;
}
}
PerkTraits [ i ] . CurrentLevel = a ;
if ( PerkTraits [ i ] . CurrentLevel > 0 && PerkTraits [ i ] . Data == None )
PerkTraits [ i ] . Data = PerkTraits [ i ] . TraitType . Static . InitializeFor ( Self , ExtPlayerController ( Owner ) ) ;
}
if ( PerkTraits [ i ] . CurrentLevel == 0 && PerkTraits [ i ] . Data != None )
PerkTraits [ i ] . TraitType . Static . CleanupTrait ( ExtPlayerController ( Owner ) , Self , PerkTraits [ i ] . Data ) ;
}
}
ApplyEffects ( ) ;
if ( PerkManager . CurrentPerk == Self )
ActivateTraits ( ) ;
}
// Check the needed amount of EXP for a perk.
function int GetNeededExp ( int LevelNum )
{
if ( LevelNum < MinimumLevel || LevelNum >= MaximumLevel )
return 0 ;
LevelNum -= MinimumLevel ;
LevelNum = ( FirstLevelExp + ( LevelNum * LevelUpExpCost ) + ( LevelNum * LevelNum * LevelUpIncCost ) ) ;
if ( CurrentPrestige > 0 && PrestigeXPReduce > 0 )
LevelNum *= ( 1. f / ( 1. f + PrestigeXPReduce * CurrentPrestige ) ) ;
return LevelNum ;
}
// Configure initialization.
static function CheckConfig ( )
{
local int i ;
local class < Ext _TraitBase > T ;
if ( Default . ConfigVersion != Default . CurrentConfigVer )
{
UpdateConfigs ( Default . ConfigVersion ) ;
Default . ConfigVersion = Default . CurrentConfigVer ;
StaticSaveConfig ( ) ;
}
for ( i = 0 ; i < Default . TraitClasses . Length ; ++ i )
{
T = class < Ext _TraitBase > ( DynamicLoadObject ( Default . TraitClasses [ i ] , Class 'Class' ) ) ;
if ( T != None )
T . Static . CheckConfig ( ) ;
}
}
static function UpdateConfigs ( int OldVer )
{
local int i , j ;
if ( OldVer == 0 )
{
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 ;
for ( i = 0 ; i < Default . DefTraitList . Length ; ++ i )
Default . TraitClasses [ i ] = PathName ( Default . DefTraitList [ i ] ) ;
}
else
{
// Add progress.
if ( OldVer == 1 )
{
for ( i = 0 ; i < Default . PerkStats . Length ; ++ i )
{
j = Default . DefPerkStats . Find ( 'StatType' , Default . PerkStats [ i ] . StatType ) ;
if ( j >= 0 )
Default . PerkStats [ i ] . Progress = Default . DefPerkStats [ j ] . Progress ;
}
// Add off-perk damage stat.
AddStatsCfg ( 12 ) ;
}
else if ( OldVer <= 3 )
AddStatsCfg ( 13 ) ; // Add self damage.
else if ( OldVer <= 4 )
AddStatsCfg ( 15 ) ; // Add poison damage.
else if ( OldVer <= 7 )
AddStatsCfg ( 16 ) ; // Add sonic/fire damage.
else if ( OldVer <= 12 )
AddStatsCfg ( 18 ) ; // Add all damage.
2020-07-07 14:04:37 +00:00
else if ( OldVer <= 13 )
AddStatsCfg ( 19 ) ; // Add HeadDamage and HealRecharge
2017-10-20 02:00:49 +00:00
if ( OldVer <= 5 )
{
// Add prestige
Default . MinLevelForPrestige = 140 ;
Default . PrestigeSPIncrease = 1 ;
Default . MaxPrestige = 20 ;
Default . PrestigeXPReduce = 0.05 ;
}
Default . TraitClasses . Length = Default . DefTraitList . Length ;
for ( i = 0 ; i < Default . DefTraitList . Length ; ++ i )
Default . TraitClasses [ i ] = PathName ( Default . DefTraitList [ i ] ) ;
}
}
static final function AddStatsCfg ( int StartRange )
{
local int i , j ;
j = Default . PerkStats . Length ;
for ( i = StartRange ; i < Default . DefPerkStats . Length ; ++ i )
{
if ( Default . DefPerkStats [ i ] . bHiddenConfig || Default . PerkStats . Find ( 'StatType' , Default . DefPerkStats [ i ] . StatType ) >= 0 ) // Don't add if already found for some reason.
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.
static function InitWebAdmin ( ExtWebAdmin _UI UI )
{
local class < Ext _TraitBase > T ;
local int i ;
UI . AddSettingsPage ( "Perk " $Default . PerkName , Default . Class , Default . WebConfigs , GetValue , ApplyValue ) ;
for ( i = 0 ; i < Default . TraitClasses . Length ; ++ i )
{
T = class < Ext _TraitBase > ( DynamicLoadObject ( Default . TraitClasses [ i ] , Class 'Class' ) ) ;
if ( T == None || UI . HasConfigFor ( T ) )
continue ;
T . Static . InitWebAdmin ( UI ) ;
}
}
static function string GetValue ( name PropName , int ElementIndex )
{
switch ( PropName )
{
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 ) ;
}
}
static function ApplyValue ( name PropName , int ElementIndex , string Value )
{
switch ( PropName )
{
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' :
if ( Value == "#DELETE" )
Default . TraitClasses . Remove ( ElementIndex , 1 ) ;
else
{
if ( ElementIndex >= Default . TraitClasses . Length )
Default . TraitClasses . Length = ElementIndex + 1 ;
Default . TraitClasses [ ElementIndex ] = Value ;
}
break ;
case 'PerkStats' :
if ( Value == "#DELETE" )
Default . PerkStats . Remove ( ElementIndex , 1 ) ;
else
{
if ( ElementIndex >= Default . PerkStats . Length )
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 ( ) ;
}
static final function FPerkStat ParsePerkStatStr ( string S )
{
local FPerkStat Res ;
local int i ;
i = InStr ( S , "," ) ;
if ( i == - 1 )
return Res ;
Res . StatType = name ( Left ( S , i ) ) ;
S = Mid ( S , i + 1 ) ;
i = InStr ( S , "," ) ;
if ( i == - 1 )
return Res ;
Res . MaxValue = int ( Left ( S , i ) ) ;
S = Mid ( S , i + 1 ) ;
i = InStr ( S , "," ) ;
if ( i == - 1 )
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.
function bool IncrementStat ( int iStat , int Amount )
{
PerkStats [ iStat ] . CurrentValue += Amount ;
if ( bOwnerNetClient )
ClientSetStatValue ( iStat , PerkStats [ iStat ] . CurrentValue ) ;
PerkManager . bStatsDirty = true ;
ApplyEffects ( ) ;
bForceNetUpdate = true ;
return true ;
}
simulated function ApplyEffects ( )
{
local int i ;
for ( i = 0 ; i < PerkStats . Length ; ++ i )
{
if ( PerkStats [ i ] . CurrentValue != PerkStats [ i ] . OldValue )
{
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.
function ApplyEffectsTo ( KFPawn _Human P )
{
local int i ;
local bool bSec ;
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
{
if ( PerkTraits [ i ] . CurrentLevel > 0 )
{
if ( PerkTraits [ i ] . TraitType . Default . bPostApplyEffect )
bSec = true ;
else PerkTraits [ i ] . TraitType . Static . ApplyEffectOn ( P , Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
}
}
if ( bSec )
{
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
{
if ( PerkTraits [ i ] . CurrentLevel > 0 && PerkTraits [ i ] . TraitType . Default . bPostApplyEffect )
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 ) ;
if ( KFP != None && ! KFP . IsAliveAndWell ( ) )
KFP = None ;
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
{
if ( PerkTraits [ i ] . CurrentLevel > 0 )
{
PerkTraits [ i ] . TraitType . Static . TraitActivate ( Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
if ( KFP != None )
{
if ( PerkTraits [ i ] . TraitType . Default . bPostApplyEffect )
bSec = true ;
else PerkTraits [ i ] . TraitType . Static . ApplyEffectOn ( KFP , Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
}
}
}
if ( bSec )
{
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
{
if ( PerkTraits [ i ] . CurrentLevel > 0 && PerkTraits [ i ] . TraitType . Default . bPostApplyEffect )
PerkTraits [ i ] . TraitType . Static . ApplyEffectOn ( KFP , Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
}
}
}
// Player disconnected/perk changed.
function DeactivateTraits ( )
{
local int i ;
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
{
if ( PerkTraits [ i ] . CurrentLevel > 0 )
PerkTraits [ i ] . TraitType . Static . TraitDeActivate ( Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
}
}
simulated unreliable client function ClientAuth ( )
{
if ( Owner == None )
SetOwner ( PlayerOwner ) ;
ServerAck ( ) ;
}
unreliable server function ServerAck ( )
{
if ( ! bClientAuthorized )
{
bClientAuthorized = true ;
RepState = 0 ;
RepIndex = 0 ;
SetTimer ( 0.01 + FRand ( ) * 0.025 , true , 'ReplicateTimer' ) ;
}
}
function ReplicateTimer ( )
{
switch ( RepState )
{
case 0 : // Send all perk stats
if ( RepIndex >= PerkStats . Length )
{
++ 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
if ( RepIndex >= PerkTraits . Length )
++ 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.
}
}
simulated reliable client function ClientIsReady ( )
{
bPerkNetReady = true ;
ApplyEffects ( ) ;
}
simulated function string GetStatUIStr ( int iStat )
{
local string S ;
local bool bLoop ;
S = string ( Abs ( PerkStats [ iStat ] . DisplayValue * 100. f ) ) ;
bLoop = true ;
// Chop off float digits that aren't needed.
while ( bLoop )
{
switch ( Right ( S , 1 ) )
{
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 ) ;
}
final function UnloadStats ( optional byte Mode )
{
local int i , j ;
local KFPawn _Human KFP ;
PerkManager . bStatsDirty = true ;
if ( Mode <= 1 )
{
// Reset stats.
for ( i = 0 ; i < PerkStats . Length ; ++ i )
{
if ( PerkStats [ i ] . CurrentValue > 0 )
{
CurrentSP += ( PerkStats [ i ] . CurrentValue * PerkStats [ i ] . CostPerValue ) ;
PerkStats [ i ] . CurrentValue = 0 ;
if ( bOwnerNetClient )
ClientSetStatValue ( i , 0 ) ;
}
}
ApplyEffects ( ) ;
}
if ( Mode == 0 || Mode == 2 )
{
KFP = KFPawn _Human ( PlayerOwner . Pawn ) ;
if ( KFP != None && ! KFP . IsAliveAndWell ( ) )
KFP = None ;
// Reset traits.
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
{
if ( PerkTraits [ i ] . CurrentLevel > 0 )
{
for ( j = 0 ; j < PerkTraits [ i ] . CurrentLevel ; ++ j )
CurrentSP += PerkTraits [ i ] . TraitType . Static . GetTraitCost ( j ) ;
if ( PerkManager . CurrentPerk == Self )
{
PerkTraits [ i ] . TraitType . Static . TraitDeActivate ( Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
if ( KFP != None )
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 ;
if ( bOwnerNetClient )
ClientReceiveTraitLvl ( i , 0 ) ;
}
}
}
}
function FullReset ( optional bool bNotPrestige )
{
UnloadStats ( ) ;
// Set minimum values.
CurrentEXP = 0 ;
if ( ! bNotPrestige )
CurrentPrestige = 0 ;
CurrentLevel = MinimumLevel ;
CurrentSP = CurrentLevel * ( StarPointsPerLevel + CurrentPrestige * PrestigeSPIncrease ) ;
NextLevelEXP = GetNeededExp ( CurrentLevel ) ;
LastLevelEXP = 0 ;
if ( PerkManager . CurrentPerk == Self && PerkManager . PRIOwner != None )
{
PerkManager . PRIOwner . SetLevelProgress ( CurrentLevel , CurrentPrestige , MinimumLevel , MaximumLevel ) ;
PerkManager . PRIOwner . bForceNetUpdate = true ;
}
bForceNetUpdate = true ;
}
function bool PreventDeath ( KFPawn _Human Player , Controller Killer , Class < DamageType > DamType )
{
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)
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
{
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 ) )
return true ;
}
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
{
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 ) )
return true ;
}
return false ;
}
simulated function PlayerDied ( )
{
local int i ;
if ( WorldInfo . NetMode != NM _Client )
{
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
{
if ( PerkTraits [ i ] . CurrentLevel > 0 )
PerkTraits [ i ] . TraitType . Static . PlayerDied ( Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
}
}
}
// Stat modifier functions.
simulated function float ApplyEffect ( name Type , float Value , float Progress )
{
local bool bActivePerk ;
bActivePerk = ( PerkManager != None && PerkManager . CurrentPerk == Self ) ;
switch ( Type )
{
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 ) ;
if ( bActivePerk && PlayerOwner . Pawn != None )
{
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 ) ;
if ( bActivePerk && WorldInfo . NetMode != NM _Client && PlayerOwner . Pawn != None && PlayerOwner . Pawn . InvManager != None )
UpdateAmmoStatus ( PlayerOwner . Pawn . InvManager ) ;
break ;
case 'Spare' :
Modifiers [ 11 ] = 1. f + ( Value * Progress ) ;
if ( bActivePerk && WorldInfo . NetMode != NM _Client && PlayerOwner . Pawn != None && PlayerOwner . Pawn . InvManager != None )
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 ) ;
if ( bActivePerk && KFPawn _Human ( PlayerOwner . Pawn ) != None )
{
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 ) ;
}
simulated function ModifyDamageGiven ( out int InDamage , optional Actor DamageCauser , optional KFPawn _Monster MyKFPM , optional KFPlayerController DamageInstigator , optional class < KFDamageType > DamageType , optional int HitZoneIdx )
{
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
{
if ( HitZoneIdx == 0 )
InDamage *= ( Modifiers [ 1 ] + Modifiers [ 19 ] ) ;
else
InDamage *= Modifiers [ 1 ] ;
}
2017-10-20 02:00:49 +00:00
else if ( DamageType == None || DamageType . Name != 'KFDT_SuicideExplosive' )
InDamage *= Modifiers [ 12 ] ;
}
simulated function ModifyDamageTaken ( out int InDamage , optional class < DamageType > DamageType , optional Controller InstigatedBy )
{
if ( InDamage > 0 )
{
if ( ( InstigatedBy == None || InstigatedBy == PlayerOwner ) && class < KFDamageType > ( DamageType ) != None )
InDamage *= Modifiers [ 13 ] ;
else if ( Modifiers [ 15 ] < 1 && class < KFDT _Toxic > ( DamageType ) != None )
InDamage = Max ( InDamage * Modifiers [ 15 ] , 1 ) ; // Do at least 1 damage.
else if ( Modifiers [ 16 ] < 1 && class < KFDT _Sonic > ( DamageType ) != None )
InDamage = Max ( InDamage * Modifiers [ 16 ] , 1 ) ;
else if ( Modifiers [ 17 ] < 1 && class < KFDT _Fire > ( DamageType ) != None )
InDamage = Max ( InDamage * Modifiers [ 17 ] , 1 ) ;
if ( Modifiers [ 18 ] < 1 && InstigatedBy != None && InstigatedBy != PlayerOwner )
InDamage = Max ( InDamage * Modifiers [ 18 ] , 1 ) ;
}
}
simulated function ModifyRecoil ( out float CurrentRecoilModifier , KFWeapon KFW )
{
if ( IsWeaponOnPerk ( KFW ) )
CurrentRecoilModifier *= Modifiers [ 2 ] ;
}
simulated function ModifySpread ( out float InSpread )
{
InSpread *= Modifiers [ 3 ] ;
}
simulated function ModifyRateOfFire ( out float InRate , KFWeapon KFW )
{
if ( IsWeaponOnPerk ( KFW ) )
InRate *= Modifiers [ 4 ] ;
}
simulated function float GetReloadRateScale ( KFWeapon KFW )
{
return ( IsWeaponOnPerk ( KFW ) ? Modifiers [ 5 ] : 1. f ) ;
}
function ModifyHealth ( out int InHealth )
{
InHealth *= Modifiers [ 6 ] ;
}
function ModifyArmor ( out byte MaxArmor )
{
MaxArmor = Min ( MaxArmor + Modifiers [ 14 ] , 255 ) ;
}
function float GetKnockdownPowerModifier ( )
{
return Modifiers [ 7 ] ;
}
function float GetStunPowerModifier ( optional class < DamageType > DamageType , optional byte HitZoneIdx )
{
return Modifiers [ 7 ] ;
}
simulated function ModifyMeleeAttackSpeed ( out float InDuration ) ;
function AddDefaultInventory ( KFPawn P )
{
local int i ;
if ( PrimaryWeapon != None )
P . DefaultInventory . AddItem ( PrimaryWeapon ) ;
P . DefaultInventory . AddItem ( PrimaryMelee ) ;
if ( KFInventoryManager ( P . InvManager ) != None )
KFInventoryManager ( P . InvManager ) . MaxCarryBlocks = KFInventoryManager ( P . InvManager ) . Default . MaxCarryBlocks + Modifiers [ 10 ] ;
for ( i = 0 ; i < PerkTraits . Length ; ++ i )
{
if ( PerkTraits [ i ] . CurrentLevel > 0 )
PerkTraits [ i ] . TraitType . Static . AddDefaultInventory ( P , Self , PerkTraits [ i ] . CurrentLevel , PerkTraits [ i ] . Data ) ;
}
}
simulated function ModifyWeldingRate ( out float FastenRate , out float UnfastenRate )
{
FastenRate *= Modifiers [ 8 ] ;
UnfastenRate *= Modifiers [ 8 ] ;
}
function bool RepairArmor ( Pawn HealTarget )
{
return false ;
}
function bool ModifyHealAmount ( out float HealAmount )
{
HealAmount *= Modifiers [ 9 ] ;
return false ;
}
simulated function ModifyMagSizeAndNumber ( KFWeapon KFW , out byte MagazineCapacity , optional array < Class < KFPerk > > WeaponPerkClass , optional bool bSecondary = false , optional name WeaponClassname )
{
if ( MagazineCapacity > 2 && ( KFW == None ? WeaponPerkClass . Find ( BasePerk ) >= 0 : IsWeaponOnPerk ( KFW ) ) ) // Skip boomstick for this.
MagazineCapacity = Min ( MagazineCapacity * Modifiers [ 10 ] , 255 ) ;
}
simulated function ModifySpareAmmoAmount ( KFWeapon KFW , out int PrimarySpareAmmo , optional const out STraderItem TraderItem , optional bool bSecondary )
{
if ( KFW == None ? TraderItem . AssociatedPerkClasses . Find ( BasePerk ) >= 0 : IsWeaponOnPerk ( KFW ) )
PrimarySpareAmmo *= Modifiers [ 11 ] ;
}
simulated function bool ShouldMagSizeModifySpareAmmo ( KFWeapon KFW , optional Class < KFPerk > WeaponPerkClass )
{
return ( KFW == None ? WeaponPerkClass == BasePerk : IsWeaponOnPerk ( KFW ) ) ;
}
final function UpdateAmmoStatus ( InventoryManager Inv )
{
local KFWeapon W ;
foreach Inv . InventoryActors ( class 'KFWeapon' , W )
{
if ( IsWeaponOnPerk ( W ) )
W . ReInitializeAmmoCounts ( PerkManager ) ;
}
}
2020-07-07 14:04:37 +00:00
simulated function ModifyHealerRechargeTime ( out float RechargeRate )
{
RechargeRate *= Modifiers [ 20 ] ;
}
2017-10-20 02:00:49 +00:00
simulated function DrawSpecialPerkHUD ( Canvas C )
{
if ( EnemyHealthRange > 0 && PlayerOwner != None && KFPawn _Human ( PlayerOwner . Pawn ) != None )
DrawEnemyHealth ( C ) ;
}
simulated final function DrawEnemyHealth ( Canvas C )
{
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 ] )
{
if ( KFPM . IsAliveAndWell ( ) && ` TimeSince(KFPM.Mesh.LastRenderTime)<0.1f && KFPM.CanShowHealth() && KFPM.GetTeamNum()!=0 && (X Dot (KFPM.Location - CameraLocation))>0 )
DrawZedHealthbar ( C , KFPM , CameraLocation ) ;
}
}
simulated final function DrawZedHealthbar ( Canvas C , KFPawn _Monster KFPM , vector CameraLocation )
{
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 ) ;
if ( KFPM . bCrawler && KFPM . Floor . Z <= - 0.7 f && KFPM . Physics == PHYS _Spider )
{
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 ) ;
if ( ScreenPos . X < 0 || ScreenPos . X > C . SizeX || ScreenPos . Y < 0 || ScreenPos . Y > C . SizeY || ! FastTrace ( TargetLocation , CameraLocation ) )
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 ) ;
}
function PlayerKilled ( KFPawn _Monster Victim , class < DamageType > DamageType ) ;
function ModifyBloatBileDoT ( out float DoTScaler )
{
DoTScaler = Modifiers [ 15 ] ;
}
simulated function bool GetIsUberAmmoActive ( KFWeapon KFW )
{
return false ;
}
function UpdatePerkHeadShots ( ImpactInfo Impact , class < DamageType > DamageType , int NumHit ) ;
function CheckForAirborneAgent ( KFPawn HealTarget , class < DamageType > DamType , int HealAmount ) ;
simulated function float GetZedTimeModifier ( KFWeapon W )
{
return 0. f ;
}
simulated function bool GetUsingTactialReload ( KFWeapon KFW )
{
return ( bTacticalReload && IsWeaponOnPerk ( KFW ) ) ;
}
simulated function float GetIronSightSpeedModifier ( KFWeapon KFW )
{
return 1. f ;
}
2017-10-20 07:02:53 +00:00
function OnWaveEnded ( ) ;
function NotifyZedTimeStarted ( ) ;
simulated function float GetZedTimeExtensions ( byte Level )
{
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
DefPerkStats ( 0 ) = ( MaxValue = 50 , CostPerValue = 1 , StatType = "Speed" , UIName = "Movement Speed (+&%)" , Progress = 0.4 )
DefPerkStats ( 1 ) = ( MaxValue = 1000 , CostPerValue = 1 , StatType = "Damage" , UIName = "Perk Damage (+&%)" , Progress = 0.5 )
2020-07-07 14:04:37 +00:00
DefPerkStats ( 2 ) = ( MaxValue = 90 , CostPerValue = 1 , StatType = "Recoil" , UIName = "Fire Recoil Reduce (+&%)" , Progress = 1 )
DefPerkStats ( 3 ) = ( MaxValue = 80 , CostPerValue = 1 , StatType = "Spread" , UIName = "Fire Spread Reduce (+&%)" , Progress = 0.75 )
2017-10-20 02:00:49 +00:00
DefPerkStats ( 4 ) = ( MaxValue = 1000 , CostPerValue = 1 , StatType = "Rate" , UIName = "Perk Rate of Fire (+&%)" , Progress = 0.5 )
DefPerkStats ( 5 ) = ( MaxValue = 1000 , CostPerValue = 1 , StatType = "Reload" , UIName = "Perk Reload Time (-&%)" , Progress = 0.5 )
2017-10-26 14:49:12 +00:00
DefPerkStats ( 6 ) = ( MaxValue = 150 , CostPerValue = 1 , StatType = "Health" , UIName = "Health (+&HP)" , Progress = 1 )
2017-10-20 02:00:49 +00:00
DefPerkStats ( 7 ) = ( MaxValue = 100 , CostPerValue = 1 , StatType = "KnockDown" , UIName = "Knockback (+&%)" , Progress = 1 )
DefPerkStats ( 8 ) = ( MaxValue = 200 , CostPerValue = 1 , StatType = "Welder" , UIName = "Welding Rate (+&%)" , bHiddenConfig = true , Progress = 0.5 )
DefPerkStats ( 9 ) = ( MaxValue = 400 , CostPerValue = 1 , StatType = "Heal" , UIName = "Heal Efficiency (+&%)" , bHiddenConfig = true , Progress = 0.5 )
DefPerkStats ( 10 ) = ( MaxValue = 400 , CostPerValue = 1 , StatType = "Mag" , UIName = "Magazine Capacity (+&%)" , Progress = 1 )
DefPerkStats ( 11 ) = ( MaxValue = 500 , CostPerValue = 1 , StatType = "Spare" , UIName = "Max Ammo (+&%)" , Progress = 1 )
DefPerkStats ( 12 ) = ( MaxValue = 1000 , CostPerValue = 1 , StatType = "OffDamage" , UIName = "Off-Perk Damage (+&%)" , Progress = 0.25 )
DefPerkStats ( 13 ) = ( MaxValue = 1000 , CostPerValue = 1 , StatType = "SelfDamage" , UIName = "Self Damage Reduction (+&%)" , Progress = 1 , bHiddenConfig = true )
DefPerkStats ( 14 ) = ( MaxValue = 150 , CostPerValue = 1 , StatType = "Armor" , UIName = "Armor (+&)" , Progress = 1 )
DefPerkStats ( 15 ) = ( MaxValue = 1000 , CostPerValue = 1 , StatType = "PoisonDmg" , UIName = "Toxic Resistance (+&%)" , Progress = 1.5 , bHiddenConfig = true )
DefPerkStats ( 16 ) = ( MaxValue = 1000 , CostPerValue = 1 , StatType = "SonicDmg" , UIName = "Sonic Resistance (+&%)" , Progress = 1.5 , bHiddenConfig = true )
DefPerkStats ( 17 ) = ( MaxValue = 1000 , CostPerValue = 1 , StatType = "FireDmg" , UIName = "Fire Resistance (+&%)" , Progress = 1.5 , bHiddenConfig = true )
DefPerkStats ( 18 ) = ( MaxValue = 500 , CostPerValue = 1 , StatType = "AllDmg" , UIName = "Zed Damage Reduction (+&%)" , Progress = 0.25 )
2020-07-06 17:45:02 +00:00
DefPerkStats ( 19 ) = ( MaxValue = 500 , CostPerValue = 1 , StatType = "HeadDamage" , UIName = "Perk Head Damage (+&%)" , Progress = 1 , bHiddenConfig = true )
2020-07-07 14:04:37 +00:00
DefPerkStats ( 20 ) = ( MaxValue = 200 , CostPerValue = 1 , StatType = "HealRecharge" , UIName = "Syringe Recharge Rate (+&%)" , 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 )
}