• Please make sure you are familiar with the forum rules. You can find them here: https://forums.tripwireinteractive.com/index.php?threads/forum-rules.2334636/

Code Custom Perk Help

FluX

Grizzled Veteran
Oct 26, 2010
5,378
234
www.fluxiserver.co.uk
Hi,

1.) What I want to do is make a custom perk for ServerPerksv4 which will only be available for specific people. How would I do this?

2.) How would I exactly make new requirements?

3.) How exactly do you make the requirements so specific i.e. damage is some kind of equation?

Please get back to me on this cause it would be nice to have my own perk for my community some time soon as it's what I promised them for the custom server I have running.

Cheers in advance.
 
Adding a new stat:

StatsObject.uc

Keeps track of all stats and saves/retrieves them. There's a big list of int variables at the top, containing all the stats you're already familiar with. Add a new stat like "KnifeDamageStat".

Scroll down and you'll see GetSaveData wich lines up all stats for saving. Add your new stat like this:

Code:
    Result = Result$","$KnifeDamageStat;
Go to SetSaveData and add the following code in the right order (The order is defined by where you added the DamageStat above in GetSaveData)

Code:
    KnifeDamageStat = GetNextValue(S);
ServerStStats.uc

This code keeps track of all the "add something to the stats" functions. As well of wich stats should get replicated in the ClientPerkRepLink. Add a new function like this one:

Code:
function AddKnifeDamage(int Amount)
{
    bHasChanged = true;
    Rep.RKnifeDamageStat+=Amount;
    if( MyStatsObject!=None )
        MyStatsObject.KnifeDamageStat+=Amount;
    DelayedStatCheck();
}
and update final function RepCopyStats, adding this line:

Code:
    Rep.RKnifeDamageStat = MyStatsObject.KnifeDamageStat;
ClientPerkRepLink.uc

This code defines all the stats the client receives from the server. Add your new stat in the long list of R***Stats like this: RKnifeDamageStat. Scroll down to the replication and add it there aswell.

SrStatList.uc

Responsible for all the drawing in the "stats" tab in the menu.

Go to InitList and add your new stat. MY server uses a custom stats object so I have a different order:

Code:
    StatProgress[9] = L.RKnifeDamageStat;
Go down to the defaultproperties and add a name, as well as increasing ItemCount by one.




To track your knife damage stat, you need to replace the Knife in the game with a new one that refers to new firing modes. These firing modes need a new hitDamageClass that looks like this:

Code:
class NewDamTypeKnife extends DamTypeKnife
    abstract;

static function AwardDamage(KFSteamStatsAndAchievements KFStatsAndAchievements, int Amount)
{
    ServerStStats(KFStatsAndAchievements).AddKnifeDamage(Amount);
}

defaultproperties
{
}


Adding a new perk:

Just write a new SRVeterancyTypes like this one:

Code:
class SRVetTank extends SRVeterancyTypes
    abstract;

static function int GetPerkProgressInt( ClientPerkRepLink StatOther, out int FinalInt, byte CurLevel, byte ReqNum )
{
    switch( CurLevel )
    {
        case 0:
            FinalInt = 10000;
            break;
        case 1:
            FinalInt = 25000;
            break;
        case 2:
            FinalInt = 100000;
            break;
        case 3:
            FinalInt = 500000;
            break;
        case 4:
            FinalInt = 1500000;
            break;
        case 5:
            FinalInt = 3500000;
            break;
        case 6:
            FinalInt = 5500000;
            break;
        default:
            if (CurLevel < 9)
                FinalInt = 5500000 + GetDoubleScaling(CurLevel, 250000);
            else if (CurLevel >= 9 && CurLevel < 19)
                FinalInt = 11000000 + GetDoubleScaling(CurLevel, 500000);
            else if (CurLevel >= 19)
                FinalInt = 15000000 + GetDoubleScaling(CurLevel, 750000);
    }
    return Min(StatOther.RKnifeDamageStat, FinalInt);
}

static function int ReduceDamage(KFPlayerReplicationInfo KFPRI, KFPawn Injured, KFMonster DamageTaker, int InDamage, class<DamageType> DmgType)
{
    return float(InDamage) * 0.85;
}

static function string GetCustomLevelInfo( byte Level )
{
    local string S;

    S = Default.CustomLevelInfo;
    return S;
}

