• 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/
  • Weve updated the Tripwire Privacy Notice under our Policies to be clearer about our use of customer information to come in line with the EU General Data Protection Regulation (GDPR) rules that come into force today (25th May 2018). The following are highlights of our changes:


    We've incorporated the relevant concepts from the GDPR including joining the EU and Swiss Privacy Shield framework. We've added explanations for why and how Tripwire processes customer data and the types of data that we process, as well as information about your data protection rights.



    For more information about our privacy practices, please review the new Privacy Policy found here: https://tripwireinteractive.com/#/privacy-notice

Custom Perk Help

FluX

FNG / Fresh Meat
Oct 26, 2010
5,386
231
0
www.fluxiservice.com
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.
 

Excalibolg

FNG / Fresh Meat
May 3, 2009
143
27
0
KF-BioticsLab
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:

FluX

FNG / Fresh Meat
Oct 26, 2010
5,386
231
0
www.fluxiservice.com
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.
 

Excalibolg

FNG / Fresh Meat
May 3, 2009
143
27
0
KF-BioticsLab


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.
 

FluX

FNG / Fresh Meat
Oct 26, 2010
5,386
231
0
www.fluxiservice.com
Anyway that I could get an ini file that has a list of names that it will check on server startup to see which nicknames the perk is allowed to?

If this isn't possible could you giv us a snippet of the code that you thought of? Im new to KF scripting completely. Im sorry for wasting anyone's time but there's always somewhere to start ;)
 

Excalibolg

FNG / Fresh Meat
May 3, 2009
143
27
0
KF-BioticsLab
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:

FluX

FNG / Fresh Meat
Oct 26, 2010
5,386
231
0
www.fluxiservice.com
Thank you ever so much mate! If I have any problems will you be able to help me out? I don't like to bug people as I try to do everything myself but if it's really needed, that ok? Sorry for bugging and thanks again.
 

FluX

FNG / Fresh Meat
Oct 26, 2010
5,386
231
0
www.fluxiservice.com
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.
 

Excalibolg

FNG / Fresh Meat
May 3, 2009
143
27
0
KF-BioticsLab
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.
 

FluX

FNG / Fresh Meat
Oct 26, 2010
5,386
231
0
www.fluxiservice.com
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%.
 

FluX

FNG / Fresh Meat
Oct 26, 2010
5,386
231
0
www.fluxiservice.com
Why don't they put my code but return 2.00 instead? wouldn't that come out with the same outcome and much less coding throughout the files?
 

Excalibolg

FNG / Fresh Meat
May 3, 2009
143
27
0
KF-BioticsLab
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:

FluX

FNG / Fresh Meat
Oct 26, 2010
5,386
231
0
www.fluxiservice.com
Ok now it makes much more sense which also leaves less code in the file. I also read your last comment wrong before which is why I may have thought it would of been better they way I explained.
 

Excalibolg

FNG / Fresh Meat
May 3, 2009
143
27
0
KF-BioticsLab
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.
 

FluX

FNG / Fresh Meat
Oct 26, 2010
5,386
231
0
www.fluxiservice.com
Sorry for the confusion. What I want to do is make a stat that will record ALL damage you do with ANY weapon only with this specific perk. I don't exactly want to ajust all weapons to add to this one stat when used as that will make it way too big a file for such a small thing for one perk.
 

krispyk

FNG / Fresh Meat
Mar 15, 2010
208
31
0
Thanks for posting this tutorial. How do we create the custom perk icons? Are there tutorials out there? I mostly work on the coding side of things. Thanks.