KF2-Server-Extension/ServerExt/Classes/Ext_PerkBase.uc
2021-08-21 07:25:27 -07:00

1583 lines
45 KiB
Ucode

// 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() localized 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.
MaxPrestige,
MinimalDataLevel; // Maximum prestige level.
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;
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;
reliable client simulated function string UIName(FDefPerkStat DefPerkStat)
{
switch (DefPerkStat.StatType)
{
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;
case name("SelfDamage"): return StatSelfDamage;
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;
case name("HeadDamage"): return StatHeadDamage;
case name("HealRecharge"): return StatHealRecharge;
}
return "";
}
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)
{
if (class<KFPerk_Survivalist>(BasePerk) != None)
return true;
//if (W.AllowedForAllPerks())
// return true;
return W!=None && W.GetWeaponPerkClass(BasePerk)==BasePerk;
}
simulated static function string GetPerkIconPath(int Level)
{
return "img://"$PathName(default.PerkIcon);
}
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 = UIName(DefPerkStats[i]);
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 = UIName(Class'Ext_PerkBase'.Default.DefPerkStats[i]);
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 = UIName(DefPerkStats[i]);
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 = UIName(Class'Ext_PerkBase'.Default.DefPerkStats[i]);
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);
// if (MinimalDataLevel > 0)
// {
// i = GetNeededExp(MinimalDataLevel-1)
// if (i > CurrentEXP)
// CurrentEXP = i
// }
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;
if (MinimalDataLevel > 0)
{
i = GetNeededExp(MinimalDataLevel-1);
if (i > CurrentEXP)
CurrentEXP = i;
}
// 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;
Default.MinimalDataLevel = 0;
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.
else if (OldVer<=13)
AddStatsCfg(19); // Add HeadDamage and HealRecharge
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);
case 'MinimalDataLevel':
return string(Default.MinimalDataLevel);
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;
case 'MinimalDataLevel':
Default.MinimalDataLevel = int(Value); break;
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;
case 'HeadDamage':
Modifiers[19] = Value*Progress;
break;
case 'HealRecharge':
Modifiers[20] = 1.f / (1.f+Value*Progress);
break;
}
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))))
{
if (HitZoneIdx == 0)
InDamage *= (Modifiers[1] + Modifiers[19]);
else
InDamage *= Modifiers[1];
}
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);
}
simulated function float GetCameraViewShakeModifier(KFWeapon KFW)
{
return Modifiers[2];
}
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 int 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);
}
}
simulated function ModifyHealerRechargeTime(out float RechargeRate)
{
RechargeRate *= Modifiers[20];
}
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.7f && 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;
}
function OnWaveEnded();
function NotifyZedTimeStarted();
simulated function float GetZedTimeExtensions(byte Level)
{
return 1.f;
}
defaultproperties
{
CurrentConfigVer=14
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)"))
// WebConfigs.Add((PropType=0,PropName="MinimalDataLevel",UIName="Minimal Real Level",UIDesc="Minimal level for new players or who loads from saves"))
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)
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)
Modifiers.Add(0.f)
Modifiers.Add(1.f)
EnemyDistDraw.Add(500)
EnemyDistDraw.Add(700)
EnemyDistDraw.Add(1000)
EnemyDistDraw.Add(1600)
}