defaultproperties
{
     CustomLevelInfo="15% less damage from enemy attacks"
     Requirements(0)="Deal damage with the knife"
     PerkIndex=4
     OnHUDIcon=Texture'KillingFloorHUD.Perks.Perk_Berserker'
     OnHUDGoldIcon=Texture'KillingFloor2HUD.Perk_Icons.Perk_Berserker_Gold'
     VeterancyName="Tank"
}

And add it to your config file.
 
Last edited:
Upvote 0
Thanks ever so much, this will be very useful to use. May take some time trying to change it as im new to KF coding but have seen some C++ and Unreal script before.

1.) What I want to do is make a custom perk for ServerPerksv4 which will only be available for specific people. How would I do this?
By any chance you know the answer to this? I would like to make some perks accessible for only my community members if possible.
 
Upvote 0
Shrug-smiley5.gif


I guess you could change SRVeterancyTypes to include a new boolean property: restricted. Then you change the perk switching functions to check if that property is set. If it is set you could check something in the KFPRI and then return "You can't access that perk, subscribe at @@@" or just accept the perk change request. I don't know what you could check for. Maybe the Steam ID is stored somewhere in there.
 
Upvote 0
Yeah, that would work. Of course you'd have to keep that ini up to date and the security measure is pretty low. Looking at ServerPerks again, the file that stores the stats has some kind of hash:

[84159f68256957d3d67b35cb78cb770f StatsObject]
PlayerName=Glider⠠⠵
So obviously there is some way to identify people. You could add a new stat that can't be raised in the game. You could then manually adjust the save file for your members and code it so that only people with that stat can select that perk.

For the latter variant you'd make changes in ServerSelectPerk of ServerStStats.uc. Add some check like if ( VetType == class'SRVetMyCustomPerk' && MyStatsObject.NewStatToIdentify == 1 ) or something like that.
 
Last edited:
Upvote 0
Code:
final function ServerSelectPerk( Class<SRVeterancyTypes> VetType )
{
 local byte i;
 if( !bStatsReadyNow )
  return;
 if( VetType==None || !SelectionOK(VetType) )
 {
  if( !bSwitchIsOKNow )
   PlayerOwner.ClientMessage("Your desired perk is unavailable.");
  return;
 }
 else if( KFPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).ClientVeteranSkill==VetType )
 {
  if( SelectingPerk!=None )
  {
   SelectingPerk = None;
   PlayerOwner.ClientMessage("You will remain the same perk now.");
  }
  return;
 }
 if( MyStatsObject!=None )
  MyStatsObject.SetSelectedPerk(string(VetType));
 if( !Level.Game.bWaitingToStartMatch && !bSwitchIsOKNow && (KFGameReplicationInfo(Level.GRI).bWaveInProgress || bHadSwitchedVet) )
 {
  PlayerOwner.ClientMessage(Repl(PlayerOwner.YouWillBecomePerkString, "%Perk%", VetType.Default.VeterancyName));
  SelectingPerk = VetType;
  return;
 }
 if( !bSwitchIsOKNow )
  bHadSwitchedVet = true;
 SelectingPerk = None;
 for( i=0; i<Rep.CachePerks.Length; i++ )
 {
  if( Rep.CachePerks[i].PerkClass==VetType )
  {
   if( Rep.CachePerks[i].CurrentLevel==0 )
    return;
   KFPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).ClientVeteranSkill = VetType;
   KFPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).ClientVeteranSkillLevel = Rep.CachePerks[i].CurrentLevel-1;
   if( KFHumanPawn(PlayerOwner.Pawn)!=None )
   {
    KFHumanPawn(PlayerOwner.Pawn).VeterancyChanged();
    DropToCarryLimit(KFHumanPawn(PlayerOwner.Pawn));
   }
  }
 }
}

Where would I put the could below exactly to affect specific perks (more then one perk)?
Code:
if ( VetType == class'SRVetMyCustomPerk' && MyStatsObject.IsFsMember == 1 )

And just so you know I have got a working custom medic perk made but im lost on how they can get some of the numbers out of the equations that is made. For example:

Code:
return 1.05 + FMin(0.05 * float(KFPRI.ClientVeteranSkillLevel - 2),0.95); // Moves up to 25% faster
Code:
return 1.0 + (0.20 * FMin(KFPRI.ClientVeteranSkillLevel, 5.0)); // 100% increase in MP7 Medic weapon ammo carry

Im guessing it's cause I don't know what this FMin is.
 
Upvote 0
Code:
final function ServerSelectPerk( Class<SRVeterancyTypes> VetType )
{
 local byte i;
 if( !bStatsReadyNow )
  return;
 if( VetType==None || !SelectionOK(VetType) [B]|| ( VetType == class'SRVetMyCustomPerk' && MyStatsObject.IsFsMember != 1 )[/B])
 {
  if( !bSwitchIsOKNow )
   PlayerOwner.ClientMessage("Your desired perk is unavailable.");
  return;
 }
 else if( KFPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).ClientVeteranSkill==VetType )
 {
  if( SelectingPerk!=None )
  {
   SelectingPerk = None;
   PlayerOwner.ClientMessage("You will remain the same perk now.");
  }
  return;
 }
 if( MyStatsObject!=None )
  MyStatsObject.SetSelectedPerk(string(VetType));
 if( !Level.Game.bWaitingToStartMatch && !bSwitchIsOKNow && (KFGameReplicationInfo(Level.GRI).bWaveInProgress || bHadSwitchedVet) )
 {
  PlayerOwner.ClientMessage(Repl(PlayerOwner.YouWillBecomePerkString, "%Perk%", VetType.Default.VeterancyName));
  SelectingPerk = VetType;
  return;
 }
 if( !bSwitchIsOKNow )
  bHadSwitchedVet = true;
 SelectingPerk = None;
 for( i=0; i<Rep.CachePerks.Length; i++ )
 {
  if( Rep.CachePerks[i].PerkClass==VetType )
  {
   if( Rep.CachePerks[i].CurrentLevel==0 )
    return;
   KFPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).ClientVeteranSkill = VetType;
   KFPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).ClientVeteranSkillLevel = Rep.CachePerks[i].CurrentLevel-1;
   if( KFHumanPawn(PlayerOwner.Pawn)!=None )
   {
    KFHumanPawn(PlayerOwner.Pawn).VeterancyChanged();
    DropToCarryLimit(KFHumanPawn(PlayerOwner.Pawn));
   }
  }
 }
}
Checks if the veterancy is invalid or if the veterancy is your custom one and that guy is not a member.

http://wiki.beyondunreal.com/Legacy:Global_Function said:
float FMin (float A, float B) [static] Returns the lower of the two values.
 
Upvote 0
To make it short they could of just changed it from
Code:
static function float GetMovementSpeedModifier(KFPlayerReplicationInfo KFPRI)
{
 if ( KFPRI.ClientVeteranSkillLevel <= 1 )
  return 1.0;
 return 1.05 + FMin(0.05 * float(KFPRI.ClientVeteranSkillLevel - 2),0.95); // Moves up to 25% faster
}

to

Code:
static function float GetMovementSpeedModifier(KFPlayerReplicationInfo KFPRI)
{
 if ( KFPRI.ClientVeteranSkillLevel <= 1 )
  return 1.0;
 return 1.25; // Moves up to 25% faster
}

Would that work because is there really any need for the above to be put when this (for what I can see) comes out with the same outcome? 1.0 = 100% speed im guessing so it's standard, 1.25 being 125%.
 
Upvote 0
You serious?

Code:
static function float GetMovementSpeedModifier(KFPlayerReplicationInfo KFPRI)
{
 if ( KFPRI.ClientVeteranSkillLevel <= 1 )
  return 1.0;
 return 1.25; // Moves up to 25% faster
}
Level 0: 1.0
Level 1: 1.0
Level 2: 1.25
Level n: 1.25

What we want though is a slow increase in movement speed.

Code:
static function float GetMovementSpeedModifier(KFPlayerReplicationInfo KFPRI)
{
 if ( KFPRI.ClientVeteranSkillLevel <= 1 )
  return 1.0;
 return 1.05 + FMin(0.05 * float(KFPRI.ClientVeteranSkillLevel - 2),0.95); // Moves up to 25% faster
}
Level 0: 1.0
Level 1: 1.0
Level 2: 1.05 + (0.05 * (2 - 2)) = 1.05
Level 3: 1.05 + (0.05 * (3 - 2)) = 1.1
Level 4: 1.05 + (0.05 * (4 - 2)) = 1.15
Level 5: 1.05 + (0.05 * (5 - 2)) = 1.2

and so on.
 
Last edited:
Upvote 0
Code:
static function int AddDamage(KFPlayerReplicationInfo KFPRI, KFMonster Injured, KFPawn DamageTaker, int InDamage, class<DamageType> DmgType)
{
    if( class<KFWeaponDamageType>(DmgType) != none  )
    {
        return float(InDamage) * (1.0 + (0.10 * float(KFPRI.ClientVeteranSkillLevel)));
    }

    return InDamage;
}

This will give 10% more damage each level with every weapon.
 
Upvote 0