Added base ServerExt and ServerExtMut
This commit is contained in:
parent
08fbb7c91c
commit
439d1b2ab2
231
ServerExt/Classes/ExtAutoPurchaseHelper.uc
Normal file
231
ServerExt/Classes/ExtAutoPurchaseHelper.uc
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
class ExtAutoPurchaseHelper extends KFAutoPurchaseHelper within ExtPlayerController;
|
||||||
|
|
||||||
|
final function class<KFPerk> GetBasePerk()
|
||||||
|
{
|
||||||
|
return (ActivePerkManager!=None && ActivePerkManager.CurrentPerk!=None) ? ActivePerkManager.CurrentPerk.BasePerk : None;
|
||||||
|
}
|
||||||
|
final function Ext_PerkBase GetExtPerk()
|
||||||
|
{
|
||||||
|
return ActivePerkManager!=None ? ActivePerkManager.CurrentPerk : None;
|
||||||
|
}
|
||||||
|
|
||||||
|
function DoAutoPurchase()
|
||||||
|
{
|
||||||
|
local int PotentialDosh, i;
|
||||||
|
local Array <STraderItem> OnPerkWeapons;
|
||||||
|
local STraderItem TopTierWeapon;
|
||||||
|
local int ItemIndex;
|
||||||
|
local bool bSecondaryWeaponPurchased;
|
||||||
|
local bool bUpgradeSuccess;
|
||||||
|
local bool bAutoFillPurchasedItem;
|
||||||
|
local string AutoFillMessageString;
|
||||||
|
local Ext_PerkBase EP;
|
||||||
|
|
||||||
|
GetTraderItems();
|
||||||
|
EP = GetExtPerk();
|
||||||
|
|
||||||
|
if( EP==None || EP.AutoBuyLoadOutPath.length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for( i = 0; i<EP.AutoBuyLoadOutPath.length; i++ )
|
||||||
|
{
|
||||||
|
ItemIndex = TraderItems.SaleItems.Find('WeaponDef', EP.AutoBuyLoadOutPath[i]);
|
||||||
|
if(ItemIndex != INDEX_NONE)
|
||||||
|
OnPerkWeapons.AddItem(TraderItems.SaleItems[ItemIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SellOffPerkWeapons();
|
||||||
|
|
||||||
|
TopTierWeapon = GetTopTierWeapon(OnPerkWeapons);
|
||||||
|
//can I afford my top teir without selling my current weapon?
|
||||||
|
if(!DoIOwnThisWeapon(TopTierWeapon) && GetCanAfford( GetAdjustedBuyPriceFor(TopTierWeapon) + DoshBuffer ) && CanCarry( TopTierWeapon ) )
|
||||||
|
{
|
||||||
|
bUpgradeSuccess = AttemptUpgrade(TotalDosh, OnPerkWeapons, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PotentialDosh = GetPotentialDosh();
|
||||||
|
bUpgradeSuccess = AttemptUpgrade(PotentialDosh+TotalDosh, OnPerkWeapons);
|
||||||
|
}
|
||||||
|
|
||||||
|
bAutoFillPurchasedItem = StartAutoFill();
|
||||||
|
if(DoIOwnThisWeapon(TopTierWeapon))
|
||||||
|
{
|
||||||
|
while(AttemptToPurchaseNextLowerTier(TotalDosh, OnPerkWeapons))
|
||||||
|
{
|
||||||
|
bSecondaryWeaponPurchased = true;
|
||||||
|
AttemptToPurchaseNextLowerTier(TotalDosh, OnPerkWeapons);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MyKFIM.ServerCloseTraderMenu();
|
||||||
|
|
||||||
|
if(bUpgradeSuccess)
|
||||||
|
{
|
||||||
|
AutoFillMessageString = class'KFCommon_LocalizedStrings'.default.WeaponUpgradeComepleteString;
|
||||||
|
}
|
||||||
|
else if(bSecondaryWeaponPurchased)
|
||||||
|
{
|
||||||
|
AutoFillMessageString = class'KFCommon_LocalizedStrings'.default.SecondaryWeaponPurchasedString;
|
||||||
|
}
|
||||||
|
else if(bAutoFillPurchasedItem)
|
||||||
|
{
|
||||||
|
AutoFillMessageString = class'KFCommon_LocalizedStrings'.default.AutoFillCompleteString;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AutoFillMessageString = class'KFCommon_LocalizedStrings'.default.NoItemsPurchasedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(MyGFxHUD != none)
|
||||||
|
{
|
||||||
|
MyGFxHUD.ShowNonCriticalMessage( class'KFCommon_LocalizedStrings'.default.AutoTradeCompleteString$AutoFillMessageString );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function SellOnPerkWeapons()
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
local class<KFPerk> Perk;
|
||||||
|
|
||||||
|
Perk = GetBasePerk();
|
||||||
|
if( Perk!=None )
|
||||||
|
{
|
||||||
|
for (i = 0; i < OwnedItemList.length; i++)
|
||||||
|
{
|
||||||
|
if( OwnedItemList[i].DefaultItem.AssociatedPerkClasses.Find(Perk)!=INDEX_NONE && OwnedItemList[i].DefaultItem.BlocksRequired != -1)
|
||||||
|
{
|
||||||
|
SellWeapon(OwnedItemList[i], i);
|
||||||
|
i=-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function SellOffPerkWeapons()
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
local Ext_PerkBase EP;
|
||||||
|
|
||||||
|
EP = GetExtPerk();
|
||||||
|
|
||||||
|
for (i = 0; i < OwnedItemList.length; i++)
|
||||||
|
{
|
||||||
|
if( OwnedItemList[i].DefaultItem.AssociatedPerkClasses.Find(EP.BasePerk)==INDEX_NONE && OwnedItemList[i].DefaultItem.BlocksRequired != -1 && OwnedItemList[i].SellPrice != 0 )
|
||||||
|
{
|
||||||
|
if(EP.AutoBuyLoadOutPath.Find(OwnedItemList[i].DefaultItem.WeaponDef) == INDEX_NONE)
|
||||||
|
{
|
||||||
|
SellWeapon(OwnedItemList[i], i);
|
||||||
|
i=-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function InitializeOwnedItemList()
|
||||||
|
{
|
||||||
|
local Inventory Inv;
|
||||||
|
local KFWeapon KFW;
|
||||||
|
local KFPawn_Human KFP;
|
||||||
|
local Ext_PerkBase EP;
|
||||||
|
|
||||||
|
EP = GetExtPerk();
|
||||||
|
OwnedItemList.length = 0;
|
||||||
|
|
||||||
|
TraderItems = KFGameReplicationInfo( WorldInfo.GRI ).TraderItems;
|
||||||
|
|
||||||
|
KFP = KFPawn_Human( Pawn );
|
||||||
|
if( KFP != none )
|
||||||
|
{
|
||||||
|
// init armor purchase values
|
||||||
|
ArmorItem.SpareAmmoCount = KFP.Armor;
|
||||||
|
ArmorItem.MaxSpareAmmo = KFP.GetMaxArmor();
|
||||||
|
ArmorItem.AmmoPricePerMagazine = TraderItems.ArmorPrice * ActivePerkManager.GetArmorDiscountMod();
|
||||||
|
ArmorItem.DefaultItem.WeaponDef = TraderItems.ArmorDef;
|
||||||
|
|
||||||
|
// init grenade purchase values
|
||||||
|
GrenadeItem.SpareAmmoCount = MyKFIM.GrenadeCount;
|
||||||
|
GrenadeItem.MaxSpareAmmo = ActivePerkManager.MaxGrenadeCount;
|
||||||
|
GrenadeItem.AmmoPricePerMagazine = TraderItems.GrenadePrice;
|
||||||
|
GrenadeItem.DefaultItem.WeaponDef = EP.GrenadeWeaponDef;
|
||||||
|
|
||||||
|
// @temp: fill in stuff that is normally serialized in the archetype
|
||||||
|
GrenadeItem.DefaultItem.AssociatedPerkClasses[0] = CurrentPerk.Class;
|
||||||
|
|
||||||
|
for ( Inv = MyKFIM.InventoryChain; Inv != none; Inv = Inv.Inventory )
|
||||||
|
{
|
||||||
|
KFW = KFWeapon( Inv );
|
||||||
|
if( KFW != none )
|
||||||
|
{
|
||||||
|
// Set the weapon information and add it to the OwnedItemList
|
||||||
|
SetWeaponInformation( KFW );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(MyGfxManager != none && MyGfxManager.TraderMenu != none)
|
||||||
|
{
|
||||||
|
MyGfxManager.TraderMenu.OwnedItemList = OwnedItemList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function int AddItemByPriority( out SItemInformation WeaponInfo )
|
||||||
|
{
|
||||||
|
local byte i;
|
||||||
|
local byte WeaponGroup, WeaponPriority;
|
||||||
|
local byte BestIndex;
|
||||||
|
local class<KFPerk> Perk;
|
||||||
|
|
||||||
|
Perk = GetBasePerk();
|
||||||
|
|
||||||
|
BestIndex = 0;
|
||||||
|
WeaponGroup = WeaponInfo.DefaultItem.InventoryGroup;
|
||||||
|
WeaponPriority = WeaponInfo.DefaultItem.GroupPriority;
|
||||||
|
|
||||||
|
for( i = 0; i < OwnedItemList.length; i++ )
|
||||||
|
{
|
||||||
|
// If the weapon belongs in the group prior to the current weapon, we've found the spot
|
||||||
|
if( WeaponGroup < OwnedItemList[i].DefaultItem.InventoryGroup )
|
||||||
|
{
|
||||||
|
BestIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if( WeaponGroup == OwnedItemList[i].DefaultItem.InventoryGroup )
|
||||||
|
{
|
||||||
|
if( WeaponPriority > OwnedItemList[i].DefaultItem.GroupPriority )
|
||||||
|
{
|
||||||
|
// if the weapon is in the same group but has a higher priority, we've found the spot
|
||||||
|
BestIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if( WeaponPriority == OwnedItemList[i].DefaultItem.GroupPriority && WeaponInfo.DefaultItem.AssociatedPerkClasses.Find(Perk)>=0 )
|
||||||
|
{
|
||||||
|
// if the weapons have the same priority give the slot to the on perk weapon
|
||||||
|
BestIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Covers the case if this weapon is the only item in the last group
|
||||||
|
BestIndex = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OwnedItemList.InsertItem( BestIndex, WeaponInfo );
|
||||||
|
|
||||||
|
// Add secondary ammo immediately after the main weapon
|
||||||
|
if( WeaponInfo.DefaultItem.WeaponDef.static.UsesSecondaryAmmo() )
|
||||||
|
{
|
||||||
|
WeaponInfo.bIsSecondaryAmmo = true;
|
||||||
|
WeaponInfo.SellPrice = 0;
|
||||||
|
OwnedItemList.InsertItem( BestIndex + 1, WeaponInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( MyGfxManager != none && MyGfxManager.TraderMenu != none )
|
||||||
|
{
|
||||||
|
MyGfxManager.TraderMenu.OwnedItemList = OwnedItemList;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BestIndex;
|
||||||
|
}
|
48
ServerExt/Classes/ExtCharDataInfo.uc
Normal file
48
ServerExt/Classes/ExtCharDataInfo.uc
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
Class ExtCharDataInfo extends Object
|
||||||
|
config(Game)
|
||||||
|
perobjectconfig
|
||||||
|
DependsOn(ExtPlayerReplicationInfo);
|
||||||
|
|
||||||
|
var config byte HeadMeshIndex,HeadSkinIndex,BodyMeshIndex,BodySkinIndex,AttachmentMesh0,AttachmentSkin0,AttachmentMesh1,AttachmentSkin1,AttachmentMesh2,AttachmentSkin2,HasInit;
|
||||||
|
|
||||||
|
final function FMyCustomChar LoadData()
|
||||||
|
{
|
||||||
|
local FMyCustomChar R;
|
||||||
|
|
||||||
|
if( HasInit==0 )
|
||||||
|
{
|
||||||
|
AttachmentMesh0 = 255;
|
||||||
|
AttachmentMesh1 = 255;
|
||||||
|
AttachmentMesh2 = 255;
|
||||||
|
}
|
||||||
|
R.HeadMeshIndex = HeadMeshIndex;
|
||||||
|
R.HeadSkinIndex = HeadSkinIndex;
|
||||||
|
R.BodyMeshIndex = BodyMeshIndex;
|
||||||
|
R.BodySkinIndex = BodySkinIndex;
|
||||||
|
R.AttachmentMeshIndices[0] = AttachmentMesh0;
|
||||||
|
R.AttachmentSkinIndices[0] = AttachmentSkin0;
|
||||||
|
R.AttachmentMeshIndices[1] = AttachmentMesh1;
|
||||||
|
R.AttachmentSkinIndices[1] = AttachmentSkin1;
|
||||||
|
R.AttachmentMeshIndices[2] = AttachmentMesh2;
|
||||||
|
R.AttachmentSkinIndices[2] = AttachmentSkin2;
|
||||||
|
return R;
|
||||||
|
}
|
||||||
|
final function SaveData( FMyCustomChar R )
|
||||||
|
{
|
||||||
|
HeadMeshIndex = R.HeadMeshIndex;
|
||||||
|
HeadSkinIndex = R.HeadSkinIndex;
|
||||||
|
BodyMeshIndex = R.BodyMeshIndex;
|
||||||
|
BodySkinIndex = R.BodySkinIndex;
|
||||||
|
AttachmentMesh0 = R.AttachmentMeshIndices[0];
|
||||||
|
AttachmentSkin0 = R.AttachmentSkinIndices[0];
|
||||||
|
AttachmentMesh1 = R.AttachmentMeshIndices[1];
|
||||||
|
AttachmentSkin1 = R.AttachmentSkinIndices[1];
|
||||||
|
AttachmentMesh2 = R.AttachmentMeshIndices[2];
|
||||||
|
AttachmentSkin2 = R.AttachmentSkinIndices[2];
|
||||||
|
HasInit = 1;
|
||||||
|
SaveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
}
|
467
ServerExt/Classes/ExtCharacterInfo.uc
Normal file
467
ServerExt/Classes/ExtCharacterInfo.uc
Normal file
@ -0,0 +1,467 @@
|
|||||||
|
// Only a helper class to hold code.
|
||||||
|
class ExtCharacterInfo extends Object
|
||||||
|
abstract;
|
||||||
|
|
||||||
|
// Hack fix for not being able to compile materials in run-time.
|
||||||
|
static final function CloneMIC( MaterialInstanceConstant B )
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
local MaterialInstanceConstant M;
|
||||||
|
local LinearColor C;
|
||||||
|
|
||||||
|
M = MaterialInstanceConstant(B.Parent);
|
||||||
|
if( M==None )
|
||||||
|
return;
|
||||||
|
B.SetParent(M.Parent);
|
||||||
|
|
||||||
|
for( i=0; i<M.TextureParameterValues.Length; ++i )
|
||||||
|
if( M.TextureParameterValues[i].ParameterValue!=None )
|
||||||
|
B.SetTextureParameterValue(M.TextureParameterValues[i].ParameterName,M.TextureParameterValues[i].ParameterValue);
|
||||||
|
|
||||||
|
for( i=0; i<M.ScalarParameterValues.Length; ++i )
|
||||||
|
B.SetScalarParameterValue(M.ScalarParameterValues[i].ParameterName,M.ScalarParameterValues[i].ParameterValue);
|
||||||
|
|
||||||
|
for( i=0; i<M.VectorParameterValues.Length; ++i )
|
||||||
|
{
|
||||||
|
C = M.VectorParameterValues[i].ParameterValue;
|
||||||
|
B.SetVectorParameterValue(M.VectorParameterValues[i].ParameterName,C);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function Object SafeLoadObject( string S, Class ObjClass )
|
||||||
|
{
|
||||||
|
local Object O;
|
||||||
|
|
||||||
|
O = FindObject(S,ObjClass);
|
||||||
|
return O!=None ? O : DynamicLoadObject(S,ObjClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the pawns character mesh from it's CharacterInfo, and updates instance of player in map if there is one. */
|
||||||
|
static final function SetCharacterMeshFromArch( KFCharacterInfo_Human C, KFPawn KFP, optional KFPlayerReplicationInfo KFPRI )
|
||||||
|
{
|
||||||
|
local ExtPlayerReplicationInfo EPRI;
|
||||||
|
local int AttachmentIdx, CosmeticMeshIdx;
|
||||||
|
local bool bMaskHeadMesh, bCustom;
|
||||||
|
|
||||||
|
EPRI = ExtPlayerReplicationInfo(KFPRI);
|
||||||
|
if ( KFPRI == none )
|
||||||
|
{
|
||||||
|
`Warn("Does not have a KFPRI" @ C);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bCustom = (EPRI!=None ? EPRI.UsesCustomChar() : false);
|
||||||
|
|
||||||
|
// Body mesh & skin. Index of 255 implies use index 0 (default).
|
||||||
|
SetBodyMeshAndSkin(C,
|
||||||
|
bCustom ? EPRI.CustomCharacter.BodyMeshIndex : KFPRI.RepCustomizationInfo.BodyMeshIndex,
|
||||||
|
bCustom ? EPRI.CustomCharacter.BodySkinIndex : KFPRI.RepCustomizationInfo.BodySkinIndex,
|
||||||
|
KFP);
|
||||||
|
|
||||||
|
// Head mesh & skin. Index of 255 implies use index 0 (default).
|
||||||
|
SetHeadMeshAndSkin(C,
|
||||||
|
bCustom ? EPRI.CustomCharacter.HeadMeshIndex : KFPRI.RepCustomizationInfo.HeadMeshIndex,
|
||||||
|
bCustom ? EPRI.CustomCharacter.HeadSkinIndex : KFPRI.RepCustomizationInfo.HeadSkinIndex,
|
||||||
|
KFP);
|
||||||
|
|
||||||
|
// skip dedicated for purely cosmetic stuff
|
||||||
|
if ( KFP.WorldInfo.NetMode != NM_DedicatedServer )
|
||||||
|
{
|
||||||
|
// Must clear all attachments before trying to attach new ones,
|
||||||
|
// otherwise we might accidentally remove things we're not supposed to
|
||||||
|
for( AttachmentIdx=0; AttachmentIdx < `MAX_COSMETIC_ATTACHMENTS; AttachmentIdx++ )
|
||||||
|
{
|
||||||
|
// Clear any previous attachments from other characters
|
||||||
|
C.DetachAttachment(AttachmentIdx, KFP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cosmetic attachment mesh & skin. Index of 255 implies don't use any attachments (default)
|
||||||
|
for( AttachmentIdx=0; AttachmentIdx < `MAX_COSMETIC_ATTACHMENTS; AttachmentIdx++ )
|
||||||
|
{
|
||||||
|
CosmeticMeshIdx = bCustom ? EPRI.CustomCharacter.AttachmentMeshIndices[AttachmentIdx] : KFPRI.RepCustomizationInfo.AttachmentMeshIndices[AttachmentIdx];
|
||||||
|
if ( CosmeticMeshIdx != `CLEARED_ATTACHMENT_INDEX )
|
||||||
|
{
|
||||||
|
bMaskHeadMesh = bMaskHeadMesh || C.CosmeticVariants[CosmeticMeshIdx].bMaskHeadMesh;
|
||||||
|
|
||||||
|
// Attach all saved attachments to the character
|
||||||
|
SetAttachmentMeshAndSkin(C,
|
||||||
|
CosmeticMeshIdx,
|
||||||
|
bCustom ? EPRI.CustomCharacter.AttachmentSkinIndices[AttachmentIdx] : KFPRI.RepCustomizationInfo.AttachmentSkinIndices[AttachmentIdx],
|
||||||
|
KFP, KFPRI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// initial mask for new MIC (also see ResetHeadMaskParam())
|
||||||
|
if ( bMaskHeadMesh && KFP.CharacterMICs[1] != None )
|
||||||
|
KFP.CharacterMICs[1].SetScalarParameterValue('Scalar_Mask', 1.f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function SetBodyMeshAndSkin( KFCharacterInfo_Human C,
|
||||||
|
byte CurrentBodyMeshIndex,
|
||||||
|
byte CurrentBodySkinIndex,
|
||||||
|
KFPawn KFP )
|
||||||
|
{
|
||||||
|
local SkeletalMesh CharBodyMesh;
|
||||||
|
|
||||||
|
// Character Mesh
|
||||||
|
if( C.BodyVariants.length > 0 )
|
||||||
|
{
|
||||||
|
// Assign a skin to the body mesh as a material override
|
||||||
|
CurrentBodyMeshIndex = (CurrentBodyMeshIndex < C.BodyVariants.length) ? CurrentBodyMeshIndex : 0;
|
||||||
|
|
||||||
|
// Load the meshes
|
||||||
|
CharBodyMesh = SkeletalMesh(SafeLoadObject(C.BodyVariants[CurrentBodyMeshIndex].MeshName, class'SkeletalMesh'));
|
||||||
|
|
||||||
|
// Assign the body mesh to the pawn
|
||||||
|
KFP.Mesh.SetSkeletalMesh(CharBodyMesh);
|
||||||
|
|
||||||
|
if (KFP.WorldInfo.NetMode != NM_DedicatedServer)
|
||||||
|
{
|
||||||
|
SetBodySkinMaterial(C, C.BodyVariants[CurrentBodyMeshIndex], CurrentBodySkinIndex, KFP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
`warn("Character does not have a valid mesh");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function SetBodySkinMaterial( KFCharacterInfo_Human C, OutfitVariants CurrentVariant, byte NewSkinIndex, KFPawn KFP)
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
if (KFP.WorldInfo.NetMode != NM_DedicatedServer)
|
||||||
|
{
|
||||||
|
if( CurrentVariant.SkinVariations.length > 0 )
|
||||||
|
{
|
||||||
|
// Assign a skin to the body mesh as a material override
|
||||||
|
NewSkinIndex = (NewSkinIndex < CurrentVariant.SkinVariations.length) ? NewSkinIndex : 0;
|
||||||
|
KFP.Mesh.SetMaterial(C.BodyMaterialID, CurrentVariant.SkinVariations[NewSkinIndex].Skin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use material specified in the mesh asset
|
||||||
|
for( i=0; i<KFP.Mesh.GetNumElements(); i++ )
|
||||||
|
{
|
||||||
|
KFP.Mesh.SetMaterial(i, none);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize MICs
|
||||||
|
if( KFP.Mesh != None )
|
||||||
|
{
|
||||||
|
KFP.CharacterMICs[0] = KFP.Mesh.CreateAndSetMaterialInstanceConstant(C.BodyMaterialID);
|
||||||
|
CloneMIC(KFP.CharacterMICs[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function SetHeadSkinMaterial( KFCharacterInfo_Human C, OutfitVariants CurrentVariant, byte NewSkinIndex, KFPawn KFP)
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
if (KFP.WorldInfo.NetMode != NM_DedicatedServer)
|
||||||
|
{
|
||||||
|
if( CurrentVariant.SkinVariations.length > 0 )
|
||||||
|
{
|
||||||
|
// Assign a skin to the body mesh as a material override
|
||||||
|
NewSkinIndex = (NewSkinIndex < CurrentVariant.SkinVariations.length) ? NewSkinIndex : 0;
|
||||||
|
KFP.ThirdPersonHeadMeshComponent.SetMaterial(C.HeadMaterialID, CurrentVariant.SkinVariations[NewSkinIndex].Skin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use material specified in the mesh asset
|
||||||
|
for( i=0; i<KFP.ThirdPersonHeadMeshComponent.GetNumElements(); i++ )
|
||||||
|
{
|
||||||
|
KFP.ThirdPersonHeadMeshComponent.SetMaterial(i, none);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize MICs
|
||||||
|
if( KFP.ThirdPersonHeadMeshComponent != None )
|
||||||
|
{
|
||||||
|
KFP.CharacterMICs[1] = KFP.ThirdPersonHeadMeshComponent.CreateAndSetMaterialInstanceConstant(C.HeadMaterialID);
|
||||||
|
CloneMIC(KFP.CharacterMICs[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function SetHeadMeshAndSkin( KFCharacterInfo_Human C,
|
||||||
|
byte CurrentHeadMeshIndex,
|
||||||
|
byte CurrentHeadSkinIndex,
|
||||||
|
KFPawn KFP )
|
||||||
|
{
|
||||||
|
local SkeletalMesh CharHeadMesh;
|
||||||
|
|
||||||
|
if ( C.HeadVariants.length > 0 )
|
||||||
|
{
|
||||||
|
CurrentHeadMeshIndex = (CurrentHeadMeshIndex < C.HeadVariants.length) ? CurrentHeadMeshIndex : 0;
|
||||||
|
|
||||||
|
CharHeadMesh = SkeletalMesh(SafeLoadObject(C.HeadVariants[CurrentHeadMeshIndex].MeshName, class'SkeletalMesh'));
|
||||||
|
|
||||||
|
// Parent the third person head mesh to the body mesh
|
||||||
|
KFP.ThirdPersonHeadMeshComponent.SetSkeletalMesh(CharHeadMesh);
|
||||||
|
KFP.ThirdPersonHeadMeshComponent.SetScale(C.DefaultMeshScale);
|
||||||
|
|
||||||
|
KFP.ThirdPersonHeadMeshComponent.SetParentAnimComponent(KFP.Mesh);
|
||||||
|
KFP.ThirdPersonHeadMeshComponent.SetShadowParent(KFP.Mesh);
|
||||||
|
KFP.ThirdPersonHeadMeshComponent.SetLODParent(KFP.Mesh);
|
||||||
|
|
||||||
|
KFP.AttachComponent(KFP.ThirdPersonHeadMeshComponent);
|
||||||
|
|
||||||
|
if (KFP.WorldInfo.NetMode != NM_DedicatedServer)
|
||||||
|
{
|
||||||
|
SetHeadSkinMaterial(C, C.HeadVariants[CurrentHeadMeshIndex], CurrentHeadSkinIndex, KFP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function SetAttachmentSkinMaterial( KFCharacterInfo_Human C,
|
||||||
|
int PawnAttachmentIndex,
|
||||||
|
const out AttachmentVariants CurrentVariant,
|
||||||
|
byte NewSkinIndex,
|
||||||
|
KFPawn KFP)
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
if (KFP.WorldInfo.NetMode != NM_DedicatedServer)
|
||||||
|
{
|
||||||
|
if( CurrentVariant.SkinVariations.length > 0 )
|
||||||
|
{
|
||||||
|
// Assign a skin to the attachment mesh as a material override
|
||||||
|
if ( NewSkinIndex < CurrentVariant.SkinVariations.length )
|
||||||
|
{
|
||||||
|
KFP.ThirdPersonAttachments[PawnAttachmentIndex].SetMaterial(
|
||||||
|
CurrentVariant.SkinMaterialID,
|
||||||
|
CurrentVariant.SkinVariations[NewSkinIndex].Skin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
`log("Out of bounds skin index for"@CurrentVariant.MeshName);
|
||||||
|
C.RemoveAttachmentMeshAndSkin(PawnAttachmentIndex, KFP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use material specified in the mesh asset
|
||||||
|
for( i=0; i < KFP.ThirdPersonAttachments[PawnAttachmentIndex].GetNumElements(); i++ )
|
||||||
|
{
|
||||||
|
KFP.ThirdPersonAttachments[PawnAttachmentIndex].SetMaterial(i, none);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Called on owning client to change a cosmetic attachment or on other clients via replication */
|
||||||
|
static final function SetAttachmentMeshAndSkin( KFCharacterInfo_Human C,
|
||||||
|
byte CurrentAttachmentMeshIndex,
|
||||||
|
byte CurrentAttachmentSkinIndex,
|
||||||
|
KFPawn KFP,
|
||||||
|
optional KFPlayerReplicationInfo KFPRI )
|
||||||
|
{
|
||||||
|
local string CharAttachmentMeshName;
|
||||||
|
local name CharAttachmentSocketName;
|
||||||
|
local bool bIsSkeletalAttachment;
|
||||||
|
local StaticMesh CharAttachmentStaticMesh;
|
||||||
|
local SkeletalMesh CharacterAttachmentSkelMesh;
|
||||||
|
local float MaxDrawDistance;
|
||||||
|
local StaticMeshComponent StaticAttachment;
|
||||||
|
local SkeletalMeshComponent SkeletalAttachment;
|
||||||
|
local SkeletalMeshSocket AttachmentSocket;
|
||||||
|
local vector AttachmentLocationRelativeToSocket, AttachmentScaleRelativeToSocket;
|
||||||
|
local rotator AttachmentRotationRelativeToSocket;
|
||||||
|
local int AttachmentSlotIndex;
|
||||||
|
|
||||||
|
if (KFP.WorldInfo.NetMode == NM_DedicatedServer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Clear any previously attachments for the same slot
|
||||||
|
//DetachConflictingAttachments(CurrentAttachmentMeshIndex, KFP, KFPRI);
|
||||||
|
// Get a slot where this attachment could fit
|
||||||
|
AttachmentSlotIndex = C.GetAttachmentSlotIndex(CurrentAttachmentMeshIndex, KFP);
|
||||||
|
|
||||||
|
// Since cosmetic attachments are optional, do not choose index 0 if none is
|
||||||
|
// specified unlike the the head and body meshes
|
||||||
|
if ( C.CosmeticVariants.length > 0 && CurrentAttachmentMeshIndex < C.CosmeticVariants.length )
|
||||||
|
{
|
||||||
|
// Cache values from character info
|
||||||
|
CharAttachmentMeshName = C.CosmeticVariants[CurrentAttachmentMeshIndex].MeshName;
|
||||||
|
CharAttachmentSocketName = C.CosmeticVariants[CurrentAttachmentMeshIndex].SocketName;
|
||||||
|
MaxDrawDistance = C.CosmeticVariants[CurrentAttachmentMeshIndex].MaxDrawDistance;
|
||||||
|
AttachmentLocationRelativeToSocket = C.CosmeticVariants[CurrentAttachmentMeshIndex].RelativeTranslation;
|
||||||
|
AttachmentRotationRelativeToSocket = C.CosmeticVariants[CurrentAttachmentMeshIndex].RelativeRotation;
|
||||||
|
AttachmentScaleRelativeToSocket = C.CosmeticVariants[CurrentAttachmentMeshIndex].RelativeScale;
|
||||||
|
bIsSkeletalAttachment = C.CosmeticVariants[CurrentAttachmentMeshIndex].bIsSkeletalAttachment;
|
||||||
|
|
||||||
|
// If it is a skeletal attachment, parent anim it to the body mesh
|
||||||
|
if( bIsSkeletalAttachment )
|
||||||
|
{
|
||||||
|
if( SkeletalMeshComponent(KFP.ThirdPersonAttachments[AttachmentSlotIndex]) != none )
|
||||||
|
{
|
||||||
|
// If previously attached and we could have changed outfits (e.g. local player UI) then re-validate
|
||||||
|
// required skeletal mesh socket. Must be after body mesh DLO, but before AttachComponent.
|
||||||
|
if ( KFP.IsLocallyControlled() )
|
||||||
|
{
|
||||||
|
if ( CharAttachmentSocketName != '' && KFP.Mesh.GetSocketByName(CharAttachmentSocketName) == None )
|
||||||
|
{
|
||||||
|
C.RemoveAttachmentMeshAndSkin(AttachmentSlotIndex, KFP, KFPRI);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SkeletalAttachment = SkeletalMeshComponent(KFP.ThirdPersonAttachments[AttachmentSlotIndex]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SkeletalAttachment = new(KFP) class'SkeletalMeshComponent';
|
||||||
|
SkeletalAttachment.SetActorCollision(false, false);
|
||||||
|
KFP.ThirdPersonAttachments[AttachmentSlotIndex] = SkeletalAttachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load and assign skeletal mesh
|
||||||
|
CharacterAttachmentSkelMesh = SkeletalMesh(SafeLoadObject(CharAttachmentMeshName, class'SkeletalMesh'));
|
||||||
|
SkeletalAttachment.SetSkeletalMesh(CharacterAttachmentSkelMesh);
|
||||||
|
|
||||||
|
// Parent animation and LOD transitions to body mesh
|
||||||
|
SkeletalAttachment.SetParentAnimComponent(KFP.Mesh);
|
||||||
|
SkeletalAttachment.SetLODParent(KFP.Mesh);
|
||||||
|
SkeletalAttachment.SetScale(C.DefaultMeshScale);
|
||||||
|
SkeletalAttachment.SetCullDistance(MaxDrawDistance);
|
||||||
|
SkeletalAttachment.SetShadowParent(KFP.Mesh);
|
||||||
|
SkeletalAttachment.SetLightingChannels(KFP.PawnLightingChannel);
|
||||||
|
|
||||||
|
// Attach
|
||||||
|
KFP.AttachComponent(SkeletalAttachment);
|
||||||
|
}
|
||||||
|
// Otherwise (if static), attach to a socket on the body mesh
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( StaticMeshComponent(KFP.ThirdPersonAttachments[AttachmentSlotIndex]) != none )
|
||||||
|
{
|
||||||
|
StaticAttachment = StaticMeshComponent(KFP.ThirdPersonAttachments[AttachmentSlotIndex]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StaticAttachment = new(KFP) class'StaticMeshComponent';
|
||||||
|
StaticAttachment.SetActorCollision(false, false);
|
||||||
|
KFP.ThirdPersonAttachments[AttachmentSlotIndex] = StaticAttachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load and assign static mesh
|
||||||
|
CharAttachmentStaticMesh = StaticMesh(SafeLoadObject(CharAttachmentMeshName, class'StaticMesh'));
|
||||||
|
StaticAttachment.SetStaticMesh(CharAttachmentStaticMesh);
|
||||||
|
|
||||||
|
// Set properties
|
||||||
|
StaticAttachment.SetScale(C.DefaultMeshScale);
|
||||||
|
StaticAttachment.SetCullDistance(MaxDrawDistance);
|
||||||
|
StaticAttachment.SetShadowParent(KFP.Mesh);
|
||||||
|
StaticAttachment.SetLightingChannels(KFP.PawnLightingChannel);
|
||||||
|
|
||||||
|
// For static meshes, attach to given socket
|
||||||
|
AttachmentSocket = KFP.mesh.GetSocketByName(CharAttachmentSocketName);
|
||||||
|
KFP.mesh.AttachComponent(
|
||||||
|
StaticAttachment,
|
||||||
|
AttachmentSocket.BoneName,
|
||||||
|
AttachmentSocket.RelativeLocation + AttachmentLocationRelativeToSocket,
|
||||||
|
AttachmentSocket.RelativeRotation + AttachmentRotationRelativeToSocket,
|
||||||
|
AttachmentSocket.RelativeScale * AttachmentScaleRelativeToSocket);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the pawn's attachment metadata
|
||||||
|
KFP.ThirdPersonAttachmentBitMask = KFP.ThirdPersonAttachmentBitMask | (1 << AttachmentSlotIndex);
|
||||||
|
KFP.ThirdPersonAttachmentSocketNames[AttachmentSlotIndex] = CharAttachmentSocketName;
|
||||||
|
|
||||||
|
SetAttachmentSkinMaterial(C,
|
||||||
|
AttachmentSlotIndex,
|
||||||
|
C.CosmeticVariants[CurrentAttachmentMeshIndex],
|
||||||
|
CurrentAttachmentSkinIndex,
|
||||||
|
KFP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Treat `CLEARED_ATTACHMENT_INDEX as special value (for client detachment)
|
||||||
|
if( CurrentAttachmentMeshIndex == `CLEARED_ATTACHMENT_INDEX )
|
||||||
|
{
|
||||||
|
C.RemoveAttachmentMeshAndSkin(AttachmentSlotIndex, KFP, KFPRI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes any attachments that exist in the same socket or have overriding cases
|
||||||
|
* Network: Local Player
|
||||||
|
*/
|
||||||
|
static final function DetachConflictingAttachments( KFCharacterInfo_Human C, byte NewAttachmentMeshIndex, KFPawn KFP, optional KFPlayerReplicationInfo KFPRI)
|
||||||
|
{
|
||||||
|
local name NewAttachmentSocketName;
|
||||||
|
local int i, CurrentAttachmentIdx;
|
||||||
|
local ExtPlayerReplicationInfo EPRI;
|
||||||
|
|
||||||
|
EPRI = ExtPlayerReplicationInfo(KFPRI);
|
||||||
|
if ( EPRI==none || !EPRI.UsesCustomChar() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( C.CosmeticVariants.length > 0 &&
|
||||||
|
NewAttachmentMeshIndex < C.CosmeticVariants.length )
|
||||||
|
{
|
||||||
|
// The socket that this attachment requires
|
||||||
|
NewAttachmentSocketName = C.CosmeticVariants[NewAttachmentMeshIndex].SocketName;
|
||||||
|
|
||||||
|
for( i=0; i < `MAX_COSMETIC_ATTACHMENTS; i++ )
|
||||||
|
{
|
||||||
|
CurrentAttachmentIdx = EPRI.CustomCharacter.AttachmentMeshIndices[i];
|
||||||
|
if ( CurrentAttachmentIdx == `CLEARED_ATTACHMENT_INDEX )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Remove the object if it is taking up our desired slot
|
||||||
|
if( KFP.ThirdPersonAttachmentSocketNames[i] != '' &&
|
||||||
|
KFP.ThirdPersonAttachmentSocketNames[i] == NewAttachmentSocketName )
|
||||||
|
{
|
||||||
|
C.RemoveAttachmentMeshAndSkin(i, KFP, KFPRI);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the object if it cannot exist at the same time as another equipped item
|
||||||
|
if( C.GetOverrideCase(CurrentAttachmentIdx, NewAttachmentMeshIndex) )
|
||||||
|
{
|
||||||
|
C.RemoveAttachmentMeshAndSkin(i, KFP, KFPRI);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check inverse override
|
||||||
|
if( C.GetOverrideCase(NewAttachmentMeshIndex, CurrentAttachmentIdx) )
|
||||||
|
{
|
||||||
|
C.RemoveAttachmentMeshAndSkin(i, KFP, KFPRI);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Assign an arm mesh and material to this pawn */
|
||||||
|
static final function SetFirstPersonArmsFromArch( KFCharacterInfo_Human C, KFPawn KFP, optional KFPlayerReplicationInfo KFPRI )
|
||||||
|
{
|
||||||
|
local MaterialInstanceConstant M;
|
||||||
|
local ExtPlayerReplicationInfo EPRI;
|
||||||
|
local bool bCustom;
|
||||||
|
|
||||||
|
EPRI = ExtPlayerReplicationInfo(KFPRI);
|
||||||
|
if ( KFPRI == none )
|
||||||
|
{
|
||||||
|
`Warn("Does not have a KFPRI" @ C);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bCustom = (EPRI!=None ? EPRI.UsesCustomChar() : false);
|
||||||
|
|
||||||
|
// First person arms mesh and skin are based on body mesh & skin.
|
||||||
|
// Index of 255 implies use index 0 (default).
|
||||||
|
C.SetArmsMeshAndSkin(
|
||||||
|
bCustom ? EPRI.CustomCharacter.BodyMeshIndex : KFPRI.RepCustomizationInfo.BodyMeshIndex,
|
||||||
|
bCustom ? EPRI.CustomCharacter.BodySkinIndex : KFPRI.RepCustomizationInfo.BodySkinIndex,
|
||||||
|
KFP);
|
||||||
|
|
||||||
|
// Hack fix for a material bug on KF2
|
||||||
|
if( bCustom && KFP.ArmsMesh.SkeletalMesh!=None && KFP.ArmsMesh.GetMaterial(0)!=None )
|
||||||
|
{
|
||||||
|
M = KFP.ArmsMesh.CreateAndSetMaterialInstanceConstant(0);
|
||||||
|
CloneMIC(M);
|
||||||
|
}
|
||||||
|
}
|
34
ServerExt/Classes/ExtHUD_PlayerBackpack.uc
Normal file
34
ServerExt/Classes/ExtHUD_PlayerBackpack.uc
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
class ExtHUD_PlayerBackpack extends KFGFxHUD_PlayerBackpack;
|
||||||
|
|
||||||
|
var class<Ext_PerkBase> EPerkClass;
|
||||||
|
|
||||||
|
function UpdateGrenades()
|
||||||
|
{
|
||||||
|
local int CurrentGrenades;
|
||||||
|
local ExtPerkManager PM;
|
||||||
|
|
||||||
|
if(MyKFInvManager != none)
|
||||||
|
CurrentGrenades = MyKFInvManager.GrenadeCount;
|
||||||
|
|
||||||
|
//Update the icon the for grenade type.
|
||||||
|
if( ExtPlayerController(MyKFPC)!=None )
|
||||||
|
{
|
||||||
|
PM = ExtPlayerController(MyKFPC).ActivePerkManager;
|
||||||
|
|
||||||
|
if( PM!=None && PM.CurrentPerk!=None && EPerkClass!=PM.CurrentPerk.Class )
|
||||||
|
{
|
||||||
|
SetString("backpackGrenadeType", "img://"$PM.CurrentPerk.GrenadeWeaponDef.Static.GetImagePath());
|
||||||
|
EPerkClass = PM.CurrentPerk.Class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update the grenades count value
|
||||||
|
if(CurrentGrenades != LastGrenades)
|
||||||
|
{
|
||||||
|
SetInt("backpackGrenades" , Min(CurrentGrenades,9));
|
||||||
|
LastGrenades = CurrentGrenades;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultProperties
|
||||||
|
{
|
||||||
|
}
|
71
ServerExt/Classes/ExtHUD_PlayerStatus.uc
Normal file
71
ServerExt/Classes/ExtHUD_PlayerStatus.uc
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
class ExtHUD_PlayerStatus extends KFGFxHUD_PlayerStatus;
|
||||||
|
|
||||||
|
var ExtPlayerController ExPC;
|
||||||
|
var class<Ext_PerkBase> ExLastPerkClass;
|
||||||
|
var string CurPerkPath;
|
||||||
|
|
||||||
|
function InitializeHUD()
|
||||||
|
{
|
||||||
|
Super.InitializeHUD();
|
||||||
|
ExPC = ExtPlayerController(MyPC);
|
||||||
|
}
|
||||||
|
|
||||||
|
function UpdatePerk()
|
||||||
|
{
|
||||||
|
local int CurrentPerkLevel,CurrentPerkEXP;
|
||||||
|
local Ext_PerkBase CurrentPerk;
|
||||||
|
|
||||||
|
if( ExPC == none || ExPC.ActivePerkManager==None || ExPC.ActivePerkManager.CurrentPerk==None )
|
||||||
|
return;
|
||||||
|
|
||||||
|
CurrentPerk = ExPC.ActivePerkManager.CurrentPerk;
|
||||||
|
CurrentPerkLevel = CurrentPerk.CurrentLevel;
|
||||||
|
CurrentPerkEXP = CurrentPerk.CurrentEXP;
|
||||||
|
|
||||||
|
// Update the perk class.
|
||||||
|
if( ( ExLastPerkClass != CurrentPerk.Class ) || ( LastPerkLevel != CurrentPerkLevel ) )
|
||||||
|
{
|
||||||
|
CurPerkPath = CurrentPerk.GetPerkIconPath(CurrentPerkLevel);
|
||||||
|
SetString("playerPerkIcon" , CurPerkPath);
|
||||||
|
SetInt("playerPerkXPPercent", CurrentPerk.GetProgressPercent() * 100.f );
|
||||||
|
if( LastPerkLevel != CurrentPerkLevel && ExLastPerkClass==CurrentPerk.Class )
|
||||||
|
{
|
||||||
|
SetBool("bLevelUp", true);
|
||||||
|
ShowXPBark(CurrentPerkEXP-LastEXPValue,CurPerkPath,true);
|
||||||
|
}
|
||||||
|
ExLastPerkClass = CurrentPerk.class;
|
||||||
|
|
||||||
|
SetInt("playerPerkLevel" , CurrentPerkLevel);
|
||||||
|
LastPerkLevel = CurrentPerkLevel;
|
||||||
|
LastEXPValue = CurrentPerkEXP;
|
||||||
|
}
|
||||||
|
else if( LastEXPValue!=CurrentPerkEXP )
|
||||||
|
{
|
||||||
|
SetBool("bLevelUp", false);
|
||||||
|
SetInt("playerPerkXPPercent", CurrentPerk.GetProgressPercent() * 100.f );
|
||||||
|
ShowXPBark(CurrentPerkEXP-LastEXPValue,CurPerkPath,true);
|
||||||
|
LastEXPValue = CurrentPerkEXP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function ShowXPBark( int DeltaXP, string IconPath, bool bIsCurrentPerk )
|
||||||
|
{
|
||||||
|
ActionScriptVoid("showXPBark");
|
||||||
|
}
|
||||||
|
|
||||||
|
function UpdateHealth()
|
||||||
|
{
|
||||||
|
if( MyPC.Pawn == none )
|
||||||
|
{
|
||||||
|
LastHealth = 0;
|
||||||
|
SetInt("playerHealth" , LastHealth);
|
||||||
|
}
|
||||||
|
else if( LastHealth != MyPC.Pawn.Health )
|
||||||
|
{
|
||||||
|
LastHealth = MyPC.Pawn.Health;
|
||||||
|
SetInt("playerHealth" , LastHealth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
}
|
61
ServerExt/Classes/ExtHUD_SpectatorInfo.uc
Normal file
61
ServerExt/Classes/ExtHUD_SpectatorInfo.uc
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
class ExtHUD_SpectatorInfo extends KFGFxHUD_SpectatorInfo;
|
||||||
|
|
||||||
|
var class<Ext_PerkBase> ExtLastPerkClass;
|
||||||
|
var bool bUnsetInfo;
|
||||||
|
|
||||||
|
function LocalizeText()
|
||||||
|
{
|
||||||
|
local GFxObject TempObject;
|
||||||
|
TempObject = CreateObject("Object");
|
||||||
|
|
||||||
|
TempObject.SetString("prevPlayer", "FREE CAMERA");
|
||||||
|
TempObject.SetString("nextPlayer", PrevPlayerString);
|
||||||
|
TempObject.SetString("changeCamera", ChangeCameraString);
|
||||||
|
|
||||||
|
SetObject("localizedText", TempObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
function UpdateSpectateeInfo(optional bool bForceUpdate)
|
||||||
|
{
|
||||||
|
local ExtPlayerReplicationInfo E;
|
||||||
|
|
||||||
|
E = ExtPlayerReplicationInfo(SpectatedKFPRI);
|
||||||
|
if( !GetPC().IsSpectating() || E==None )
|
||||||
|
{
|
||||||
|
if( !bUnsetInfo )
|
||||||
|
{
|
||||||
|
SetVisible(false);
|
||||||
|
bUnsetInfo = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the perk class.
|
||||||
|
if( ExtLastPerkClass!=E.ECurrentPerk || LastPerkLevel!=E.ECurrentPerkLevel || bForceUpdate || bUnsetInfo )
|
||||||
|
{
|
||||||
|
LastPerkLevel = E.ECurrentPerkLevel;
|
||||||
|
ExtLastPerkClass = E.ECurrentPerk;
|
||||||
|
UpdatePlayerInfo(bForceUpdate);
|
||||||
|
bUnsetInfo = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function UpdatePlayerInfo(optional bool bForceUpdate)
|
||||||
|
{
|
||||||
|
local GFxObject TempObject;
|
||||||
|
|
||||||
|
TempObject = CreateObject("Object");
|
||||||
|
TempObject.SetString("playerName", SpectatedKFPRI.GetHumanReadableName());
|
||||||
|
if( ExtLastPerkClass!=None )
|
||||||
|
{
|
||||||
|
TempObject.SetString("playerPerk", SpectatedKFPRI.CurrentPerkClass.default.LevelString @LastPerkLevel @ExtLastPerkClass.default.PerkName );
|
||||||
|
TempObject.SetString("iconPath", ExtLastPerkClass.Static.GetPerkIconPath(LastPerkLevel));
|
||||||
|
}
|
||||||
|
else TempObject.SetString("playerPerk","No perk");
|
||||||
|
SetObject("playerData", TempObject);
|
||||||
|
SetVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
}
|
56
ServerExt/Classes/ExtHUD_WaveInfo.uc
Normal file
56
ServerExt/Classes/ExtHUD_WaveInfo.uc
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
class ExtHUD_WaveInfo extends KFGFxHUD_WaveInfo;
|
||||||
|
|
||||||
|
function TickHud(float DeltaTime)
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
if(KFGRI == none)
|
||||||
|
KFGRI = KFGameReplicationInfo(GetPC().WorldInfo.GRI);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(KFGRI.bTraderIsOpen)
|
||||||
|
{
|
||||||
|
i = KFGRI.GetTraderTimeRemaining();
|
||||||
|
if(LastTraderTimeRemaining != i)
|
||||||
|
{
|
||||||
|
SetInt("remainingTraderTime" ,i);
|
||||||
|
LastTraderTimeRemaining = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i = KFGRI.IsFinalWave() ? INDEX_NONE : Max(KFGRI.AIRemaining,0);
|
||||||
|
if(LastZEDCount != i)
|
||||||
|
{
|
||||||
|
SetInt("remainingZEDs" ,i);
|
||||||
|
LastZEDCount = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Max # of waves.
|
||||||
|
if(LastWaveMax != KFGRI.WaveMax)
|
||||||
|
{
|
||||||
|
LastWaveMax = KFGRI.WaveMax;
|
||||||
|
SetInt("maxWaves" ,LastWaveMax-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current wave we're on.
|
||||||
|
if( LastWave!=KFGRI.WaveNum )
|
||||||
|
{
|
||||||
|
LastWave = KFGRI.WaveNum;
|
||||||
|
if( LastWave>LastWaveMax )
|
||||||
|
{
|
||||||
|
SetInt("currentWave",0); // Force text to refresh.
|
||||||
|
SetString("finalText", "END");
|
||||||
|
}
|
||||||
|
SetInt("currentWave",Min(LastWave,LastWaveMax));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function UpdateWaveCount();
|
||||||
|
|
||||||
|
DefaultProperties
|
||||||
|
{
|
||||||
|
LastWave=-1
|
||||||
|
}
|
1222
ServerExt/Classes/ExtHumanPawn.uc
Normal file
1222
ServerExt/Classes/ExtHumanPawn.uc
Normal file
File diff suppressed because it is too large
Load Diff
22
ServerExt/Classes/ExtInventoryManager.uc
Normal file
22
ServerExt/Classes/ExtInventoryManager.uc
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
class ExtInventoryManager extends KFInventoryManager;
|
||||||
|
|
||||||
|
// Dosh spamming barrier.
|
||||||
|
var transient float MoneyTossTime;
|
||||||
|
var transient byte MoneyTossCount;
|
||||||
|
|
||||||
|
reliable server function ServerThrowMoney()
|
||||||
|
{
|
||||||
|
if( MoneyTossTime>WorldInfo.TimeSeconds )
|
||||||
|
{
|
||||||
|
if( MoneyTossCount>=10 )
|
||||||
|
return;
|
||||||
|
++MoneyTossCount;
|
||||||
|
MoneyTossTime = FMax(MoneyTossTime,WorldInfo.TimeSeconds+0.5);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MoneyTossCount = 0;
|
||||||
|
MoneyTossTime = WorldInfo.TimeSeconds+1;
|
||||||
|
}
|
||||||
|
Super.ServerThrowMoney();
|
||||||
|
}
|
632
ServerExt/Classes/ExtMenu_Gear.uc
Normal file
632
ServerExt/Classes/ExtMenu_Gear.uc
Normal file
@ -0,0 +1,632 @@
|
|||||||
|
class ExtMenu_Gear extends KFGFxObject_Menu;
|
||||||
|
|
||||||
|
var ExtPlayerReplicationInfo ExtPRI;
|
||||||
|
|
||||||
|
var KFGFxObject_TraderItems TraderItems;
|
||||||
|
var KFGFxGearContainer_PerksSelection PerkSelectionContainer;
|
||||||
|
var KFCharacterInfo_Human CurrentCharInfo;
|
||||||
|
var string CharInfoPath;
|
||||||
|
var int CurrentPerkIndex;
|
||||||
|
var array<class<KFWeaponDefinition> > CurrentWearponDefList;
|
||||||
|
var array<Emote> EmoteList;
|
||||||
|
|
||||||
|
var bool bWaitingCharList,bIsCustomChar;
|
||||||
|
|
||||||
|
function InitializeMenu( KFGFxMoviePlayer_Manager InManager )
|
||||||
|
{
|
||||||
|
super(KFGFxObject_Menu).InitializeMenu(InManager);
|
||||||
|
LocalizeText();
|
||||||
|
EmoteList = class'KFEmoteList'.static.GetEmoteArray();
|
||||||
|
InitCharacterMenu();
|
||||||
|
TraderItems = KFGameReplicationInfo( GetPC().WorldInfo.GRI ).TraderItems;
|
||||||
|
}
|
||||||
|
function InitCharacterMenu()
|
||||||
|
{
|
||||||
|
ExtPRI = ExtPlayerReplicationInfo(GetPC().PlayerReplicationInfo);
|
||||||
|
|
||||||
|
if( ExtPRI!=None && ExtPRI.bClientInitChars )
|
||||||
|
CharListRecieved();
|
||||||
|
else if( ExtPRI==None )
|
||||||
|
{
|
||||||
|
if( GetPC().PlayerReplicationInfo!=None ) // Faulty mod setup.
|
||||||
|
{
|
||||||
|
bWaitingCharList = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GetPC().SetTimer(0.1,false,'InitCharacterMenu',Self);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ExtPRI.OnCharListDone = CharListRecieved;
|
||||||
|
bWaitingCharList = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event bool WidgetInitialized(name WidgetName, name WidgetPath, GFxObject Widget)
|
||||||
|
{
|
||||||
|
switch(WidgetName)
|
||||||
|
{
|
||||||
|
case 'perkSelectionContainer':
|
||||||
|
if ( PerkSelectionContainer == none )
|
||||||
|
{
|
||||||
|
PerkSelectionContainer = KFGFxGearContainer_PerksSelection( Widget );
|
||||||
|
PerkSelectionContainer.Initialize(self);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function OnOpen()
|
||||||
|
{
|
||||||
|
local PlayerController PC;
|
||||||
|
|
||||||
|
PC = GetPC();
|
||||||
|
if( PC == none )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// @hack: moved from KFGfxMoviePlayer_Manager because this causes a crash while
|
||||||
|
// bink (e.g. KFII-25456) are playing. Don't use HandleInputAxis with Bink! (for now) :)
|
||||||
|
GetGameViewportClient().HandleInputAxis = OnAxisModified;
|
||||||
|
|
||||||
|
if ( PC.PlayerReplicationInfo.bReadyToPlay && PC.WorldInfo.GRI.bMatchHasBegun )
|
||||||
|
{
|
||||||
|
// Players cannot change characters if they are in a game
|
||||||
|
SetBool("characterButtonEnabled", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function LocalizeText()
|
||||||
|
{
|
||||||
|
local GFxObject LocalizedObject;
|
||||||
|
|
||||||
|
LocalizedObject = CreateObject("Object");
|
||||||
|
|
||||||
|
LocalizedObject.SetString("header", class'KFGFxMenu_Gear'.Default.GearHeaderString);
|
||||||
|
LocalizedObject.SetString("listButton", class'KFGFxMenu_Gear'.Default.BackString);
|
||||||
|
LocalizedObject.SetString("bioStringText", class'KFGFxMenu_Gear'.Default.BioString);
|
||||||
|
LocalizedObject.SetString("charactersString", class'KFGFxMenu_Gear'.Default.CharacterString);
|
||||||
|
LocalizedObject.SetString("headsString", class'KFGFxMenu_Gear'.Default.HeadString);
|
||||||
|
LocalizedObject.SetString("emoteString", Class'KFLocalMessage_VoiceComms'.default.VoiceCommsOptionStrings[8]);
|
||||||
|
LocalizedObject.SetString("bodiesString", class'KFGFxMenu_Gear'.Default.BodyString);
|
||||||
|
LocalizedObject.SetString("skinsString", class'KFGFxMenu_Gear'.Default.SkinsString);
|
||||||
|
LocalizedObject.SetString("attachmentsString", class'KFGFxMenu_Gear'.Default.AttachmentsString);
|
||||||
|
|
||||||
|
SetObject("localizeText", LocalizedObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function CharListRecieved()
|
||||||
|
{
|
||||||
|
UpdateCharacterList();
|
||||||
|
UpdateGear();
|
||||||
|
}
|
||||||
|
|
||||||
|
function UpdateEmoteList()
|
||||||
|
{
|
||||||
|
local byte ItemIndex, i;
|
||||||
|
local GFxObject DataProvider, SlotObject;
|
||||||
|
local string TexturePath;
|
||||||
|
|
||||||
|
ItemIndex = 0;
|
||||||
|
DataProvider = CreateArray();
|
||||||
|
|
||||||
|
for (i = 0; i < EmoteList.length; i++)
|
||||||
|
{
|
||||||
|
if ( class'KFEmoteList'.static.GetUnlockedEmote(EmoteList[i].Id) != 'NONE')
|
||||||
|
{
|
||||||
|
SlotObject = CreateObject( "Object" );
|
||||||
|
SlotObject.SetInt("ItemIndex", i);
|
||||||
|
SlotObject.SetString("label", Localize(EmoteList[i].ItemName, "EmoteName", class'KFGFxMenu_Gear'.Default.KFCharacterInfoString));
|
||||||
|
TexturePath = "img://"$EmoteList[i].IconPath;
|
||||||
|
SlotObject.SetBool("enabled", true);
|
||||||
|
SlotObject.SetString("source", TexturePath);
|
||||||
|
DataProvider.SetElementObject(ItemIndex, SlotObject);
|
||||||
|
ItemIndex++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//`log(MyKFPRI.EmoteList[i] @ "is not purchased.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetObject("emoteArray", DataProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
function UpdateCharacterList()
|
||||||
|
{
|
||||||
|
local byte i, ItemIndex;
|
||||||
|
local GFxObject DataProvider, SlotObject;
|
||||||
|
local string TexturePath;
|
||||||
|
|
||||||
|
bWaitingCharList = false;
|
||||||
|
ItemIndex = 0;
|
||||||
|
DataProvider = CreateArray();
|
||||||
|
for( i=0; i<ExtPRI.CharacterArchetypes.length; i++)
|
||||||
|
{
|
||||||
|
SlotObject = CreateObject( "Object" );
|
||||||
|
SlotObject.SetInt("ItemIndex", i);
|
||||||
|
SlotObject.SetString("label", Localize(String(ExtPRI.CharacterArchetypes[i].Name), "CharacterName", class'KFGFxMenu_Gear'.Default.KFCharacterInfoString));
|
||||||
|
SlotObject.SetBool("enabled", true);
|
||||||
|
TexturePath = "img://"$PathName(ExtPRI.CharacterArchetypes[i].DefaultHeadPortrait);
|
||||||
|
SlotObject.SetString("source", TexturePath);
|
||||||
|
DataProvider.SetElementObject(ItemIndex, SlotObject);
|
||||||
|
ItemIndex++;
|
||||||
|
}
|
||||||
|
for( i=0; i<ExtPRI.CustomCharList.length; i++)
|
||||||
|
{
|
||||||
|
if( !ExtPRI.IsClientCharLocked(ExtPRI.CharacterArchetypes.length+i) )
|
||||||
|
{
|
||||||
|
SlotObject = CreateObject( "Object" );
|
||||||
|
SlotObject.SetInt("ItemIndex", (ExtPRI.CharacterArchetypes.length+i));
|
||||||
|
SlotObject.SetString("label", Repl(string(ExtPRI.CustomCharList[i].Char.Name),"_"," "));
|
||||||
|
SlotObject.SetBool("enabled", true);
|
||||||
|
TexturePath = "img://"$PathName(ExtPRI.CustomCharList[i].Char.DefaultHeadPortrait);
|
||||||
|
SlotObject.SetString("source", TexturePath);
|
||||||
|
DataProvider.SetElementObject(ItemIndex, SlotObject);
|
||||||
|
ItemIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetObject("characterArray", DataProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
function UpdateGear()
|
||||||
|
{
|
||||||
|
if( bWaitingCharList )
|
||||||
|
return;
|
||||||
|
|
||||||
|
CurrentCharInfo = ExtPRI.GetSelectedArch();
|
||||||
|
bIsCustomChar = ExtPRI.ReallyUsingCustomChar();
|
||||||
|
|
||||||
|
CharInfoPath = String(CurrentCharInfo.Name);
|
||||||
|
// Set the list of usable bodies for this character
|
||||||
|
UpdateMeshList(class'KFGFxMenu_Gear'.Default.BodyMeshKey, class'KFGFxMenu_Gear'.Default.BodySkinKey, CurrentCharInfo.BodyVariants, "bodyArray");
|
||||||
|
// Set the list of usable heads for this character
|
||||||
|
UpdateMeshList(class'KFGFxMenu_Gear'.Default.HeadMeshKey, class'KFGFxMenu_Gear'.Default.HeadSkinKey, CurrentCharInfo.HeadVariants, "headsArray");
|
||||||
|
// Set the list of usable attachments for this character
|
||||||
|
UpdateAttachmentsList(CurrentCharInfo.CosmeticVariants);
|
||||||
|
|
||||||
|
UpdateEmoteList();
|
||||||
|
|
||||||
|
SetCurrentCharacterButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
final function string GetMenuName( Object Obj )
|
||||||
|
{
|
||||||
|
return Obj==None ? "Empty" : Repl(string(Obj.Name),"_"," ");
|
||||||
|
}
|
||||||
|
final function string GetMenuNameStr( string ObjName )
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
i = InStr(ObjName,".",true);
|
||||||
|
if( i!=-1 )
|
||||||
|
ObjName = Mid(ObjName,i+1);
|
||||||
|
return Repl(ObjName,"_"," ");
|
||||||
|
}
|
||||||
|
|
||||||
|
function UpdateMeshList(string OutfitKey, string SkinKey, array<OutfitVariants> Outfits, string DataArrayString)
|
||||||
|
{
|
||||||
|
local byte i, ItemIndex;
|
||||||
|
local GFxObject DataProvider, SlotObject;
|
||||||
|
local string TexturePath;
|
||||||
|
local OutfitVariants Outfit;
|
||||||
|
|
||||||
|
ItemIndex = 0;
|
||||||
|
DataProvider = CreateArray();
|
||||||
|
|
||||||
|
for (i = 0; i < Outfits.length; i++)
|
||||||
|
{
|
||||||
|
Outfit = Outfits[i];
|
||||||
|
if( bIsCustomChar )
|
||||||
|
{
|
||||||
|
SlotObject = CreateObject( "Object" );
|
||||||
|
SlotObject.SetInt("ItemIndex", i);
|
||||||
|
SlotObject.SetString("label", GetMenuNameStr(Outfit.MeshName));
|
||||||
|
SlotObject.SetBool("enabled", true);
|
||||||
|
|
||||||
|
TexturePath = "img://"$PathName(Outfit.UITexture);
|
||||||
|
SlotObject.SetString("source", TexturePath);
|
||||||
|
|
||||||
|
UpdateVariants( OutfitKey, SkinKey, Outfit.SkinVariations, i, SlotObject );
|
||||||
|
|
||||||
|
DataProvider.SetElementObject(ItemIndex, SlotObject);
|
||||||
|
ItemIndex++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SlotObject = CreateObject( "Object" );
|
||||||
|
SlotObject.SetInt("ItemIndex", i);
|
||||||
|
SlotObject.SetString("label", Localize(CharInfoPath, OutfitKey$i, class'KFGFxMenu_Gear'.Default.KFCharacterInfoString));
|
||||||
|
SlotObject.SetBool("enabled", true);
|
||||||
|
|
||||||
|
TexturePath = "img://"$PathName(Outfit.UITexture);
|
||||||
|
SlotObject.SetString("source", TexturePath);
|
||||||
|
|
||||||
|
UpdateVariants( OutfitKey, SkinKey, Outfit.SkinVariations, i, SlotObject );
|
||||||
|
|
||||||
|
DataProvider.SetElementObject(ItemIndex, SlotObject);
|
||||||
|
ItemIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetObject(DataArrayString, DataProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
function UpdateAttachmentsList(array<AttachmentVariants> Attachments)
|
||||||
|
{
|
||||||
|
local byte i, ItemIndex;
|
||||||
|
local GFxObject DataProvider, SlotObject;
|
||||||
|
local string TexturePath;
|
||||||
|
local AttachmentVariants Variant;
|
||||||
|
|
||||||
|
ItemIndex = 0;
|
||||||
|
DataProvider = CreateArray();
|
||||||
|
|
||||||
|
// Insert blank object
|
||||||
|
SlotObject = CreateObject( "Object" );
|
||||||
|
SlotObject.SetString("label", class'KFGFxMenu_Gear'.Default.NoneString);
|
||||||
|
SlotObject.SetString("source", "img://"$class'KFGFxMenu_Gear'.Default.ClearImagePath);
|
||||||
|
SlotObject.SetBool("enabled", true);
|
||||||
|
DataProvider.SetElementObject(ItemIndex, SlotObject);
|
||||||
|
ItemIndex++;
|
||||||
|
|
||||||
|
for (i = 0; i < Attachments.length; i++)
|
||||||
|
{
|
||||||
|
Variant = Attachments[i];
|
||||||
|
if( bIsCustomChar )
|
||||||
|
{
|
||||||
|
SlotObject = CreateObject( "Object" );
|
||||||
|
SlotObject.SetInt("ItemIndex", i);
|
||||||
|
SlotObject.SetString("label", GetMenuNameStr(Variant.MeshName));
|
||||||
|
SlotObject.SetBool("enabled", true);
|
||||||
|
|
||||||
|
TexturePath = "img://"$PathName(Variant.UITexture);
|
||||||
|
SlotObject.SetString("source", TexturePath);
|
||||||
|
UpdateVariants( class'KFGFxMenu_Gear'.Default.AttachmentKey, class'KFGFxMenu_Gear'.Default.AttachmentSkinKey, Variant.SkinVariations, i, SlotObject );
|
||||||
|
|
||||||
|
DataProvider.SetElementObject(ItemIndex, SlotObject);
|
||||||
|
ItemIndex++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SlotObject = CreateObject( "Object" );
|
||||||
|
SlotObject.SetInt("ItemIndex", i);
|
||||||
|
SlotObject.SetString("label", Localize(CharInfoPath, class'KFGFxMenu_Gear'.Default.AttachmentKey$i, class'KFGFxMenu_Gear'.Default.KFCharacterInfoString));
|
||||||
|
SlotObject.SetBool("enabled", true);
|
||||||
|
|
||||||
|
TexturePath = "img://"$PathName(Variant.UITexture);
|
||||||
|
SlotObject.SetString("source", TexturePath);
|
||||||
|
UpdateVariants( class'KFGFxMenu_Gear'.Default.AttachmentKey, class'KFGFxMenu_Gear'.Default.AttachmentSkinKey, Variant.SkinVariations, i, SlotObject );
|
||||||
|
|
||||||
|
DataProvider.SetElementObject(ItemIndex, SlotObject);
|
||||||
|
ItemIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetObject("attachmentsArray", DataProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
function UpdateVariants(string OutfitKey, string KeyName, out array<SkinVariant> SkinVariations, int OutfitIndex, out GFxObject MeshObject)
|
||||||
|
{
|
||||||
|
local byte i, ItemIndex;
|
||||||
|
local GFxObject DataProvider, SlotObject;
|
||||||
|
local SkinVariant Skin;
|
||||||
|
local string SectionPath;
|
||||||
|
local string TexturePath;
|
||||||
|
|
||||||
|
ItemIndex = 0;
|
||||||
|
DataProvider = CreateArray();
|
||||||
|
SectionPath = CharInfoPath$"."$OutfitKey$OutfitIndex;
|
||||||
|
|
||||||
|
for (i = 0; i < SkinVariations.length; i++)
|
||||||
|
{
|
||||||
|
Skin = SkinVariations[i];
|
||||||
|
if( bIsCustomChar )
|
||||||
|
{
|
||||||
|
SlotObject = CreateObject( "Object" );
|
||||||
|
SlotObject.SetInt("ItemIndex", i);
|
||||||
|
SlotObject.SetString("label", GetMenuName(Skin.Skin));
|
||||||
|
SlotObject.SetBool("enabled", true);
|
||||||
|
TexturePath = "img://"$PathName(Skin.UITexture);
|
||||||
|
SlotObject.SetString("source", TexturePath);
|
||||||
|
|
||||||
|
DataProvider.SetElementObject(ItemIndex, SlotObject);
|
||||||
|
ItemIndex++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SlotObject = CreateObject( "Object" );
|
||||||
|
SlotObject.SetInt("ItemIndex", i);
|
||||||
|
SlotObject.SetString("label", Localize(SectionPath, KeyName$i, class'KFGFxMenu_Gear'.Default.KFCharacterInfoString));
|
||||||
|
SlotObject.SetBool("enabled", true);
|
||||||
|
TexturePath = "img://"$PathName(Skin.UITexture);
|
||||||
|
SlotObject.SetString("source", TexturePath);
|
||||||
|
|
||||||
|
DataProvider.SetElementObject(ItemIndex, SlotObject);
|
||||||
|
ItemIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MeshObject.SetObject("skinInfo", DataProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SetCurrentCharacterButtons()
|
||||||
|
{
|
||||||
|
local bool bCustom;
|
||||||
|
local GFxObject DataObject;
|
||||||
|
|
||||||
|
bCustom = ExtPRI.UsesCustomChar();
|
||||||
|
DataObject = CreateObject("Object");
|
||||||
|
|
||||||
|
DataObject.SetString( "selectedCharacter", (bIsCustomChar ? Repl(string(CurrentCharInfo.Name),"_"," ") : Localize(CharInfoPath, "CharacterName", class'KFGFxMenu_Gear'.Default.KFCharacterInfoString)) );
|
||||||
|
DataObject.SetString( "characterBio", (bIsCustomChar ? Repl(CurrentCharInfo.ArmMeshPackageName,"|","\n") : Localize(CharInfoPath, "Description", class'KFGFxMenu_Gear'.Default.KFCharacterInfoString)) );
|
||||||
|
DataObject.SetInt( "selectedCharacterIndex", bCustom ? ExtPRI.CustomCharacter.CharacterIndex : ExtPRI.RepCustomizationInfo.CharacterIndex );
|
||||||
|
|
||||||
|
SetObject( "selectedCharacter", DataObject);
|
||||||
|
|
||||||
|
//set head
|
||||||
|
SetGearButtons(bCustom ? ExtPRI.CustomCharacter.HeadMeshIndex : ExtPRI.RepCustomizationInfo.HeadMeshIndex, bCustom ? ExtPRI.CustomCharacter.HeadSkinIndex : ExtPRI.RepCustomizationInfo.HeadSkinIndex, class'KFGFxMenu_Gear'.Default.HeadMeshKey, class'KFGFxMenu_Gear'.Default.HeadSkinKey, class'KFGFxMenu_Gear'.Default.HeadFunctionKey);
|
||||||
|
//set body
|
||||||
|
SetGearButtons(bCustom ? ExtPRI.CustomCharacter.BodyMeshIndex : ExtPRI.RepCustomizationInfo.BodyMeshIndex, bCustom ? ExtPRI.CustomCharacter.BodySkinIndex : ExtPRI.RepCustomizationInfo.BodySkinIndex, class'KFGFxMenu_Gear'.Default.BodyMeshKey, class'KFGFxMenu_Gear'.Default.BodySkinKey, class'KFGFxMenu_Gear'.Default.BodyFunctionKey);
|
||||||
|
//set attachments
|
||||||
|
SetAttachmentButtons(class'KFGFxMenu_Gear'.Default.AttachmentKey, class'KFGFxMenu_Gear'.Default.AttachmentFunctionKey);
|
||||||
|
|
||||||
|
SetEmoteButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
function SetEmoteButton()
|
||||||
|
{
|
||||||
|
local GFxObject DataObject;
|
||||||
|
local int EmoteIndex;
|
||||||
|
|
||||||
|
EmoteIndex = class'KFEmoteList'.static.GetEmoteIndex( class'KFEmoteList'.static.GetEquippedEmoteId());
|
||||||
|
|
||||||
|
DataObject = CreateObject("Object");
|
||||||
|
if(EmoteIndex == 255)
|
||||||
|
{
|
||||||
|
DataObject.SetString( "selectedEmote", "");
|
||||||
|
DataObject.SetInt( "selectedEmoteIndex", 0 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DataObject.SetString( "selectedEmote", Localize(EmoteList[EmoteIndex].ItemName, "EmoteName", class'KFGFxMenu_Gear'.Default.KFCharacterInfoString));
|
||||||
|
DataObject.SetInt( "selectedEmoteIndex", 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SetObject("selectedEmote", DataObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Update the labels for our gear buttons */
|
||||||
|
function SetGearButtons(byte MeshIndex, byte SkinIndex, string MeshKey, string SkinKey, string sectionFunctionName)
|
||||||
|
{
|
||||||
|
local string SectionPath;
|
||||||
|
local string CurrentMesh;
|
||||||
|
local string SkinName, MeshName;
|
||||||
|
local GFxObject DataObject;
|
||||||
|
|
||||||
|
if( bWaitingCharList )
|
||||||
|
return;
|
||||||
|
|
||||||
|
DataObject = CreateObject("Object");
|
||||||
|
|
||||||
|
if(MeshIndex == `CLEARED_ATTACHMENT_INDEX)
|
||||||
|
{
|
||||||
|
DataObject.SetString( sectionFunctionName, class'KFGFxMenu_Gear'.Default.NoneString );
|
||||||
|
}
|
||||||
|
else if( bIsCustomChar )
|
||||||
|
{
|
||||||
|
if( MeshKey==class'KFGFxMenu_Gear'.Default.HeadMeshKey )
|
||||||
|
{
|
||||||
|
SkinName = GetMenuName(CurrentCharInfo.HeadVariants[MeshIndex].SkinVariations[SkinIndex].Skin);
|
||||||
|
MeshName = GetMenuNameStr(CurrentCharInfo.HeadVariants[MeshIndex].MeshName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SkinName = GetMenuName(CurrentCharInfo.BodyVariants[MeshIndex].SkinVariations[SkinIndex].Skin);
|
||||||
|
MeshName = GetMenuNameStr(CurrentCharInfo.BodyVariants[MeshIndex].MeshName);
|
||||||
|
}
|
||||||
|
DataObject.SetString( sectionFunctionName, MeshName @"\n" @SkinName );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CurrentMesh = MeshKey$MeshIndex;
|
||||||
|
SectionPath = CharInfoPath$"."$CurrentMesh;
|
||||||
|
|
||||||
|
SkinName = Localize(SectionPath, SkinKey$SkinIndex, class'KFGFxMenu_Gear'.Default.KFCharacterInfoString);
|
||||||
|
MeshName = Localize(CharInfoPath, CurrentMesh, class'KFGFxMenu_Gear'.Default.KFCharacterInfoString);
|
||||||
|
DataObject.SetString( sectionFunctionName, MeshName @"\n" @SkinName );
|
||||||
|
}
|
||||||
|
|
||||||
|
DataObject.SetInt( (sectionFunctionName$"Index"), MeshIndex);
|
||||||
|
DataObject.SetInt( (sectionFunctionName$"SkinIndex"), SkinIndex);
|
||||||
|
|
||||||
|
SetObject( sectionFunctionName, DataObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Update the labels for our currently equipped attachments */
|
||||||
|
function SetAttachmentButtons(string AttachmentMeshKey, string sectionFunctionName)
|
||||||
|
{
|
||||||
|
local string CurrentMesh, FinishedString;
|
||||||
|
local GFxObject DataObject;
|
||||||
|
local byte i, AttachmentIndex;
|
||||||
|
local bool bCustom;
|
||||||
|
|
||||||
|
if( bWaitingCharList )
|
||||||
|
return;
|
||||||
|
|
||||||
|
bCustom = ExtPRI.UsesCustomChar();
|
||||||
|
DataObject = CreateObject("Object");
|
||||||
|
|
||||||
|
for(i = 0; i < `MAX_COSMETIC_ATTACHMENTS; i++)
|
||||||
|
{
|
||||||
|
AttachmentIndex = bCustom ? ExtPRI.CustomCharacter.AttachmentMeshIndices[i] : ExtPRI.RepCustomizationInfo.AttachmentMeshIndices[i];
|
||||||
|
if( AttachmentIndex == `CLEARED_ATTACHMENT_INDEX )
|
||||||
|
{
|
||||||
|
FinishedString $= "----"$"\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CurrentMesh = AttachmentMeshKey$AttachmentIndex;
|
||||||
|
FinishedString $= (bIsCustomChar ? GetMenuNameStr(CurrentCharInfo.CosmeticVariants[AttachmentIndex].MeshName) : Localize(CharInfoPath, CurrentMesh, class'KFGFxMenu_Gear'.Default.KFCharacterInfoString))$"\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DataObject.SetString( sectionFunctionName, FinishedString );
|
||||||
|
|
||||||
|
SetObject( sectionFunctionName, DataObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
event OnClose()
|
||||||
|
{
|
||||||
|
local PlayerController PC;
|
||||||
|
|
||||||
|
super.OnClose();
|
||||||
|
|
||||||
|
GetGameViewportClient().HandleInputAxis = none;
|
||||||
|
|
||||||
|
if ( class'WorldInfo'.static.IsMenuLevel() )
|
||||||
|
{
|
||||||
|
Manager.ManagerObject.SetBool("backgroundVisible", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are alive, in game, with a playable pawn. switch back to first person view when leaving this menu
|
||||||
|
PC = GetPC();
|
||||||
|
if( PC != none && PC.WorldInfo.GRI.bMatchHasBegun && PC.Pawn != none && !PC.Pawn.IsA('KFPawn_Customization') )
|
||||||
|
{
|
||||||
|
PC.ServerCamera( 'FirstPerson' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event bool OnAxisModified( int ControllerId, name Key, float Delta, float DeltaTime, bool bGamepad )
|
||||||
|
{
|
||||||
|
if ( GetPC().PlayerInput.bUsingGamepad )
|
||||||
|
{
|
||||||
|
if ( Key == 'XboxTypeS_RightX' && Abs(Delta) > class'KFGFxMenu_Gear'.Default.ControllerRotationThreshold)
|
||||||
|
{
|
||||||
|
Callback_RotateCamera(Delta * class'KFGFxMenu_Gear'.Default.ControllerRotationRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================
|
||||||
|
// ActionScript Callbacks
|
||||||
|
//==============================================================
|
||||||
|
|
||||||
|
function Callback_Emote(byte Index)
|
||||||
|
{
|
||||||
|
local KFPlayerController KFPC;
|
||||||
|
|
||||||
|
KFPC = KFPlayerController(GetPC());
|
||||||
|
if( KFPC != none )
|
||||||
|
{
|
||||||
|
class'KFEmoteList'.static.SaveEquippedEmote(EmoteList[Index].ID);
|
||||||
|
|
||||||
|
if ( KFPawn_Customization(KFPC.Pawn) != none )
|
||||||
|
{
|
||||||
|
KFPawn_Customization(KFPC.Pawn).PlayEmoteAnimation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetEmoteButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
function Callback_RotateCamera( int RotationDirection )
|
||||||
|
{
|
||||||
|
local KFPlayerCamera PlayerCamera;
|
||||||
|
|
||||||
|
PlayerCamera = KFPlayerCamera( GetPC().PlayerCamera );
|
||||||
|
if ( PlayerCamera != none )
|
||||||
|
PlayerCamera.CustomizationCam.RotatedCamera( RotationDirection );
|
||||||
|
}
|
||||||
|
|
||||||
|
function Callback_EndRotateCamera()
|
||||||
|
{
|
||||||
|
local KFPlayerCamera PlayerCamera;
|
||||||
|
|
||||||
|
PlayerCamera = KFPlayerCamera( GetPC().PlayerCamera );
|
||||||
|
if ( PlayerCamera != none )
|
||||||
|
PlayerCamera.CustomizationCam.StartFadeRotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function Callback_Weapon( int ItemIndex, int SkinIndex )
|
||||||
|
{
|
||||||
|
local KFPawn_Customization KFP;
|
||||||
|
|
||||||
|
KFP = KFPawn_Customization(GetPC().Pawn);
|
||||||
|
if(KFP != none)
|
||||||
|
KFP.AttachWeaponByItemDefinition(SkinIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Callback_BodyCamera()
|
||||||
|
{
|
||||||
|
if ( KFPlayerCamera( GetPC().PlayerCamera ) != none )
|
||||||
|
KFPlayerCamera( GetPC().PlayerCamera ).CustomizationCam.SetBodyView( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
function Callback_HeadCamera()
|
||||||
|
{
|
||||||
|
if ( KFPlayerCamera( GetPC().PlayerCamera ) != none )
|
||||||
|
KFPlayerCamera( GetPC().PlayerCamera ).CustomizationCam.SetBodyView( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
function Callback_Character(byte Index)
|
||||||
|
{
|
||||||
|
ExtPRI.ChangeCharacter(Index,!ExtPRI.UsesCustomChar());
|
||||||
|
UpdateGear();
|
||||||
|
}
|
||||||
|
|
||||||
|
function Callback_Head( byte MeshIndex, byte SkinIndex )
|
||||||
|
{
|
||||||
|
if( !ExtPRI.UsesCustomChar() ) // Force client to setup custom character now for this server.
|
||||||
|
ExtPRI.ChangeCharacter(ExtPRI.RepCustomizationInfo.CharacterIndex,true);
|
||||||
|
ExtPRI.UpdateCustomization(CO_Head, MeshIndex, SkinIndex);
|
||||||
|
SetGearButtons(MeshIndex, SkinIndex, class'KFGFxMenu_Gear'.Default.HeadMeshKey, class'KFGFxMenu_Gear'.Default.HeadSkinKey, class'KFGFxMenu_Gear'.Default.HeadFunctionKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Callback_Body( byte MeshIndex, byte SkinIndex )
|
||||||
|
{
|
||||||
|
if( !ExtPRI.UsesCustomChar() ) // Force client to setup custom character now for this server.
|
||||||
|
ExtPRI.ChangeCharacter(ExtPRI.RepCustomizationInfo.CharacterIndex,true);
|
||||||
|
|
||||||
|
ExtPRI.UpdateCustomization(CO_Body, MeshIndex, SkinIndex);
|
||||||
|
|
||||||
|
// When assigning a new body mesh we may need to remove certain attachments
|
||||||
|
// refresh filters, and update the equipped accessories list
|
||||||
|
UpdateAttachmentsList(CurrentCharInfo.CosmeticVariants);
|
||||||
|
SetAttachmentButtons(class'KFGFxMenu_Gear'.Default.AttachmentKey, class'KFGFxMenu_Gear'.Default.AttachmentFunctionKey);
|
||||||
|
|
||||||
|
SetGearButtons(MeshIndex, SkinIndex, class'KFGFxMenu_Gear'.Default.BodyMeshKey, class'KFGFxMenu_Gear'.Default.BodySkinKey, class'KFGFxMenu_Gear'.Default.BodyFunctionKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Callback_Attachment( byte MeshIndex, byte SkinIndex )
|
||||||
|
{
|
||||||
|
local int SlotIndex;
|
||||||
|
local KFPawn KFP;
|
||||||
|
|
||||||
|
if( !ExtPRI.UsesCustomChar() ) // Force client to setup custom character now for this server.
|
||||||
|
ExtPRI.ChangeCharacter(ExtPRI.RepCustomizationInfo.CharacterIndex,true);
|
||||||
|
|
||||||
|
KFP = KFPawn(GetPC().Pawn);
|
||||||
|
if( KFP!=None )
|
||||||
|
{
|
||||||
|
if( MeshIndex==`CLEARED_ATTACHMENT_INDEX )
|
||||||
|
ExtPRI.RemoveAttachments();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
class'ExtCharacterInfo'.Static.DetachConflictingAttachments(CurrentCharInfo, MeshIndex, KFP, ExtPRI);
|
||||||
|
SlotIndex = CurrentCharInfo.GetAttachmentSlotIndex(MeshIndex, KFP);
|
||||||
|
ExtPRI.UpdateCustomization(CO_Attachment, MeshIndex, SkinIndex, SlotIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetAttachmentButtons(class'KFGFxMenu_Gear'.Default.AttachmentKey, class'KFGFxMenu_Gear'.Default.AttachmentFunctionKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
SubWidgetBindings.Add((WidgetName="customizationComponent",WidgetClass=class'KFGFxObject_Container'))
|
||||||
|
SubWidgetBindings.Add((WidgetName="perkSelectionContainer",WidgetClass=class'KFGFxGearContainer_PerksSelection'))
|
||||||
|
}
|
78
ServerExt/Classes/ExtMenu_Perks.uc
Normal file
78
ServerExt/Classes/ExtMenu_Perks.uc
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
class ExtMenu_Perks extends KFGFxMenu_Perks;
|
||||||
|
|
||||||
|
var ExtPlayerController ExtKFPC;
|
||||||
|
var Ext_PerkBase ExtPrevPerk;
|
||||||
|
|
||||||
|
function OnOpen()
|
||||||
|
{
|
||||||
|
KFPC = KFPlayerController( GetPC() );
|
||||||
|
if( ExtKFPC == none )
|
||||||
|
ExtKFPC = ExtPlayerController(KFPC);
|
||||||
|
|
||||||
|
if( ExtKFPC.ActivePerkManager==None )
|
||||||
|
{
|
||||||
|
ExtKFPC.SetTimer(0.25,true,'OnOpen',Self);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ExtKFPC.ClearTimer('OnOpen',Self);
|
||||||
|
|
||||||
|
if( ExtPrevPerk==None )
|
||||||
|
ExtPrevPerk = ExtKFPC.ActivePerkManager.CurrentPerk;
|
||||||
|
|
||||||
|
ExUpdateContainers(ExtPrevPerk);
|
||||||
|
SetBool( "locked", true);
|
||||||
|
}
|
||||||
|
final function ExUpdateContainers( Ext_PerkBase PerkClass )
|
||||||
|
{
|
||||||
|
LastPerkLevel = PerkClass.CurrentLevel;
|
||||||
|
if ( ExtPerksContainer_Header(HeaderContainer)!=none )
|
||||||
|
ExtPerksContainer_Header(HeaderContainer).ExUpdatePerkHeader( PerkClass );
|
||||||
|
if ( ExtPerksContainer_Details(DetailsContainer)!=none )
|
||||||
|
{
|
||||||
|
ExtPerksContainer_Details(DetailsContainer).ExUpdateDetails( PerkClass );
|
||||||
|
ExtPerksContainer_Details(DetailsContainer).ExUpdatePassives( PerkClass );
|
||||||
|
}
|
||||||
|
if ( SelectionContainer != none )
|
||||||
|
SelectionContainer.UpdatePerkSelection(ExtKFPC.ActivePerkManager.UserPerks.Find(PerkClass));
|
||||||
|
}
|
||||||
|
|
||||||
|
function CheckTiersForPopup();
|
||||||
|
|
||||||
|
event OnClose()
|
||||||
|
{
|
||||||
|
ExtPrevPerk = None;
|
||||||
|
if ( ExtKFPC != none )
|
||||||
|
ExtKFPC.ClearTimer('OnOpen',Self);
|
||||||
|
super.OnClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
function PerkChanged( byte NewPerkIndex, bool bClickedIndex)
|
||||||
|
{
|
||||||
|
ExUpdateContainers(ExtPrevPerk);
|
||||||
|
}
|
||||||
|
|
||||||
|
function OneSecondLoop()
|
||||||
|
{
|
||||||
|
if( ExtPrevPerk!=None && LastPerkLevel!=ExtPrevPerk.CurrentLevel )
|
||||||
|
ExUpdateContainers(ExtPrevPerk);
|
||||||
|
}
|
||||||
|
|
||||||
|
function UpdateLock();
|
||||||
|
function SavePerkData();
|
||||||
|
|
||||||
|
function Callback_PerkSelected(byte NewPerkIndex, bool bClickedIndex)
|
||||||
|
{
|
||||||
|
ExtPrevPerk = ExtKFPC.ActivePerkManager.UserPerks[NewPerkIndex];
|
||||||
|
ExUpdateContainers(ExtPrevPerk);
|
||||||
|
|
||||||
|
ExtKFPC.PendingPerkClass = ExtPrevPerk.Class;
|
||||||
|
ExtKFPC.SwitchToPerk(ExtPrevPerk.Class);
|
||||||
|
}
|
||||||
|
function Callback_SkillSelectionOpened();
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
SubWidgetBindings(0)=(WidgetClass=Class'ExtPerksContainer_Selection')
|
||||||
|
SubWidgetBindings(1)=(WidgetClass=Class'ExtPerksContainer_Header')
|
||||||
|
SubWidgetBindings(3)=(WidgetClass=Class'ExtPerksContainer_Details')
|
||||||
|
}
|
54
ServerExt/Classes/ExtMenu_Trader.uc
Normal file
54
ServerExt/Classes/ExtMenu_Trader.uc
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
class ExtMenu_Trader extends KFGFxMenu_Trader;
|
||||||
|
|
||||||
|
var ExtPlayerController ExtKFPC;
|
||||||
|
var Ext_PerkBase ExLastPerkClass;
|
||||||
|
|
||||||
|
function InitializeMenu( KFGFxMoviePlayer_Manager InManager )
|
||||||
|
{
|
||||||
|
Super.InitializeMenu(InManager);
|
||||||
|
ExtKFPC = ExtPlayerController ( GetPC() );
|
||||||
|
}
|
||||||
|
function int GetPerkIndex()
|
||||||
|
{
|
||||||
|
return (ExtKFPC.ActivePerkManager!=None ? Max(ExtKFPC.ActivePerkManager.UserPerks.Find(ExtKFPC.ActivePerkManager.CurrentPerk),0) : 0);
|
||||||
|
}
|
||||||
|
function UpdatePlayerInfo()
|
||||||
|
{
|
||||||
|
if( ExtKFPC != none && PlayerInfoContainer != none )
|
||||||
|
{
|
||||||
|
PlayerInfoContainer.SetPerkInfo();
|
||||||
|
PlayerInfoContainer.SetPerkList();
|
||||||
|
if( ExtKFPC.ActivePerkManager!=None && ExtKFPC.ActivePerkManager.CurrentPerk!=ExLastPerkClass)
|
||||||
|
{
|
||||||
|
ExLastPerkClass = ExtKFPC.ActivePerkManager.CurrentPerk;
|
||||||
|
OnPerkChanged(GetPerkIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
RefreshItemComponents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Callback_PerkChanged(int PerkIndex)
|
||||||
|
{
|
||||||
|
ExtKFPC.PendingPerkClass = ExtKFPC.ActivePerkManager.UserPerks[PerkIndex].Class;
|
||||||
|
ExtKFPC.SwitchToPerk(ExtKFPC.PendingPerkClass);
|
||||||
|
|
||||||
|
if( PlayerInventoryContainer != none )
|
||||||
|
{
|
||||||
|
PlayerInventoryContainer.UpdateLock();
|
||||||
|
}
|
||||||
|
UpdatePlayerInfo();
|
||||||
|
|
||||||
|
// Refresht he UI
|
||||||
|
RefreshItemComponents();
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
SubWidgetBindings.Remove((WidgetName="filterContainer",WidgetClass=class'KFGFxTraderContainer_Filter'))
|
||||||
|
SubWidgetBindings.Add((WidgetName="filterContainer",WidgetClass=class'ExtTraderContainer_Filter'))
|
||||||
|
SubWidgetBindings.Remove((WidgetName="shopContainer",WidgetClass=class'KFGFxTraderContainer_Store'))
|
||||||
|
SubWidgetBindings.Add((WidgetName="shopContainer",WidgetClass=class'ExtTraderContainer_Store'))
|
||||||
|
SubWidgetBindings.Remove((WidgetName="playerInfoContainer",WidgetClass=class'KFGFxTraderContainer_PlayerInfo'))
|
||||||
|
SubWidgetBindings.Add((WidgetName="playerInfoContainer",WidgetClass=class'ExtTraderContainer_PlayerInfo'))
|
||||||
|
}
|
108
ServerExt/Classes/ExtMoviePlayer_HUD.uc
Normal file
108
ServerExt/Classes/ExtMoviePlayer_HUD.uc
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
Class ExtMoviePlayer_HUD extends KFGFxMoviePlayer_HUD;
|
||||||
|
|
||||||
|
function TickHud(float DeltaTime)
|
||||||
|
{
|
||||||
|
local PlayerController PC;
|
||||||
|
|
||||||
|
PC = GetPC();
|
||||||
|
if( PC!=none && PC.PlayerInput!=None )
|
||||||
|
Super.TickHud(DeltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
final function ShowKillMessageX(PlayerReplicationInfo PRI1, PlayerReplicationInfo PRI2, optional string VictimStr, optional bool bDeathMessage = false, optional class<Pawn> PawnOther )
|
||||||
|
{
|
||||||
|
local GFxObject DataObject;
|
||||||
|
local bool bHumanDeath;
|
||||||
|
local string KilledName, KillerName, KilledIconpath, KillerIconPath;
|
||||||
|
local string KillerTextColor, KilledTextColor;
|
||||||
|
|
||||||
|
if(KFPC == none)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( KFGXHUDManager != none )
|
||||||
|
{
|
||||||
|
if(PawnOther != none)
|
||||||
|
{
|
||||||
|
if( bDeathMessage )
|
||||||
|
{
|
||||||
|
KillerTextColor = ZEDTeamTextColor;
|
||||||
|
KillerName = class'KFExtendedHUD'.Static.GetNameOf(PawnOther);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KilledName = class'KFExtendedHUD'.Static.GetNameOf(PawnOther);
|
||||||
|
bHumanDeath = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( (PawnOther==None || !bDeathMessage) && PRI1 != none)
|
||||||
|
{
|
||||||
|
if(PRI1.GetTeamNum() == 255)
|
||||||
|
{
|
||||||
|
KillerTextColor = ZEDTeamTextColor;
|
||||||
|
KillerIconpath = "img://"$class'KFPerk_Monster'.static.GetPerkIconPath();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KillerTextColor = HumanTeamTextColor;
|
||||||
|
if( ExtPlayerReplicationInfo(PRI1)!=None && ExtPlayerReplicationInfo(PRI1).ECurrentPerk!=None )
|
||||||
|
KillerIconpath = ExtPlayerReplicationInfo(PRI1).ECurrentPerk.static.GetPerkIconPath(0);
|
||||||
|
}
|
||||||
|
KillerName = PRI1.PlayerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(PRI2 != none)
|
||||||
|
{
|
||||||
|
if(PRI2.GetTeamNum() == class'KFTeamInfo_Human'.default.TeamIndex)
|
||||||
|
{
|
||||||
|
bHumanDeath = true;
|
||||||
|
KilledTextColor = HumanTeamTextColor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KilledTextColor = ZEDTeamTextColor;
|
||||||
|
bHumanDeath = false;
|
||||||
|
}
|
||||||
|
KilledName = PRI2.PlayerName;
|
||||||
|
if( ExtPlayerReplicationInfo(PRI2)!=None && ExtPlayerReplicationInfo(PRI2).ECurrentPerk!=None )
|
||||||
|
KilledIconpath = ExtPlayerReplicationInfo(PRI2).ECurrentPerk.static.GetPerkIconPath(0);
|
||||||
|
}
|
||||||
|
else if( VictimStr!="" )
|
||||||
|
{
|
||||||
|
KilledTextColor = HumanTeamTextColor;
|
||||||
|
KilledIconpath = "img://"$class'KFPerk_Monster'.static.GetPerkIconPath();
|
||||||
|
bHumanDeath = false;
|
||||||
|
KilledName = VictimStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataObject = CreateObject("Object");
|
||||||
|
|
||||||
|
DataObject.SetBool("humanDeath", bHumanDeath);
|
||||||
|
|
||||||
|
DataObject.SetString("killedName", KilledName);
|
||||||
|
DataObject.SetString("killedTextColor", KilledTextColor);
|
||||||
|
DataObject.SetString("killedIcon", KilledIconpath);
|
||||||
|
|
||||||
|
DataObject.SetString("killerName", KillerName);
|
||||||
|
DataObject.SetString("killerTextColor", KillerTextColor);
|
||||||
|
DataObject.SetString("killerIcon", KillerIconpath);
|
||||||
|
|
||||||
|
//temp remove when rest of design catches up
|
||||||
|
DataObject.SetString("text", KillerName@KilledName);
|
||||||
|
|
||||||
|
KFGXHUDManager.SetObject("newBark", DataObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
WidgetBindings.Remove((WidgetName="SpectatorInfoWidget",WidgetClass=class'KFGFxHUD_SpectatorInfo'))
|
||||||
|
WidgetBindings.Add((WidgetName="SpectatorInfoWidget",WidgetClass=class'ExtHUD_SpectatorInfo'))
|
||||||
|
WidgetBindings.Remove((WidgetName="PlayerStatWidgetMC",WidgetClass=class'KFGFxHUD_PlayerStatus'))
|
||||||
|
WidgetBindings.Add((WidgetName="PlayerStatWidgetMC",WidgetClass=class'ExtHUD_PlayerStatus'))
|
||||||
|
WidgetBindings.Remove((WidgetName="PlayerBackpackWidget",WidgetClass=class'KFGFxHUD_PlayerBackpack'))
|
||||||
|
WidgetBindings.Add((WidgetName="PlayerBackpackWidget",WidgetClass=class'ExtHUD_PlayerBackpack'))
|
||||||
|
WidgetBindings.Remove((WidgetName="WaveInfoContainer",WidgetClass=class'KFGFxHUD_WaveInfo'))
|
||||||
|
WidgetBindings.Add((WidgetName="WaveInfoContainer",WidgetClass=class'ExtHUD_WaveInfo'))
|
||||||
|
WidgetBindings.Remove((WidgetName="bossHealthBar", WidgetClass=class'KFGFxWidget_BossHealthBar'))
|
||||||
|
WidgetBindings.Add((WidgetName="bossHealthBar", WidgetClass=class'ExtWidget_BossHealthBar'))
|
||||||
|
}
|
80
ServerExt/Classes/ExtMoviePlayer_Manager.uc
Normal file
80
ServerExt/Classes/ExtMoviePlayer_Manager.uc
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
Class ExtMoviePlayer_Manager extends KFGFxMoviePlayer_Manager;
|
||||||
|
|
||||||
|
var ExtMenu_Gear EGearMenu;
|
||||||
|
var KF2GUIController MyGUIController;
|
||||||
|
|
||||||
|
event bool WidgetInitialized(name WidgetName, name WidgetPath, GFxObject Widget)
|
||||||
|
{
|
||||||
|
local PlayerController PC;
|
||||||
|
|
||||||
|
switch ( WidgetName )
|
||||||
|
{
|
||||||
|
case 'gearMenu':
|
||||||
|
PC = GetPC();
|
||||||
|
if( PC.PlayerReplicationInfo.bReadyToPlay && PC.WorldInfo.GRI.bMatchHasBegun )
|
||||||
|
return true;
|
||||||
|
if (EGearMenu == none)
|
||||||
|
{
|
||||||
|
EGearMenu = ExtMenu_Gear(Widget);
|
||||||
|
EGearMenu.InitializeMenu(self);
|
||||||
|
}
|
||||||
|
OnMenuOpen( WidgetPath, EGearMenu );
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return Super.WidgetInitialized(WidgetName,WidgetPath,Widget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function LaunchMenus( optional bool bForceSkipLobby )
|
||||||
|
{
|
||||||
|
local GFxWidgetBinding WidgetBinding;
|
||||||
|
local bool bSkippedLobby;
|
||||||
|
|
||||||
|
// Add either the in game party or out of game party widget
|
||||||
|
WidgetBinding.WidgetName = 'partyWidget';
|
||||||
|
bSkippedLobby = bForceSkipLobby || CheckSkipLobby();
|
||||||
|
WidgetBinding.WidgetClass = class'ExtWidget_PartyInGame';
|
||||||
|
ManagerObject.SetBool("backgroundVisible", false);
|
||||||
|
ManagerObject.SetBool("IISMovieVisible", false);
|
||||||
|
if(bSkippedLobby)
|
||||||
|
CurrentBackgroundMovie.Stop();
|
||||||
|
|
||||||
|
WidgetBindings.AddItem(WidgetBinding);
|
||||||
|
|
||||||
|
// Load the platform-specific graphics options menu
|
||||||
|
switch( class'KFGameEngine'.static.GetPlatform() )
|
||||||
|
{
|
||||||
|
case PLATFORM_PC_DX10:
|
||||||
|
WidgetBinding.WidgetName = 'optionsGraphicsMenu';
|
||||||
|
WidgetBinding.WidgetClass = class'KFGFxOptionsMenu_Graphics_DX10';
|
||||||
|
WidgetBindings.AddItem(WidgetBinding);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WidgetBinding.WidgetName = 'optionsGraphicsMenu';
|
||||||
|
WidgetBinding.WidgetClass = class'KFGFxOptionsMenu_Graphics';
|
||||||
|
WidgetBindings.AddItem(WidgetBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bSkippedLobby)
|
||||||
|
{
|
||||||
|
LoadWidgets(WidgetPaths);
|
||||||
|
OpenMenu(UI_Start);
|
||||||
|
AllowCloseMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// do this stuff in case CheckSkipLobby failed
|
||||||
|
if( bForceSkipLobby )
|
||||||
|
{
|
||||||
|
bAfterLobby = true;
|
||||||
|
CloseMenus(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
WidgetBindings.Remove((WidgetName="PerksMenu",WidgetClass=class'KFGFxMenu_Perks'))
|
||||||
|
WidgetBindings.Add((WidgetName="PerksMenu",WidgetClass=class'ExtMenu_Perks'))
|
||||||
|
WidgetBindings.Remove((WidgetName="gearMenu",WidgetClass=class'KFGFxMenu_Gear'))
|
||||||
|
WidgetBindings.Add((WidgetName="gearMenu",WidgetClass=class'ExtMenu_Gear'))
|
||||||
|
WidgetBindings.Remove((WidgetName="traderMenu",WidgetClass=class'KFGFxMenu_Trader'))
|
||||||
|
WidgetBindings.Add((WidgetName="traderMenu",WidgetClass=class'ExtMenu_Trader'))
|
||||||
|
}
|
56
ServerExt/Classes/ExtPawn_Customization.uc
Normal file
56
ServerExt/Classes/ExtPawn_Customization.uc
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
class ExtPawn_Customization extends KFPawn_Customization;
|
||||||
|
|
||||||
|
simulated function KFCharacterInfoBase GetCharacterInfo()
|
||||||
|
{
|
||||||
|
if( ExtPlayerReplicationInfo(PlayerReplicationInfo)!=None )
|
||||||
|
return ExtPlayerReplicationInfo(PlayerReplicationInfo).GetSelectedArch();
|
||||||
|
return Super.GetCharacterInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function SetCharacterArch( KFCharacterInfoBase Info, optional bool bForce )
|
||||||
|
{
|
||||||
|
local KFPlayerReplicationInfo KFPRI;
|
||||||
|
|
||||||
|
KFPRI = KFPlayerReplicationInfo( PlayerReplicationInfo );
|
||||||
|
if (Info != CharacterArch || bForce)
|
||||||
|
{
|
||||||
|
// Set Family Info
|
||||||
|
CharacterArch = Info;
|
||||||
|
CharacterArch.SetCharacterFromArch( self, KFPRI );
|
||||||
|
class'ExtCharacterInfo'.Static.SetCharacterMeshFromArch( KFCharacterInfo_Human(CharacterArch), self, KFPRI );
|
||||||
|
class'ExtCharacterInfo'.Static.SetFirstPersonArmsFromArch( KFCharacterInfo_Human(CharacterArch), self, KFPRI );
|
||||||
|
|
||||||
|
SetCharacterAnimationInfo();
|
||||||
|
|
||||||
|
// Sounds
|
||||||
|
SoundGroupArch = Info.SoundGroupArch;
|
||||||
|
|
||||||
|
if (WorldInfo.NetMode != NM_DedicatedServer)
|
||||||
|
{
|
||||||
|
// refresh weapon attachment (attachment bone may have changed)
|
||||||
|
if (WeaponAttachmentTemplate != None)
|
||||||
|
{
|
||||||
|
WeaponAttachmentChanged(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( CharacterArch != none )
|
||||||
|
{
|
||||||
|
if( CharacterArch.VoiceGroupArchName != "" )
|
||||||
|
VoiceGroupArch = class<KFPawnVoiceGroup>(class'ExtCharacterInfo'.Static.SafeLoadObject(CharacterArch.VoiceGroupArchName, class'Class'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bool Died(Controller Killer, class<DamageType> DamageType, vector HitLocation)
|
||||||
|
{
|
||||||
|
// Destroy this pawn if player leaves.
|
||||||
|
Destroy();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
bCollideActors=false
|
||||||
|
bBlockActors=false
|
||||||
|
}
|
645
ServerExt/Classes/ExtPerkManager.uc
Normal file
645
ServerExt/Classes/ExtPerkManager.uc
Normal file
@ -0,0 +1,645 @@
|
|||||||
|
/*
|
||||||
|
Extended Perk Manager
|
||||||
|
Written by Marco
|
||||||
|
*/
|
||||||
|
Class ExtPerkManager extends KFPerk;
|
||||||
|
|
||||||
|
enum EReplicateState
|
||||||
|
{
|
||||||
|
REP_CustomCharacters,
|
||||||
|
REP_CustomInventory,
|
||||||
|
REP_PerkClasses,
|
||||||
|
REP_Done
|
||||||
|
};
|
||||||
|
const CUR_SaveVersion=2;
|
||||||
|
|
||||||
|
var int UserDataVersion;
|
||||||
|
var transient float LastNapalmTime;
|
||||||
|
|
||||||
|
// Server -> Client rep status
|
||||||
|
var byte RepState;
|
||||||
|
var int RepIndex;
|
||||||
|
|
||||||
|
var array<Ext_PerkBase> UserPerks;
|
||||||
|
var Ext_PerkBase CurrentPerk;
|
||||||
|
var int ExpUpStatus[2];
|
||||||
|
var string StrPerkName;
|
||||||
|
|
||||||
|
var ExtPlayerReplicationInfo PRIOwner;
|
||||||
|
var Controller PlayerOwner;
|
||||||
|
|
||||||
|
// Stats
|
||||||
|
var int TotalEXP,TotalKills,TotalPlayTime;
|
||||||
|
|
||||||
|
var bool bStatsDirty,bServerReady,bUserStatsBroken,bCurrentlyHealing;
|
||||||
|
|
||||||
|
replication
|
||||||
|
{
|
||||||
|
// Things the server should send to the client.
|
||||||
|
if ( bNetDirty )
|
||||||
|
CurrentPerk;
|
||||||
|
}
|
||||||
|
|
||||||
|
final function SetGrenadeCap( byte AddedCap )
|
||||||
|
{
|
||||||
|
MaxGrenadeCount = Default.MaxGrenadeCount + AddedCap;
|
||||||
|
if( RepState==REP_Done )
|
||||||
|
ClientSetGrenadeCap(MaxGrenadeCount);
|
||||||
|
}
|
||||||
|
simulated reliable client function ClientSetGrenadeCap( byte NewCap )
|
||||||
|
{
|
||||||
|
MaxGrenadeCount = NewCap;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bool ApplyPerkClass( class<Ext_PerkBase> P )
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
for( i=0; i<UserPerks.Length; ++i )
|
||||||
|
if( UserPerks[i].Class==P )
|
||||||
|
{
|
||||||
|
ApplyPerk(UserPerks[i]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function bool ApplyPerkName( string S )
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
for( i=0; i<UserPerks.Length; ++i )
|
||||||
|
if( string(UserPerks[i].Class.Name)~=S )
|
||||||
|
{
|
||||||
|
ApplyPerk(UserPerks[i]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function ApplyPerk( Ext_PerkBase P )
|
||||||
|
{
|
||||||
|
if( P==None )
|
||||||
|
return;
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.DeactivateTraits();
|
||||||
|
bStatsDirty = true;
|
||||||
|
CurrentPerk = P;
|
||||||
|
if( PRIOwner!=None )
|
||||||
|
{
|
||||||
|
PRIOwner.ECurrentPerk = P.Class;
|
||||||
|
P.UpdatePRILevel();
|
||||||
|
}
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.ActivateTraits();
|
||||||
|
}
|
||||||
|
simulated final function Ext_PerkBase FindPerk( class<Ext_PerkBase> P )
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
for( i=0; i<UserPerks.Length; ++i )
|
||||||
|
if( UserPerks[i].Class==P )
|
||||||
|
return UserPerks[i];
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function PostBeginPlay()
|
||||||
|
{
|
||||||
|
SetTimer(0.01,false,'InitPerks');
|
||||||
|
if( WorldInfo.NetMode!=NM_Client )
|
||||||
|
SetTimer(1,true,'CheckPlayTime');
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function InitPerks()
|
||||||
|
{
|
||||||
|
local Ext_PerkBase P;
|
||||||
|
|
||||||
|
if( WorldInfo.NetMode==NM_Client )
|
||||||
|
{
|
||||||
|
foreach DynamicActors(class'Ext_PerkBase',P)
|
||||||
|
if( P.PerkManager!=Self )
|
||||||
|
RegisterPerk(P);
|
||||||
|
}
|
||||||
|
else if( PRIOwner!=PlayerOwner.PlayerReplicationInfo ) // See if was assigned an inactive PRI.
|
||||||
|
{
|
||||||
|
PRIOwner = ExtPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo);
|
||||||
|
if( PRIOwner!=None )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
{
|
||||||
|
PRIOwner.ECurrentPerk = CurrentPerk.Class;
|
||||||
|
CurrentPerk.UpdatePRILevel();
|
||||||
|
}
|
||||||
|
PRIOwner.RepKills = TotalKills;
|
||||||
|
PRIOwner.RepEXP = TotalEXP;
|
||||||
|
PRIOwner.SetInitPlayTime(TotalPlayTime);
|
||||||
|
PRIOwner.PerkManager = Self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function CheckPlayTime()
|
||||||
|
{
|
||||||
|
++TotalPlayTime; // Stats.
|
||||||
|
}
|
||||||
|
function ServerInitPerks()
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
for( i=0; i<UserPerks.Length; ++i )
|
||||||
|
UserPerks[i].SetInitialLevel();
|
||||||
|
bServerReady = true;
|
||||||
|
CurrentPerk = None;
|
||||||
|
if( StrPerkName!="" )
|
||||||
|
ApplyPerkName(StrPerkName);
|
||||||
|
if( CurrentPerk==None )
|
||||||
|
ApplyPerk(UserPerks[Rand(UserPerks.Length)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function RegisterPerk( Ext_PerkBase P )
|
||||||
|
{
|
||||||
|
UserPerks[UserPerks.Length] = P;
|
||||||
|
P.PerkManager = Self;
|
||||||
|
}
|
||||||
|
simulated function UnregisterPerk( Ext_PerkBase P )
|
||||||
|
{
|
||||||
|
UserPerks.RemoveItem(P);
|
||||||
|
P.PerkManager = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Destroyed()
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
for( i=(UserPerks.Length-1); i>=0; --i )
|
||||||
|
{
|
||||||
|
UserPerks[i].PerkManager = None;
|
||||||
|
UserPerks[i].Destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function EarnedEXP( int EXP, optional byte Mode )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
{
|
||||||
|
// Limit how much EXP we got for healing and welding.
|
||||||
|
switch( Mode )
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
ExpUpStatus[0]+=EXP;
|
||||||
|
EXP = ExpUpStatus[0]/CurrentPerk.WeldExpUpNum;
|
||||||
|
if( EXP>0 )
|
||||||
|
ExpUpStatus[0]-=(EXP*CurrentPerk.WeldExpUpNum);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ExpUpStatus[1]+=EXP;
|
||||||
|
EXP = ExpUpStatus[1]/CurrentPerk.HealExpUpNum;
|
||||||
|
if( EXP>0 )
|
||||||
|
ExpUpStatus[1]-=(EXP*CurrentPerk.HealExpUpNum);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( EXP>0 && CurrentPerk.EarnedEXP(EXP) )
|
||||||
|
{
|
||||||
|
TotalEXP+=EXP;
|
||||||
|
PRIOwner.RepEXP+=EXP;
|
||||||
|
bStatsDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// XML stat writing
|
||||||
|
function OutputXML( ExtStatWriter Data )
|
||||||
|
{
|
||||||
|
local string S;
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
Data.StartIntendent("user","ver",string(CUR_SaveVersion));
|
||||||
|
Data.WriteValue("id64",OnlineSubsystemSteamworks(class'GameEngine'.Static.GetOnlineSubsystem()).UniqueNetIdToInt64(PRIOwner.UniqueId));
|
||||||
|
Data.WriteValue("name",PRIOwner.PlayerName);
|
||||||
|
Data.WriteValue("exp",string(TotalEXP));
|
||||||
|
Data.WriteValue("kills",string(TotalKills));
|
||||||
|
Data.WriteValue("time",string(TotalPlayTime));
|
||||||
|
if( ExtPlayerController(Owner)!=None && ExtPlayerController(Owner).PendingPerkClass!=None )
|
||||||
|
S = string(ExtPlayerController(Owner).PendingPerkClass.Name);
|
||||||
|
else S = (CurrentPerk!=None ? string(CurrentPerk.Class.Name) : "None");
|
||||||
|
Data.WriteValue("activeperk",S);
|
||||||
|
|
||||||
|
for( i=0; i<UserPerks.Length; ++i )
|
||||||
|
if( UserPerks[i].HasAnyProgress() )
|
||||||
|
UserPerks[i].OutputXML(Data);
|
||||||
|
|
||||||
|
Data.EndIntendent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data saving.
|
||||||
|
function SaveData( ExtSaveDataBase Data )
|
||||||
|
{
|
||||||
|
local int i,o;
|
||||||
|
|
||||||
|
Data.FlushData();
|
||||||
|
Data.SetSaveVersion(++UserDataVersion);
|
||||||
|
Data.SetArVer(CUR_SaveVersion);
|
||||||
|
|
||||||
|
// Write global stats.
|
||||||
|
Data.SaveInt(TotalEXP,3);
|
||||||
|
Data.SaveInt(TotalKills,3);
|
||||||
|
Data.SaveInt(TotalPlayTime,3);
|
||||||
|
|
||||||
|
// Write character.
|
||||||
|
if( PRIOwner!=None )
|
||||||
|
PRIOwner.SaveCustomCharacter(Data);
|
||||||
|
else class'ExtPlayerReplicationInfo'.Static.DummySaveChar(Data);
|
||||||
|
|
||||||
|
// Write selected perk.
|
||||||
|
if( ExtPlayerController(Owner)!=None && ExtPlayerController(Owner).PendingPerkClass!=None )
|
||||||
|
Data.SaveStr(string(ExtPlayerController(Owner).PendingPerkClass.Name));
|
||||||
|
else Data.SaveStr(CurrentPerk!=None ? string(CurrentPerk.Class.Name) : "");
|
||||||
|
|
||||||
|
// Count how many progressed perks we have.
|
||||||
|
o = 0;
|
||||||
|
for( i=0; i<UserPerks.Length; ++i )
|
||||||
|
if( UserPerks[i].HasAnyProgress() )
|
||||||
|
++o;
|
||||||
|
|
||||||
|
// Then write count we have.
|
||||||
|
Data.SaveInt(o);
|
||||||
|
|
||||||
|
// Then perk stats.
|
||||||
|
for( i=0; i<UserPerks.Length; ++i )
|
||||||
|
{
|
||||||
|
if( !UserPerks[i].HasAnyProgress() ) // Skip this perk.
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Data.SaveStr(string(UserPerks[i].Class.Name));
|
||||||
|
o = Data.TellOffset(); // Mark checkpoint.
|
||||||
|
Data.SaveInt(0,1); // Reserve space for later.
|
||||||
|
UserPerks[i].SaveData(Data);
|
||||||
|
|
||||||
|
// Now save the skip offset for perk data incase perk gets removed from server.
|
||||||
|
Data.SeekOffset(o);
|
||||||
|
Data.SaveInt(Data.TotalSize(),1);
|
||||||
|
Data.ToEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data loading.
|
||||||
|
function LoadData( ExtSaveDataBase Data )
|
||||||
|
{
|
||||||
|
local int i,j,l,o;
|
||||||
|
local string S;
|
||||||
|
|
||||||
|
Data.ToStart();
|
||||||
|
UserDataVersion = Data.GetSaveVersion();
|
||||||
|
|
||||||
|
// Read global stats.
|
||||||
|
TotalEXP = Data.ReadInt(3);
|
||||||
|
TotalKills = Data.ReadInt(3);
|
||||||
|
TotalPlayTime = Data.ReadInt(3);
|
||||||
|
|
||||||
|
// Read character.
|
||||||
|
if( PRIOwner!=None )
|
||||||
|
{
|
||||||
|
PRIOwner.RepKills = TotalKills;
|
||||||
|
PRIOwner.RepEXP = TotalEXP;
|
||||||
|
PRIOwner.SetInitPlayTime(TotalPlayTime);
|
||||||
|
PRIOwner.LoadCustomCharacter(Data);
|
||||||
|
}
|
||||||
|
else class'ExtPlayerReplicationInfo'.Static.DummyLoadChar(Data);
|
||||||
|
|
||||||
|
// Find selected perk.
|
||||||
|
CurrentPerk = None;
|
||||||
|
StrPerkName = Data.ReadStr();
|
||||||
|
|
||||||
|
l = Data.ReadInt(); // Perk stats length.
|
||||||
|
for( i=0; i<l; ++i )
|
||||||
|
{
|
||||||
|
S = Data.ReadStr();
|
||||||
|
o = Data.ReadInt(1); // Read skip offset.
|
||||||
|
Data.PushEOFLimit(o);
|
||||||
|
for( j=0; j<UserPerks.Length; ++j )
|
||||||
|
if( S~=string(UserPerks[j].Class.Name) )
|
||||||
|
{
|
||||||
|
UserPerks[j].LoadData(Data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Data.PopEOFLimit();
|
||||||
|
Data.SeekOffset(o); // Jump to end of this section.
|
||||||
|
}
|
||||||
|
bStatsDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function AddDefaultInventory( KFPawn P )
|
||||||
|
{
|
||||||
|
local KFInventoryManager KFIM;
|
||||||
|
|
||||||
|
if( P != none && P.InvManager != none )
|
||||||
|
{
|
||||||
|
KFIM = KFInventoryManager(P.InvManager);
|
||||||
|
if( KFIM != none )
|
||||||
|
{
|
||||||
|
//Grenades added on spawn
|
||||||
|
KFIM.GiveInitialGrenadeCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.AddDefaultInventory(P);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function PlayerDied()
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.PlayerDied();
|
||||||
|
}
|
||||||
|
|
||||||
|
function PreNotifyPlayerLeave()
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.DeactivateTraits();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start client replication of perks data.
|
||||||
|
// Call this once the stats has been properly loaded serverside!
|
||||||
|
function InitiateClientRep()
|
||||||
|
{
|
||||||
|
RepState = 0;
|
||||||
|
RepIndex = 0;
|
||||||
|
SetTimer(0.01,true,'ReplicateTimer');
|
||||||
|
}
|
||||||
|
function ReplicateTimer()
|
||||||
|
{
|
||||||
|
switch( RepState )
|
||||||
|
{
|
||||||
|
case REP_CustomCharacters: // Replicate custom characters.
|
||||||
|
if( RepIndex>=PRIOwner.CustomCharList.Length )
|
||||||
|
{
|
||||||
|
PRIOwner.AllCharReceived();
|
||||||
|
RepIndex = 0;
|
||||||
|
++RepState;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PRIOwner.ReceivedCharacter(RepIndex,PRIOwner.CustomCharList[RepIndex]);
|
||||||
|
++RepIndex;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case REP_CustomInventory: // Replicate custom trader inventory
|
||||||
|
if( !PRIOwner.OnRepNextItem(PRIOwner,RepIndex) )
|
||||||
|
{
|
||||||
|
RepIndex = 0;
|
||||||
|
++RepState;
|
||||||
|
}
|
||||||
|
else ++RepIndex;
|
||||||
|
break;
|
||||||
|
case REP_PerkClasses: // Open up all actor channel connections.
|
||||||
|
if( RepIndex>=UserPerks.Length )
|
||||||
|
{
|
||||||
|
RepIndex = 0;
|
||||||
|
++RepState;
|
||||||
|
}
|
||||||
|
else if( UserPerks[RepIndex].bClientAuthorized )
|
||||||
|
{
|
||||||
|
if( UserPerks[RepIndex].bPerkNetReady )
|
||||||
|
++RepIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UserPerks[RepIndex].RemoteRole = ROLE_SimulatedProxy;
|
||||||
|
if( UserPerks[RepIndex].NextAuthTime<WorldInfo.RealTimeSeconds )
|
||||||
|
{
|
||||||
|
UserPerks[RepIndex].NextAuthTime = WorldInfo.RealTimeSeconds+0.5;
|
||||||
|
UserPerks[RepIndex].ClientAuth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if( MaxGrenadeCount!=Default.MaxGrenadeCount )
|
||||||
|
ClientSetGrenadeCap(MaxGrenadeCount);
|
||||||
|
ClearTimer('ReplicateTimer');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bool CanEarnSmallRadiusKillXP( class<DamageType> DT )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function ModifySpeed( out float Speed )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
Speed *= CurrentPerk.Modifiers[0];
|
||||||
|
}
|
||||||
|
function ModifyDamageGiven( out int InDamage, optional Actor DamageCauser, optional KFPawn_Monster MyKFPM, optional KFPlayerController DamageInstigator, optional class<KFDamageType> DamageType, optional int HitZoneIdx )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.ModifyDamageGiven(InDamage,DamageCauser,MyKFPM,DamageInstigator,DamageType,HitZoneIdx);
|
||||||
|
}
|
||||||
|
simulated function ModifyDamageTaken( out int InDamage, optional class<DamageType> DamageType, optional Controller InstigatedBy )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.ModifyDamageTaken(InDamage,DamageType,InstigatedBy);
|
||||||
|
}
|
||||||
|
simulated function ModifyRecoil( out float CurrentRecoilModifier, KFWeapon KFW )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.ModifyRecoil(CurrentRecoilModifier,KFW);
|
||||||
|
}
|
||||||
|
simulated function ModifySpread( out float InSpread )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.ModifySpread(InSpread);
|
||||||
|
}
|
||||||
|
simulated function ModifyRateOfFire( out float InRate, KFWeapon KFW )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.ModifyRateOfFire(InRate,KFW);
|
||||||
|
}
|
||||||
|
simulated function float GetReloadRateScale(KFWeapon KFW)
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? CurrentPerk.GetReloadRateScale(KFW) : 1.f);
|
||||||
|
}
|
||||||
|
simulated function bool GetUsingTactialReload( KFWeapon KFW )
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? CurrentPerk.GetUsingTactialReload(KFW) : false);
|
||||||
|
}
|
||||||
|
function ModifyHealth( out int InHealth )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.ModifyHealth(InHealth);
|
||||||
|
}
|
||||||
|
function ModifyArmor( out byte MaxArmor )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.ModifyArmor(MaxArmor);
|
||||||
|
}
|
||||||
|
function float GetKnockdownPowerModifier( optional class<DamageType> DamageType, optional byte BodyPart, optional bool bIsSprinting=false )
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? CurrentPerk.GetKnockdownPowerModifier() : 1.f);
|
||||||
|
}
|
||||||
|
function float GetStumblePowerModifier( optional KFPawn KFP, optional class<KFDamageType> DamageType, optional out float CooldownModifier, optional byte BodyPart )
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? CurrentPerk.GetKnockdownPowerModifier() : 1.f);
|
||||||
|
}
|
||||||
|
function float GetStunPowerModifier( optional class<DamageType> DamageType, optional byte HitZoneIdx )
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? CurrentPerk.GetStunPowerModifier(DamageType,HitZoneIdx) : 1.f);
|
||||||
|
}
|
||||||
|
simulated function ModifyMeleeAttackSpeed( out float InDuration, KFWeapon KFW )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.ModifyMeleeAttackSpeed(InDuration);
|
||||||
|
}
|
||||||
|
simulated function class<KFProj_Grenade> GetGrenadeClass()
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? CurrentPerk.GrenadeClass : GrenadeClass);
|
||||||
|
}
|
||||||
|
simulated function ModifyWeldingRate( out float FastenRate, out float UnfastenRate )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.ModifyWeldingRate(FastenRate,UnfastenRate);
|
||||||
|
}
|
||||||
|
simulated function bool HasNightVision()
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? CurrentPerk.bHasNightVision : false);
|
||||||
|
}
|
||||||
|
function bool RepairArmor( Pawn HealTarget )
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? CurrentPerk.RepairArmor(HealTarget) : false);
|
||||||
|
}
|
||||||
|
function bool ModifyHealAmount( out float HealAmount )
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? CurrentPerk.ModifyHealAmount(HealAmount) : false);
|
||||||
|
}
|
||||||
|
function bool CanNotBeGrabbed()
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? !CurrentPerk.bCanBeGrabbed : false);
|
||||||
|
}
|
||||||
|
simulated function ModifyMagSizeAndNumber( KFWeapon KFW, out byte MagazineCapacity, optional array< Class<KFPerk> > WeaponPerkClass, optional bool bSecondary=false, optional name WeaponClassname )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.ModifyMagSizeAndNumber(KFW,MagazineCapacity,WeaponPerkClass,bSecondary,WeaponClassname);
|
||||||
|
}
|
||||||
|
simulated function ModifySpareAmmoAmount( KFWeapon KFW, out int PrimarySpareAmmo, optional const out STraderItem TraderItem, optional bool bSecondary=false )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.ModifySpareAmmoAmount(KFW,PrimarySpareAmmo,TraderItem,bSecondary);
|
||||||
|
}
|
||||||
|
simulated function ModifyMaxSpareAmmoAmount( KFWeapon KFW, out int SpareAmmoCapacity, optional const out STraderItem TraderItem, optional bool bSecondary=false )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.ModifySpareAmmoAmount(KFW,SpareAmmoCapacity,TraderItem,bSecondary);
|
||||||
|
}
|
||||||
|
simulated function bool ShouldMagSizeModifySpareAmmo( KFWeapon KFW, optional Class<KFPerk> WeaponPerkClass )
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? CurrentPerk.ShouldMagSizeModifySpareAmmo(KFW,WeaponPerkClass) : false);
|
||||||
|
}
|
||||||
|
simulated function ModifyHealerRechargeTime( out float RechargeRate )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.ModifyHealerRechargeTime(RechargeRate);
|
||||||
|
}
|
||||||
|
simulated function bool CanExplosiveWeld()
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? CurrentPerk.bExplosiveWeld : false);
|
||||||
|
}
|
||||||
|
simulated function bool IsOnContactActive()
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? CurrentPerk.bExplodeOnContact : false);
|
||||||
|
}
|
||||||
|
function bool CanSpreadNapalm()
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None && CurrentPerk.bNapalmFire && LastNapalmTime!=WorldInfo.TimeSeconds )
|
||||||
|
{
|
||||||
|
LastNapalmTime = WorldInfo.TimeSeconds; // Avoid infinite script recursion in KFPawn_Monster.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
simulated function bool IsRangeActive()
|
||||||
|
{
|
||||||
|
return MyPRI!=None ? MyPRI.bExtraFireRange : false;
|
||||||
|
}
|
||||||
|
simulated function DrawSpecialPerkHUD(Canvas C)
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.DrawSpecialPerkHUD(C);
|
||||||
|
}
|
||||||
|
function PlayerKilled( KFPawn_Monster Victim, class<DamageType> DamageType )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.PlayerKilled(Victim,DamageType);
|
||||||
|
}
|
||||||
|
function ModifyBloatBileDoT( out float DoTScaler )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.ModifyBloatBileDoT(DoTScaler);
|
||||||
|
}
|
||||||
|
simulated function bool GetIsUberAmmoActive( KFWeapon KFW )
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? CurrentPerk.GetIsUberAmmoActive(KFW) : false);
|
||||||
|
}
|
||||||
|
function UpdatePerkHeadShots( ImpactInfo Impact, class<DamageType> DamageType, int NumHit )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None )
|
||||||
|
CurrentPerk.UpdatePerkHeadShots(Impact,DamageType,NumHit);
|
||||||
|
}
|
||||||
|
function CheckForAirborneAgent( KFPawn HealTarget, class<DamageType> DamType, int HealAmount )
|
||||||
|
{
|
||||||
|
if( !bCurrentlyHealing && CurrentPerk!=None )
|
||||||
|
{
|
||||||
|
// Using boolean to avoid infinite recursion.
|
||||||
|
bCurrentlyHealing = true;
|
||||||
|
CurrentPerk.CheckForAirborneAgent(HealTarget,DamType,HealAmount);
|
||||||
|
bCurrentlyHealing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
simulated function float GetZedTimeModifier( KFWeapon W )
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? CurrentPerk.GetZedTimeModifier(W) : 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Poison darts
|
||||||
|
function bool IsAcidicCompoundActive()
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? CurrentPerk.bToxicDart : false);
|
||||||
|
}
|
||||||
|
function ModifyACDamage( out int InDamage )
|
||||||
|
{
|
||||||
|
if( CurrentPerk!=None && CurrentPerk.bToxicDart )
|
||||||
|
InDamage += CurrentPerk.ToxicDartDamage;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zombie explosion!
|
||||||
|
function bool CouldBeZedShrapnel( class<KFDamageType> KFDT )
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? (CurrentPerk.bFireExplode && class<KFDT_Fire>(KFDT)!=None) : false);
|
||||||
|
}
|
||||||
|
simulated function bool ShouldShrapnel()
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? (CurrentPerk.bFireExplode && Rand(3)==0) : false);
|
||||||
|
}
|
||||||
|
function GameExplosion GetExplosionTemplate()
|
||||||
|
{
|
||||||
|
return class'KFPerk_Firebug'.Default.ExplosionTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SWAT:
|
||||||
|
simulated function bool HasHeavyArmor()
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None && CurrentPerk.bHeavyArmor);
|
||||||
|
}
|
||||||
|
simulated function float GetIronSightSpeedModifier( KFWeapon KFW )
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? CurrentPerk.GetIronSightSpeedModifier(KFW) : 1.f);
|
||||||
|
}
|
||||||
|
simulated function float GetCrouchSpeedModifier( KFWeapon KFW )
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None ? CurrentPerk.GetIronSightSpeedModifier(KFW) : 1.f);
|
||||||
|
}
|
||||||
|
simulated function bool ShouldKnockDownOnBump()
|
||||||
|
{
|
||||||
|
return (CurrentPerk!=None && CurrentPerk.bHasSWATEnforcer);
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
bTickIsDisabled=false
|
||||||
|
NetPriority=3.5
|
||||||
|
}
|
61
ServerExt/Classes/ExtPerksContainer_Details.uc
Normal file
61
ServerExt/Classes/ExtPerksContainer_Details.uc
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
class ExtPerksContainer_Details extends KFGFxPerksContainer_Details;
|
||||||
|
|
||||||
|
`define AddWeaponsInfo(InClassDef) if( `InClassDef!=None ) AddWeaponInfo(WeaponNames, WeaponSources, `InClassDef.static.GetItemName(), `InClassDef.static.GetImagePath())
|
||||||
|
|
||||||
|
final function ExUpdateDetails( Ext_PerkBase PerkClass )
|
||||||
|
{
|
||||||
|
local GFxObject DetailsProvider;
|
||||||
|
local KFPlayerController KFPC;
|
||||||
|
local KFGameReplicationInfo KFGRI;
|
||||||
|
local array<string> WeaponNames;
|
||||||
|
local array<string> WeaponSources;
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
DetailsProvider = CreateObject( "Object" );
|
||||||
|
|
||||||
|
KFPC = KFPlayerController( GetPC() );
|
||||||
|
|
||||||
|
if ( KFPC != none)
|
||||||
|
{
|
||||||
|
KFGRI = KFGameReplicationInfo(KFPC.WorldInfo.GRI);
|
||||||
|
|
||||||
|
DetailsProvider.SetString( "ExperienceMessage", ExperienceString @ PerkClass.CurrentEXP );
|
||||||
|
|
||||||
|
if(KFGRI != none)
|
||||||
|
{
|
||||||
|
`AddWeaponsInfo(PerkClass.PrimaryWeaponDef);
|
||||||
|
`AddWeaponsInfo(PerkClass.SecondaryWeaponDef);
|
||||||
|
`AddWeaponsInfo(PerkClass.KnifeWeaponDef);
|
||||||
|
`AddWeaponsInfo(PerkClass.GrenadeWeaponDef);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < WeaponNames.length; i++)
|
||||||
|
{
|
||||||
|
DetailsProvider.SetString( "WeaponName" $ i, WeaponNames[i] );
|
||||||
|
DetailsProvider.SetString( "WeaponImage" $ i, "img://"$WeaponSources[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
DetailsProvider.SetString( "EXPAction1", "Kill zombies" );
|
||||||
|
//DetailsProvider.SetString( "EXPAction2", PerkClass.default.EXPAction2 );
|
||||||
|
|
||||||
|
SetObject( "detailsData", DetailsProvider );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final function ExUpdatePassives( Ext_PerkBase PerkClass )
|
||||||
|
{
|
||||||
|
local GFxObject PassivesProvider;
|
||||||
|
local GFxObject PassiveObject;
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
PassivesProvider = CreateArray();
|
||||||
|
for( i=0; i<PerkClass.PerkStats.Length; ++i )
|
||||||
|
{
|
||||||
|
PassiveObject = CreateObject( "Object" );
|
||||||
|
PassiveObject.SetString( "PassiveTitle", PerkClass.GetStatUIStr(i) );
|
||||||
|
PassiveObject.SetString( "PerkBonusModifier", "");
|
||||||
|
PassiveObject.SetString( "PerkBonusAmount", "" );
|
||||||
|
PassivesProvider.SetElementObject( i, PassiveObject );
|
||||||
|
}
|
||||||
|
SetObject( "passivesData", PassivesProvider );
|
||||||
|
}
|
19
ServerExt/Classes/ExtPerksContainer_Header.uc
Normal file
19
ServerExt/Classes/ExtPerksContainer_Header.uc
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
class ExtPerksContainer_Header extends KFGFxPerksContainer_Header;
|
||||||
|
|
||||||
|
final function ExUpdatePerkHeader( Ext_PerkBase PerkClass )
|
||||||
|
{
|
||||||
|
local GFxObject PerkDataProvider;
|
||||||
|
|
||||||
|
PerkDataProvider = CreateObject( "Object" );
|
||||||
|
PerkDataProvider.SetString( "perkTitle", PerkClass.PerkName );
|
||||||
|
PerkDataProvider.SetString( "perkLevel", LevelString@PerkClass.CurrentLevel);
|
||||||
|
PerkDataProvider.SetString( "iconSource", PerkClass.GetPerkIconPath(PerkClass.CurrentLevel) );
|
||||||
|
PerkDataProvider.SetString( "prestigeLevel", ""); //not used yet so not point to populating with data
|
||||||
|
PerkDataProvider.SetString( "xpString", PerkClass.CurrentEXP$"/"$PerkClass.NextLevelEXP );
|
||||||
|
PerkDataProvider.SetFloat( "xpPercent", PerkClass.GetProgressPercent() );
|
||||||
|
SetObject( "perkData", PerkDataProvider );
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
}
|
48
ServerExt/Classes/ExtPerksContainer_Selection.uc
Normal file
48
ServerExt/Classes/ExtPerksContainer_Selection.uc
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
class ExtPerksContainer_Selection extends KFGFxPerksContainer_Selection;
|
||||||
|
|
||||||
|
function UpdatePerkSelection(byte SelectedPerkIndex)
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
local GFxObject DataProvider;
|
||||||
|
local GFxObject TempObj;
|
||||||
|
local ExtPlayerController KFPC;
|
||||||
|
local Ext_PerkBase PerkClass;
|
||||||
|
|
||||||
|
KFPC = ExtPlayerController( GetPC() );
|
||||||
|
|
||||||
|
if ( KFPC!=none && KFPC.ActivePerkManager!=None )
|
||||||
|
{
|
||||||
|
DataProvider = CreateArray();
|
||||||
|
|
||||||
|
for (i = 0; i < KFPC.ActivePerkManager.UserPerks.Length; i++)
|
||||||
|
{
|
||||||
|
PerkClass = KFPC.ActivePerkManager.UserPerks[i];
|
||||||
|
TempObj = CreateObject( "Object" );
|
||||||
|
TempObj.SetInt( "PerkLevel", PerkClass.CurrentLevel );
|
||||||
|
TempObj.SetString( "Title", PerkClass.PerkName );
|
||||||
|
TempObj.SetString( "iconSource", PerkClass.GetPerkIconPath(PerkClass.CurrentLevel) );
|
||||||
|
TempObj.SetBool("bTierUnlocked", true);
|
||||||
|
|
||||||
|
DataProvider.SetElementObject( i, TempObj );
|
||||||
|
}
|
||||||
|
SetObject( "perkData", DataProvider );
|
||||||
|
SetInt("SelectedIndex", SelectedPerkIndex);
|
||||||
|
|
||||||
|
UpdatePendingPerkInfo(SelectedPerkIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function UpdatePendingPerkInfo(byte SelectedPerkIndex)
|
||||||
|
{
|
||||||
|
local ExtPlayerController KFPC;
|
||||||
|
local Ext_PerkBase PerkClass;
|
||||||
|
|
||||||
|
KFPC = ExtPlayerController( GetPC() );
|
||||||
|
if( KFPC != none )
|
||||||
|
{
|
||||||
|
PerkClass = KFPC.ActivePerkManager.UserPerks[SelectedPerkIndex];
|
||||||
|
SetPendingPerkChanges(PerkClass.PerkName, PerkClass.GetPerkIconPath(PerkClass.CurrentLevel), "Perk changes will be applied when you die.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function SavePerk(int PerkID);
|
1176
ServerExt/Classes/ExtPlayerController.uc
Normal file
1176
ServerExt/Classes/ExtPlayerController.uc
Normal file
File diff suppressed because it is too large
Load Diff
94
ServerExt/Classes/ExtPlayerInput.uc
Normal file
94
ServerExt/Classes/ExtPlayerInput.uc
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
Class ExtPlayerInput extends KFPlayerInput;
|
||||||
|
|
||||||
|
var KF2GUIController MyGUIController;
|
||||||
|
var bool bHandledTravel;
|
||||||
|
|
||||||
|
exec function StartCrouch()
|
||||||
|
{
|
||||||
|
bDuck = 1;
|
||||||
|
}
|
||||||
|
exec function ToggleCrouch()
|
||||||
|
{
|
||||||
|
bDuck = (bDuck == 0) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated exec function IronSights(optional bool bHoldButtonMode)
|
||||||
|
{
|
||||||
|
local KFWeapon KFW;
|
||||||
|
|
||||||
|
if( Pawn != none )
|
||||||
|
{
|
||||||
|
if( KFPawn_Monster(Pawn)!=None )
|
||||||
|
Pawn.StartFire(1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KFW = KFWeapon(Pawn.Weapon);
|
||||||
|
if ( KFW != None )
|
||||||
|
KFW.SetIronSights((bHoldButtonMode) ? true : !KFW.bUsingSights);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
simulated exec function IronSightsRelease(optional bool bHoldButtonMode)
|
||||||
|
{
|
||||||
|
local KFWeapon KFW;
|
||||||
|
|
||||||
|
if( Pawn != none )
|
||||||
|
{
|
||||||
|
if( KFPawn_Monster(Pawn)!=None )
|
||||||
|
Pawn.StopFire(1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KFW = KFWeapon(Pawn.Weapon);
|
||||||
|
if ( !KFW.bHasIronSights || bHoldButtonMode )
|
||||||
|
KFW.SetIronSights(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated exec function ToggleFlashlight()
|
||||||
|
{
|
||||||
|
if( KFPawn_Monster(Pawn)!=None && Pawn.Health>0 )
|
||||||
|
SetNightVision(!bNightVisionActive);
|
||||||
|
else Super.ToggleFlashlight();
|
||||||
|
}
|
||||||
|
|
||||||
|
function PreClientTravel( string PendingURL, ETravelType TravelType, bool bIsSeamlessTravel)
|
||||||
|
{
|
||||||
|
Super.PreClientTravel(PendingURL,TravelType,bIsSeamlessTravel);
|
||||||
|
if( !bHandledTravel )
|
||||||
|
{
|
||||||
|
bHandledTravel = true;
|
||||||
|
if( KFExtendedHUD(MyHUD)!=None )
|
||||||
|
KFExtendedHUD(MyHUD).NotifyLevelChange(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event bool FilterButtonInput(int ControllerId, Name Key, EInputEvent Event, float AmountDepressed, bool bGamepad)
|
||||||
|
{
|
||||||
|
if ( MyGfxManager.bAfterLobby && Event==IE_Pressed && (Key == 'Escape' || Key == 'XboxTypeS_Start') )
|
||||||
|
{
|
||||||
|
if( MyGUIController==None || MyGUIController.bIsInvalid )
|
||||||
|
{
|
||||||
|
MyGUIController = class'KF2GUIController'.Static.GetGUIController(Outer);
|
||||||
|
if( MyGUIController==None )
|
||||||
|
{
|
||||||
|
ExtPlayerController(Outer).CancelConnection();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( MyGUIController.bIsInMenuState )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if( MyGFxManager.bMenusOpen )
|
||||||
|
{
|
||||||
|
return MyGFxManager.ToggleMenus();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MyGUIController.OpenMenu(ExtPlayerController(Outer).MidGameMenuClass);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
781
ServerExt/Classes/ExtPlayerReplicationInfo.uc
Normal file
781
ServerExt/Classes/ExtPlayerReplicationInfo.uc
Normal file
@ -0,0 +1,781 @@
|
|||||||
|
Class ExtPlayerReplicationInfo extends KFPlayerReplicationInfo;
|
||||||
|
|
||||||
|
struct FCustomCharEntry
|
||||||
|
{
|
||||||
|
var bool bLock;
|
||||||
|
var KFCharacterInfo_Human Char;
|
||||||
|
var ObjectReferencer Ref;
|
||||||
|
};
|
||||||
|
struct FMyCustomChar // Now without constant.
|
||||||
|
{
|
||||||
|
var byte CharacterIndex,HeadMeshIndex,HeadSkinIndex,BodyMeshIndex,BodySkinIndex,AttachmentMeshIndices[`MAX_COSMETIC_ATTACHMENTS],AttachmentSkinIndices[`MAX_COSMETIC_ATTACHMENTS];
|
||||||
|
|
||||||
|
structdefaultproperties
|
||||||
|
{
|
||||||
|
CharacterIndex=255
|
||||||
|
AttachmentMeshIndices[0]=255
|
||||||
|
AttachmentMeshIndices[1]=255
|
||||||
|
AttachmentMeshIndices[2]=255
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// For custom trader inventory.
|
||||||
|
struct FCustomTraderItem
|
||||||
|
{
|
||||||
|
var class<KFWeaponDefinition> WeaponDef;
|
||||||
|
var class<KFWeapon> WeaponClass;
|
||||||
|
};
|
||||||
|
|
||||||
|
var bool bIsMuted,bInitialPT,bIsDev,bHiddenUser,bClientUseCustom,bClientFirstChar,bClientCharListDone,bClientInitChars;
|
||||||
|
|
||||||
|
var int RespawnCounter;
|
||||||
|
var byte AdminType;
|
||||||
|
var class<Ext_PerkBase> ECurrentPerk;
|
||||||
|
var int ECurrentPerkLevel,ECurrentPerkPrestige;
|
||||||
|
var ExtPerkManager PerkManager;
|
||||||
|
/* AdminTypes:
|
||||||
|
0 - Super Admin (server owner)
|
||||||
|
1 - Admin
|
||||||
|
2 - Moderator
|
||||||
|
3 - Trusted member
|
||||||
|
4 - VIP
|
||||||
|
*/
|
||||||
|
|
||||||
|
var string TaggedPlayerName;
|
||||||
|
var repnotify string NameTag;
|
||||||
|
var repnotify byte RepLevelProgress;
|
||||||
|
var transient color HUDPerkColor;
|
||||||
|
var byte FixedData;
|
||||||
|
var int RepPlayTime,RepKills,RepEXP;
|
||||||
|
|
||||||
|
// Custom character stuff.
|
||||||
|
var array<FCustomCharEntry> CustomCharList;
|
||||||
|
var repnotify FMyCustomChar CustomCharacter;
|
||||||
|
var transient array<ExtCharDataInfo> SaveDataObjects;
|
||||||
|
var transient ExtPlayerReplicationInfo LocalOwnerPRI; // Local playercontroller owner PRI
|
||||||
|
|
||||||
|
// Custom trader inventory
|
||||||
|
var KFGFxObject_TraderItems CustomList;
|
||||||
|
var array<FCustomTraderItem> CustomItems;
|
||||||
|
|
||||||
|
// Supplier data:
|
||||||
|
var transient struct FSupplierData
|
||||||
|
{
|
||||||
|
var transient Pawn SuppliedPawn;
|
||||||
|
var transient float NextSupplyTimer;
|
||||||
|
} SupplierLimit;
|
||||||
|
var repnotify class<Ext_TraitSupply> HasSupplier;
|
||||||
|
|
||||||
|
replication
|
||||||
|
{
|
||||||
|
// Things the server should send to the client.
|
||||||
|
if ( true )
|
||||||
|
RespawnCounter,AdminType,ECurrentPerk,ECurrentPerkLevel,ECurrentPerkPrestige,RepKills,RepEXP,RepLevelProgress,bIsDev,NameTag,FixedData,bHiddenUser,CustomCharacter,HasSupplier;
|
||||||
|
if (bNetInitial || bInitialPT)
|
||||||
|
RepPlayTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function PostBeginPlay()
|
||||||
|
{
|
||||||
|
local PlayerController PC;
|
||||||
|
|
||||||
|
Super.PostBeginPlay();
|
||||||
|
SetTimer(1,true,'TickPT');
|
||||||
|
if( WorldInfo.NetMode!=NM_DedicatedServer )
|
||||||
|
{
|
||||||
|
HUDPerkColor = PickPerkColor();
|
||||||
|
PC = GetALocalPlayerController();
|
||||||
|
if( PC!=None )
|
||||||
|
LocalOwnerPRI = ExtPlayerReplicationInfo(PC.PlayerReplicationInfo);
|
||||||
|
}
|
||||||
|
else LocalOwnerPRI = Self; // Dedicated server can use self PRI.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resupply traits:
|
||||||
|
simulated final function bool CanUseSupply( Pawn P )
|
||||||
|
{
|
||||||
|
return (SupplierLimit.SuppliedPawn!=P || SupplierLimit.NextSupplyTimer<WorldInfo.TimeSeconds);
|
||||||
|
}
|
||||||
|
simulated final function UsedSupply( Pawn P, float NextTime )
|
||||||
|
{
|
||||||
|
SupplierLimit.SuppliedPawn = P;
|
||||||
|
SupplierLimit.NextSupplyTimer = WorldInfo.TimeSeconds+NextTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function ClientInitialize(Controller C)
|
||||||
|
{
|
||||||
|
local ExtPlayerReplicationInfo PRI;
|
||||||
|
|
||||||
|
Super.ClientInitialize(C);
|
||||||
|
|
||||||
|
if( WorldInfo.NetMode!=NM_DedicatedServer )
|
||||||
|
{
|
||||||
|
LocalOwnerPRI = Self;
|
||||||
|
|
||||||
|
// Make all other PRI's load character list from local owner PRI.
|
||||||
|
foreach DynamicActors(class'ExtPlayerReplicationInfo',PRI)
|
||||||
|
PRI.LocalOwnerPRI = Self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function TickPT()
|
||||||
|
{
|
||||||
|
++RepPlayTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated event ReplicatedEvent(name VarName)
|
||||||
|
{
|
||||||
|
switch( VarName )
|
||||||
|
{
|
||||||
|
case 'RepLevelProgress':
|
||||||
|
HUDPerkColor = PickPerkColor();
|
||||||
|
break;
|
||||||
|
case 'CustomCharacter':
|
||||||
|
CharacterCustomizationChanged();
|
||||||
|
break;
|
||||||
|
case 'HasSupplier':
|
||||||
|
SupplierLimit.SuppliedPawn = None; // Reset if stat was changed.
|
||||||
|
break;
|
||||||
|
case 'PlayerName':
|
||||||
|
case 'NameTag':
|
||||||
|
UpdateNameTag();
|
||||||
|
default:
|
||||||
|
Super.ReplicatedEvent(VarName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function SetPlayerName(string S)
|
||||||
|
{
|
||||||
|
Super.SetPlayerName(S);
|
||||||
|
UpdateNameTag();
|
||||||
|
}
|
||||||
|
function SetPlayerNameTag( string S )
|
||||||
|
{
|
||||||
|
NameTag = S;
|
||||||
|
UpdateNameTag();
|
||||||
|
}
|
||||||
|
function OverrideWith(PlayerReplicationInfo PRI)
|
||||||
|
{
|
||||||
|
Super.OverrideWith(PRI);
|
||||||
|
NameTag = ExtPlayerReplicationInfo(PRI).NameTag;
|
||||||
|
bAdmin = PRI.bAdmin;
|
||||||
|
AdminType = ExtPlayerReplicationInfo(PRI).AdminType;
|
||||||
|
UpdateNameTag();
|
||||||
|
}
|
||||||
|
simulated final function UpdateNameTag()
|
||||||
|
{
|
||||||
|
if( NameTag!="" )
|
||||||
|
TaggedPlayerName = "["$NameTag$"] "$PlayerName;
|
||||||
|
else TaggedPlayerName = PlayerName;
|
||||||
|
}
|
||||||
|
final function SetLevelProgress( int CurLevel, int CurPrest, int MinLevel, int MaxLevel )
|
||||||
|
{
|
||||||
|
local float V;
|
||||||
|
|
||||||
|
ECurrentPerkLevel = CurLevel;
|
||||||
|
ECurrentPerkPrestige = CurPrest;
|
||||||
|
V = FClamp((float(CurLevel-MinLevel) / float(MaxLevel-MinLevel))*255.f,0,255);
|
||||||
|
RepLevelProgress = V;
|
||||||
|
bForceNetUpdate = true;
|
||||||
|
|
||||||
|
if( WorldInfo.NetMode!=NM_DedicatedServer )
|
||||||
|
HUDPerkColor = PickPerkColor();
|
||||||
|
}
|
||||||
|
simulated final function string GetPerkLevelStr()
|
||||||
|
{
|
||||||
|
return (ECurrentPerkPrestige>0 ? (string(ECurrentPerkPrestige)$"-"$string(ECurrentPerkLevel)) : string(ECurrentPerkLevel));
|
||||||
|
}
|
||||||
|
simulated final function color PickPerkColor()
|
||||||
|
{
|
||||||
|
local float P;
|
||||||
|
local byte i;
|
||||||
|
|
||||||
|
if( RepLevelProgress==0 )
|
||||||
|
return MakeColor(255,255,255,255);
|
||||||
|
P = float(RepLevelProgress) / 255.f;
|
||||||
|
if( P<0.25f ) // White - Blue
|
||||||
|
{
|
||||||
|
i = 255 - (P*1020.f);
|
||||||
|
return MakeColor(i,i,255,255);
|
||||||
|
}
|
||||||
|
if( P<0.5f ) // Blue - Green
|
||||||
|
{
|
||||||
|
i = ((P-0.25f)*1020.f);
|
||||||
|
return MakeColor(0,i,255-i,255);
|
||||||
|
}
|
||||||
|
if( P<0.75f ) // Green - Red
|
||||||
|
{
|
||||||
|
i = ((P-0.5f)*1020.f);
|
||||||
|
return MakeColor(i,255-i,0,255);
|
||||||
|
}
|
||||||
|
// Red - Yellow
|
||||||
|
i = ((P-0.75f)*1020.f);
|
||||||
|
return MakeColor(255,i,0,255);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SetInitPlayTime( int T )
|
||||||
|
{
|
||||||
|
bInitialPT = true;
|
||||||
|
bForceNetUpdate = true;
|
||||||
|
RepPlayTime = T;
|
||||||
|
SetTimer(5,false,'UnsetPT');
|
||||||
|
}
|
||||||
|
function UnsetPT()
|
||||||
|
{
|
||||||
|
bInitialPT = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Delegate bool OnRepNextItem( ExtPlayerReplicationInfo PRI, int RepIndex )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
simulated reliable client function ClientAddTraderItem( int Index, FCustomTraderItem Item )
|
||||||
|
{
|
||||||
|
// Make sure to not execute on server.
|
||||||
|
if( WorldInfo.NetMode!=NM_Client && (PlayerController(Owner)==None || LocalPlayer(PlayerController(Owner).Player)==None) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( CustomList==None )
|
||||||
|
{
|
||||||
|
CustomList = CreateNewList();
|
||||||
|
RecheckGRI();
|
||||||
|
}
|
||||||
|
CustomItems.AddItem(Item);
|
||||||
|
SetWeaponInfo(false,Index,Item,CustomList);
|
||||||
|
}
|
||||||
|
simulated static final function KFGFxObject_TraderItems CreateNewList()
|
||||||
|
{
|
||||||
|
local KFGFxObject_TraderItems L,B;
|
||||||
|
|
||||||
|
B = class'KFGameReplicationInfo'.Default.TraderItems;
|
||||||
|
L = new(B) class'KFGFxObject_TraderItems'; // Make clone of list.
|
||||||
|
L.SaleItems = B.SaleItems;
|
||||||
|
L.ArmorPrice = B.ArmorPrice;
|
||||||
|
L.GrenadePrice = B.GrenadePrice;
|
||||||
|
|
||||||
|
return L;
|
||||||
|
}
|
||||||
|
simulated static final function SetWeaponInfo( bool bDedicated, int Index, FCustomTraderItem Item, KFGFxObject_TraderItems List )
|
||||||
|
{
|
||||||
|
local array<STraderItemWeaponStats> S;
|
||||||
|
|
||||||
|
if( List.SaleItems.Length<=Index )
|
||||||
|
List.SaleItems.Length = Index+1;
|
||||||
|
|
||||||
|
List.SaleItems[Index].WeaponDef = Item.WeaponDef;
|
||||||
|
List.SaleItems[Index].ClassName = Item.WeaponClass.Name;
|
||||||
|
if( class<KFWeap_DualBase>(Item.WeaponClass)!=None && class<KFWeap_DualBase>(Item.WeaponClass).Default.SingleClass!=None )
|
||||||
|
List.SaleItems[Index].SingleClassName = class<KFWeap_DualBase>(Item.WeaponClass).Default.SingleClass.Name;
|
||||||
|
else List.SaleItems[Index].SingleClassName = '';
|
||||||
|
List.SaleItems[Index].DualClassName = Item.WeaponClass.Default.DualClass!=None ? Item.WeaponClass.Default.DualClass.Name : '';
|
||||||
|
List.SaleItems[Index].AssociatedPerkClasses = Item.WeaponClass.Static.GetAssociatedPerkClasses();
|
||||||
|
List.SaleItems[Index].MagazineCapacity = Item.WeaponClass.Default.MagazineCapacity[0];
|
||||||
|
List.SaleItems[Index].InitialSpareMags = Item.WeaponClass.Default.InitialSpareMags[0];
|
||||||
|
List.SaleItems[Index].MaxSpareAmmo = Item.WeaponClass.Default.SpareAmmoCapacity[0];
|
||||||
|
List.SaleItems[Index].MaxSecondaryAmmo = Item.WeaponClass.Default.MagazineCapacity[1] * Item.WeaponClass.Default.SpareAmmoCapacity[1];
|
||||||
|
List.SaleItems[Index].BlocksRequired = Item.WeaponClass.Default.InventorySize;
|
||||||
|
List.SaleItems[Index].ItemID = Index;
|
||||||
|
|
||||||
|
if( !bDedicated )
|
||||||
|
{
|
||||||
|
List.SaleItems[Index].SecondaryAmmoImagePath = Item.WeaponClass.Default.SecondaryAmmoTexture!=None ? "img://"$PathName(Item.WeaponClass.Default.SecondaryAmmoTexture) : "";
|
||||||
|
List.SaleItems[Index].TraderFilter = Item.WeaponClass.Static.GetTraderFilter();
|
||||||
|
List.SaleItems[Index].InventoryGroup = Item.WeaponClass.Default.InventoryGroup;
|
||||||
|
List.SaleItems[Index].GroupPriority = Item.WeaponClass.Default.GroupPriority;
|
||||||
|
Item.WeaponClass.Static.SetTraderWeaponStats(S);
|
||||||
|
List.SaleItems[Index].WeaponStats = S;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function RecheckGRI()
|
||||||
|
{
|
||||||
|
local ExtPlayerController PC;
|
||||||
|
|
||||||
|
if( KFGameReplicationInfo(WorldInfo.GRI)==None )
|
||||||
|
SetTimer(0.1,false,'RecheckGRI');
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KFGameReplicationInfo(WorldInfo.GRI).TraderItems = CustomList;
|
||||||
|
foreach LocalPlayerControllers(class'ExtPlayerController',PC)
|
||||||
|
if( PC.PurchaseHelper!=None )
|
||||||
|
PC.PurchaseHelper.TraderItems = CustomList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated final function bool ShowAdminName()
|
||||||
|
{
|
||||||
|
return (bAdmin || AdminType<255);
|
||||||
|
}
|
||||||
|
simulated function string GetAdminName()
|
||||||
|
{
|
||||||
|
switch( AdminType )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return "Super Admin";
|
||||||
|
case 1:
|
||||||
|
case 255:
|
||||||
|
return "Admin";
|
||||||
|
case 2:
|
||||||
|
return "Mod";
|
||||||
|
case 3:
|
||||||
|
return "Trusted Member";
|
||||||
|
case 4:
|
||||||
|
return "VIP";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
simulated function string GetAdminNameAbr()
|
||||||
|
{
|
||||||
|
switch( AdminType )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return "S";
|
||||||
|
case 1:
|
||||||
|
case 255:
|
||||||
|
return "A";
|
||||||
|
case 2:
|
||||||
|
return "M";
|
||||||
|
case 3:
|
||||||
|
return "T";
|
||||||
|
case 4:
|
||||||
|
return "V";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
simulated function string GetAdminColor()
|
||||||
|
{
|
||||||
|
switch( AdminType )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return "FF6600";
|
||||||
|
case 1:
|
||||||
|
case 255:
|
||||||
|
return "40FFFF";
|
||||||
|
case 2:
|
||||||
|
return "FF33FF";
|
||||||
|
case 3:
|
||||||
|
return "FF0000";
|
||||||
|
case 4:
|
||||||
|
return "FFD700";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
simulated function color GetAdminColorC()
|
||||||
|
{
|
||||||
|
switch( AdminType )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return MakeColor(255,102,0,255);
|
||||||
|
case 1:
|
||||||
|
case 255:
|
||||||
|
return MakeColor(64,255,255,255);
|
||||||
|
case 2:
|
||||||
|
return MakeColor(255,51,255,255);
|
||||||
|
case 3:
|
||||||
|
return MakeColor(255,0,0,255);
|
||||||
|
case 4:
|
||||||
|
return MakeColor(255,215,0,255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function string GetHumanReadableName()
|
||||||
|
{
|
||||||
|
return TaggedPlayerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SetFixedData( byte M )
|
||||||
|
{
|
||||||
|
OnModeSet(Self,M);
|
||||||
|
FixedData = FixedData | M;
|
||||||
|
SetTimer(5,false,'ClearFixed');
|
||||||
|
}
|
||||||
|
function ClearFixed()
|
||||||
|
{
|
||||||
|
FixedData = 0;
|
||||||
|
}
|
||||||
|
simulated final function string GetDesc()
|
||||||
|
{
|
||||||
|
local string S;
|
||||||
|
|
||||||
|
if( (FixedData & 1)!=0 )
|
||||||
|
S = "A.";
|
||||||
|
if( (FixedData & 2)!=0 )
|
||||||
|
S $= "WF.";
|
||||||
|
if( (FixedData & 4)!=0 )
|
||||||
|
S $= "G.";
|
||||||
|
if( (FixedData & 8)!=0 )
|
||||||
|
S $= "NW.";
|
||||||
|
if( (FixedData & 16)!=0 )
|
||||||
|
S $= "WA.";
|
||||||
|
return S;
|
||||||
|
}
|
||||||
|
delegate OnModeSet( ExtPlayerReplicationInfo PRI, byte Num );
|
||||||
|
|
||||||
|
simulated final function bool LoadPlayerCharacter( byte CharIndex, out FMyCustomChar CharInfo )
|
||||||
|
{
|
||||||
|
local KFCharacterInfo_Human C;
|
||||||
|
|
||||||
|
if( CharIndex>=(CharacterArchetypes.Length+CustomCharList.Length) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( SaveDataObjects.Length<=CharIndex )
|
||||||
|
SaveDataObjects.Length = CharIndex+1;
|
||||||
|
if( SaveDataObjects[CharIndex]==None )
|
||||||
|
{
|
||||||
|
C = (CharIndex<CharacterArchetypes.Length) ? CharacterArchetypes[CharIndex] : CustomCharList[CharIndex-CharacterArchetypes.Length].Char;
|
||||||
|
SaveDataObjects[CharIndex] = new(None,PathName(C)) class'ExtCharDataInfo';
|
||||||
|
}
|
||||||
|
CharInfo = SaveDataObjects[CharIndex].LoadData();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
simulated final function bool SavePlayerCharacter()
|
||||||
|
{
|
||||||
|
local KFCharacterInfo_Human C;
|
||||||
|
|
||||||
|
if( CustomCharacter.CharacterIndex>=(CharacterArchetypes.Length+CustomCharList.Length) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( SaveDataObjects.Length<=CustomCharacter.CharacterIndex )
|
||||||
|
SaveDataObjects.Length = CustomCharacter.CharacterIndex+1;
|
||||||
|
if( SaveDataObjects[CustomCharacter.CharacterIndex]==None )
|
||||||
|
{
|
||||||
|
C = (CustomCharacter.CharacterIndex<CharacterArchetypes.Length) ? CharacterArchetypes[CustomCharacter.CharacterIndex] : CustomCharList[CustomCharacter.CharacterIndex-CharacterArchetypes.Length].Char;
|
||||||
|
SaveDataObjects[CustomCharacter.CharacterIndex] = new(None,PathName(C)) class'ExtCharDataInfo';
|
||||||
|
}
|
||||||
|
SaveDataObjects[CustomCharacter.CharacterIndex].SaveData(CustomCharacter);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
simulated function ChangeCharacter( byte CharIndex, optional bool bFirstSet )
|
||||||
|
{
|
||||||
|
local FMyCustomChar NewChar;
|
||||||
|
local byte i;
|
||||||
|
|
||||||
|
if( CharIndex>=(CharacterArchetypes.Length+CustomCharList.Length) || IsClientCharLocked(CharIndex) )
|
||||||
|
CharIndex = 0;
|
||||||
|
|
||||||
|
if( bFirstSet && RepCustomizationInfo.CharacterIndex==CharIndex )
|
||||||
|
{
|
||||||
|
// Copy properties from default character info.
|
||||||
|
NewChar.HeadMeshIndex = RepCustomizationInfo.HeadMeshIndex;
|
||||||
|
NewChar.HeadSkinIndex = RepCustomizationInfo.HeadSkinIndex;
|
||||||
|
NewChar.BodyMeshIndex = RepCustomizationInfo.BodyMeshIndex;
|
||||||
|
NewChar.BodySkinIndex = RepCustomizationInfo.BodySkinIndex;
|
||||||
|
for( i=0; i<`MAX_COSMETIC_ATTACHMENTS; ++i )
|
||||||
|
{
|
||||||
|
NewChar.AttachmentMeshIndices[i] = RepCustomizationInfo.AttachmentMeshIndices[i];
|
||||||
|
NewChar.AttachmentSkinIndices[i] = RepCustomizationInfo.AttachmentSkinIndices[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( LoadPlayerCharacter(CharIndex,NewChar) )
|
||||||
|
{
|
||||||
|
NewChar.CharacterIndex = CharIndex;
|
||||||
|
CustomCharacter = NewChar;
|
||||||
|
ServerSetCharacterX(NewChar);
|
||||||
|
if( WorldInfo.NetMode==NM_Client )
|
||||||
|
CharacterCustomizationChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
simulated function UpdateCustomization( byte Type, byte MeshIndex, byte SkinIndex, optional byte SlotIndex )
|
||||||
|
{
|
||||||
|
switch( Type )
|
||||||
|
{
|
||||||
|
case CO_Head:
|
||||||
|
CustomCharacter.HeadMeshIndex = MeshIndex;
|
||||||
|
CustomCharacter.HeadSkinIndex = SkinIndex;
|
||||||
|
break;
|
||||||
|
case CO_Body:
|
||||||
|
CustomCharacter.BodyMeshIndex = MeshIndex;
|
||||||
|
CustomCharacter.BodySkinIndex = SkinIndex;
|
||||||
|
break;
|
||||||
|
case CO_Attachment:
|
||||||
|
CustomCharacter.AttachmentMeshIndices[SlotIndex] = MeshIndex;
|
||||||
|
CustomCharacter.AttachmentSkinIndices[SlotIndex] = SkinIndex;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SavePlayerCharacter();
|
||||||
|
ServerSetCharacterX(CustomCharacter);
|
||||||
|
if( WorldInfo.NetMode==NM_Client )
|
||||||
|
CharacterCustomizationChanged();
|
||||||
|
}
|
||||||
|
simulated final function RemoveAttachments()
|
||||||
|
{
|
||||||
|
local byte i;
|
||||||
|
|
||||||
|
for( i=0; i<`MAX_COSMETIC_ATTACHMENTS; ++i )
|
||||||
|
{
|
||||||
|
CustomCharacter.AttachmentMeshIndices[i] = `CLEARED_ATTACHMENT_INDEX;
|
||||||
|
CustomCharacter.AttachmentSkinIndices[i] = 0;
|
||||||
|
}
|
||||||
|
SavePlayerCharacter();
|
||||||
|
ServerSetCharacterX(CustomCharacter);
|
||||||
|
if( WorldInfo.NetMode==NM_Client )
|
||||||
|
CharacterCustomizationChanged();
|
||||||
|
}
|
||||||
|
simulated function ClearCharacterAttachment(int AttachmentIndex)
|
||||||
|
{
|
||||||
|
if( UsesCustomChar() )
|
||||||
|
{
|
||||||
|
CustomCharacter.AttachmentMeshIndices[AttachmentIndex] = `CLEARED_ATTACHMENT_INDEX;
|
||||||
|
CustomCharacter.AttachmentSkinIndices[AttachmentIndex] = 0;
|
||||||
|
}
|
||||||
|
else Super.ClearCharacterAttachment(AttachmentIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
reliable server final function ServerSetCharacterX( FMyCustomChar NewMeshInfo )
|
||||||
|
{
|
||||||
|
if( NewMeshInfo.CharacterIndex>=(CharacterArchetypes.Length+CustomCharList.Length) || IsClientCharLocked(NewMeshInfo.CharacterIndex) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
CustomCharacter = NewMeshInfo;
|
||||||
|
|
||||||
|
if ( Role == Role_Authority )
|
||||||
|
{
|
||||||
|
CharacterCustomizationChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
simulated final function bool IsClientCharLocked( byte Index )
|
||||||
|
{
|
||||||
|
if( Index<CharacterArchetypes.Length )
|
||||||
|
return false;
|
||||||
|
Index-=CharacterArchetypes.Length;
|
||||||
|
return (Index<CustomCharList.Length && CustomCharList[Index].bLock && !ShowAdminName());
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated reliable client function ReceivedCharacter( byte Index, FCustomCharEntry C )
|
||||||
|
{
|
||||||
|
if( WorldInfo.NetMode==NM_DedicatedServer )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( CustomCharList.Length<=Index )
|
||||||
|
CustomCharList.Length = Index+1;
|
||||||
|
CustomCharList[Index] = C;
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated reliable client function AllCharReceived()
|
||||||
|
{
|
||||||
|
if( WorldInfo.NetMode==NM_DedicatedServer )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( !bClientInitChars )
|
||||||
|
{
|
||||||
|
OnCharListDone();
|
||||||
|
NotifyCharListDone();
|
||||||
|
bClientInitChars = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
simulated final function NotifyCharListDone()
|
||||||
|
{
|
||||||
|
local KFPawn_Human KFP;
|
||||||
|
local KFCharacterInfo_Human NewCharArch;
|
||||||
|
local ExtPlayerReplicationInfo EPRI;
|
||||||
|
|
||||||
|
foreach WorldInfo.AllPawns(class'KFPawn_Human', KFP)
|
||||||
|
{
|
||||||
|
EPRI = ExtPlayerReplicationInfo(KFP.PlayerReplicationInfo);
|
||||||
|
if( EPRI!=None )
|
||||||
|
{
|
||||||
|
NewCharArch = EPRI.GetSelectedArch();
|
||||||
|
|
||||||
|
if( NewCharArch != KFP.CharacterArch )
|
||||||
|
{
|
||||||
|
// selected a new character
|
||||||
|
KFP.SetCharacterArch( NewCharArch );
|
||||||
|
}
|
||||||
|
else if( WorldInfo.NetMode != NM_DedicatedServer )
|
||||||
|
{
|
||||||
|
// refresh cosmetics only
|
||||||
|
class'ExtCharacterInfo'.Static.SetCharacterMeshFromArch( NewCharArch, KFP, EPRI );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated delegate OnCharListDone();
|
||||||
|
|
||||||
|
// Player has a server specific setting for a character selected.
|
||||||
|
simulated final function bool UsesCustomChar()
|
||||||
|
{
|
||||||
|
if( LocalOwnerPRI==None )
|
||||||
|
return false; // Not yet init on client.
|
||||||
|
return CustomCharacter.CharacterIndex<(LocalOwnerPRI.CustomCharList.Length+CharacterArchetypes.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client uses a server specific custom character.
|
||||||
|
simulated final function bool ReallyUsingCustomChar()
|
||||||
|
{
|
||||||
|
if( !UsesCustomChar() )
|
||||||
|
return false;
|
||||||
|
return (CustomCharacter.CharacterIndex>=CharacterArchetypes.Length);
|
||||||
|
}
|
||||||
|
simulated final function KFCharacterInfo_Human GetSelectedArch()
|
||||||
|
{
|
||||||
|
if( UsesCustomChar() )
|
||||||
|
return (CustomCharacter.CharacterIndex<CharacterArchetypes.Length) ? CharacterArchetypes[CustomCharacter.CharacterIndex] : LocalOwnerPRI.CustomCharList[CustomCharacter.CharacterIndex-CharacterArchetypes.Length].Char;
|
||||||
|
return CharacterArchetypes[RepCustomizationInfo.CharacterIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated event CharacterCustomizationChanged()
|
||||||
|
{
|
||||||
|
local KFPawn_Human KFP;
|
||||||
|
local KFCharacterInfo_Human NewCharArch;
|
||||||
|
|
||||||
|
foreach WorldInfo.AllPawns(class'KFPawn_Human', KFP)
|
||||||
|
{
|
||||||
|
if( KFP.PlayerReplicationInfo == self || (KFP.DrivenVehicle != None && KFP.DrivenVehicle.PlayerReplicationInfo == self) )
|
||||||
|
{
|
||||||
|
NewCharArch = GetSelectedArch();
|
||||||
|
|
||||||
|
if( NewCharArch != KFP.CharacterArch )
|
||||||
|
{
|
||||||
|
// selected a new character
|
||||||
|
KFP.SetCharacterArch( NewCharArch );
|
||||||
|
}
|
||||||
|
else if( WorldInfo.NetMode != NM_DedicatedServer )
|
||||||
|
{
|
||||||
|
// refresh cosmetics only
|
||||||
|
class'ExtCharacterInfo'.Static.SetCharacterMeshFromArch( NewCharArch, KFP, self );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save/Load custom character information.
|
||||||
|
final function SaveCustomCharacter( ExtSaveDataBase Data )
|
||||||
|
{
|
||||||
|
local byte i,c;
|
||||||
|
local string S;
|
||||||
|
|
||||||
|
// Write the name of custom character.
|
||||||
|
if( UsesCustomChar() )
|
||||||
|
S = string(GetSelectedArch().Name);
|
||||||
|
Data.SaveStr(S);
|
||||||
|
if( S=="" )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Write selected accessories.
|
||||||
|
Data.SaveInt(CustomCharacter.HeadMeshIndex);
|
||||||
|
Data.SaveInt(CustomCharacter.HeadSkinIndex);
|
||||||
|
Data.SaveInt(CustomCharacter.BodyMeshIndex);
|
||||||
|
Data.SaveInt(CustomCharacter.BodySkinIndex);
|
||||||
|
|
||||||
|
c = 0;
|
||||||
|
for( i=0; i<`MAX_COSMETIC_ATTACHMENTS; ++i )
|
||||||
|
{
|
||||||
|
if( CustomCharacter.AttachmentMeshIndices[i]!=255 )
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write attachments count.
|
||||||
|
Data.SaveInt(c);
|
||||||
|
|
||||||
|
// Write attachments.
|
||||||
|
for( i=0; i<`MAX_COSMETIC_ATTACHMENTS; ++i )
|
||||||
|
{
|
||||||
|
if( CustomCharacter.AttachmentMeshIndices[i]!=255 )
|
||||||
|
{
|
||||||
|
Data.SaveInt(i);
|
||||||
|
Data.SaveInt(CustomCharacter.AttachmentMeshIndices[i]);
|
||||||
|
Data.SaveInt(CustomCharacter.AttachmentSkinIndices[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final function LoadCustomCharacter( ExtSaveDataBase Data )
|
||||||
|
{
|
||||||
|
local string S;
|
||||||
|
local byte i,n,j;
|
||||||
|
|
||||||
|
if( Data.GetArVer()>=2 )
|
||||||
|
S = Data.ReadStr();
|
||||||
|
if( S=="" ) // Stock skin.
|
||||||
|
return;
|
||||||
|
|
||||||
|
for( i=0; i<CharacterArchetypes.Length; ++i )
|
||||||
|
{
|
||||||
|
if( string(CharacterArchetypes[i].Name)~=S )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( i==CharacterArchetypes.Length )
|
||||||
|
{
|
||||||
|
for( i=0; i<CustomCharList.Length; ++i )
|
||||||
|
{
|
||||||
|
if( string(CustomCharList[i].Char.Name)~=S )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( i==CharacterArchetypes.Length )
|
||||||
|
{
|
||||||
|
// Character not found = Skip data.
|
||||||
|
Data.SkipBytes(4);
|
||||||
|
n = Data.ReadInt();
|
||||||
|
for( i=0; i<n; ++i )
|
||||||
|
Data.SkipBytes(3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
i+=CharacterArchetypes.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomCharacter.CharacterIndex = i;
|
||||||
|
CustomCharacter.HeadMeshIndex = Data.ReadInt();
|
||||||
|
CustomCharacter.HeadSkinIndex = Data.ReadInt();
|
||||||
|
CustomCharacter.BodyMeshIndex = Data.ReadInt();
|
||||||
|
CustomCharacter.BodySkinIndex = Data.ReadInt();
|
||||||
|
|
||||||
|
n = Data.ReadInt();
|
||||||
|
for( i=0; i<n; ++i )
|
||||||
|
{
|
||||||
|
j = Min(Data.ReadInt(),`MAX_COSMETIC_ATTACHMENTS-1);
|
||||||
|
CustomCharacter.AttachmentMeshIndices[j] = Data.ReadInt();
|
||||||
|
CustomCharacter.AttachmentSkinIndices[j] = Data.ReadInt();
|
||||||
|
}
|
||||||
|
bNetDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only used to skip offset (in case of an error).
|
||||||
|
static final function DummyLoadChar( ExtSaveDataBase Data )
|
||||||
|
{
|
||||||
|
local string S;
|
||||||
|
local byte i,n;
|
||||||
|
|
||||||
|
if( Data.GetArVer()>=2 )
|
||||||
|
S = Data.ReadStr();
|
||||||
|
if( S=="" ) // Stock skin.
|
||||||
|
return;
|
||||||
|
|
||||||
|
Data.SkipBytes(4);
|
||||||
|
n = Data.ReadInt();
|
||||||
|
for( i=0; i<n; ++i )
|
||||||
|
Data.SkipBytes(3);
|
||||||
|
}
|
||||||
|
static final function DummySaveChar( ExtSaveDataBase Data )
|
||||||
|
{
|
||||||
|
Data.SaveStr("");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set admin levels without having to hard-reference to this mod.
|
||||||
|
event BeginState(Name N)
|
||||||
|
{
|
||||||
|
switch( N )
|
||||||
|
{
|
||||||
|
case 'Global':
|
||||||
|
AdminType = 0;
|
||||||
|
break;
|
||||||
|
case 'Admin':
|
||||||
|
AdminType = 1;
|
||||||
|
break;
|
||||||
|
case 'Mod':
|
||||||
|
AdminType = 2;
|
||||||
|
break;
|
||||||
|
case 'TMem':
|
||||||
|
AdminType = 3;
|
||||||
|
break;
|
||||||
|
case 'VIP':
|
||||||
|
AdminType = 4;
|
||||||
|
break;
|
||||||
|
case 'User':
|
||||||
|
AdminType = 255;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
RespawnCounter=-1
|
||||||
|
AdminType=255
|
||||||
|
TaggedPlayerName="Player"
|
||||||
|
}
|
95
ServerExt/Classes/ExtProj_CrackerGrenade.uc
Normal file
95
ServerExt/Classes/ExtProj_CrackerGrenade.uc
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// Written by Marco.
|
||||||
|
class ExtProj_CrackerGrenade extends KFProj_FragGrenade
|
||||||
|
hidedropdown;
|
||||||
|
|
||||||
|
var() byte NumCrackers;
|
||||||
|
|
||||||
|
simulated function PostBeginPlay()
|
||||||
|
{
|
||||||
|
Super.PostBeginPlay();
|
||||||
|
SetTimer(FuseTime+FRand()*0.25, true, 'ExplodeTimer');
|
||||||
|
}
|
||||||
|
simulated function ExplodeTimer()
|
||||||
|
{
|
||||||
|
local Actor HitActor;
|
||||||
|
local vector HitLocation, HitNormal;
|
||||||
|
|
||||||
|
if( WorldInfo.NetMode!=NM_Client && InstigatorController==none )
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GetExplodeEffectLocation(HitLocation, HitNormal, HitActor);
|
||||||
|
if( --NumCrackers==0 )
|
||||||
|
TriggerExplosion(HitLocation, HitNormal, HitActor);
|
||||||
|
else SmallExplosion(HitLocation, HitNormal, HitActor);
|
||||||
|
}
|
||||||
|
simulated function SmallExplosion(Vector HitLocation, Vector HitNormal, Actor HitActor)
|
||||||
|
{
|
||||||
|
local vector NudgedHitLocation, ExplosionDirection;
|
||||||
|
|
||||||
|
Velocity = VRand()*(900.f*FRand());
|
||||||
|
SetPhysics(PHYS_Falling);
|
||||||
|
if (ExplosionTemplate != None)
|
||||||
|
{
|
||||||
|
// using a hitlocation slightly away from the impact point is nice for certain things
|
||||||
|
NudgedHitLocation = HitLocation + (HitNormal * 32.f);
|
||||||
|
|
||||||
|
ExplosionActor = Spawn(ExplosionActorClass, self,, NudgedHitLocation, rotator(HitNormal));
|
||||||
|
if (ExplosionActor != None)
|
||||||
|
{
|
||||||
|
ExplosionActor.RemoteRole = ROLE_None;
|
||||||
|
ExplosionActor.Instigator = Instigator;
|
||||||
|
ExplosionActor.InstigatorController = InstigatorController;
|
||||||
|
|
||||||
|
PrepareExplosionTemplate();
|
||||||
|
|
||||||
|
// If the locations are zero (probably because this exploded in the air) set defaults
|
||||||
|
if( IsZero(HitLocation) )
|
||||||
|
HitLocation = Location;
|
||||||
|
|
||||||
|
if( IsZero(HitNormal) )
|
||||||
|
{
|
||||||
|
HitNormal = vect(0,0,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// these are needed for the decal tracing later in GameExplosionActor.Explode()
|
||||||
|
ExplosionTemplate.HitActor = HitActor;
|
||||||
|
ExplosionTemplate.HitLocation = HitLocation;// NudgedHitLocation
|
||||||
|
ExplosionTemplate.HitNormal = HitNormal;
|
||||||
|
|
||||||
|
// If desired, attach to mover if we hit one
|
||||||
|
if(bAttachExplosionToHitMover && InterpActor(HitActor) != None)
|
||||||
|
{
|
||||||
|
ExplosionActor.Attachee = HitActor;
|
||||||
|
ExplosionTemplate.bAttachExplosionEmitterToAttachee = TRUE;
|
||||||
|
ExplosionActor.SetBase(HitActor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// directional?
|
||||||
|
if (ExplosionTemplate.bDirectionalExplosion)
|
||||||
|
{
|
||||||
|
ExplosionDirection = GetExplosionDirection(HitNormal);
|
||||||
|
//DrawDebugLine(ExplosionActor.Location, ExplosionActor.Location+ExplosionDirection*64, 255, 255, 0, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo: make this function responsible for setting explosion instance parameters, and take instance parameters
|
||||||
|
// out of GearExplosion (e.g. Attachee)
|
||||||
|
PrepareExplosionActor(ExplosionActor);
|
||||||
|
|
||||||
|
ExplosionActor.Explode(ExplosionTemplate, ExplosionDirection); // go bewm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
simulated function ProcessTouch(Actor Other, Vector HitLocation, Vector HitNormal)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
simulated function Explode(vector HitLocation, vector HitNormal);
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
bCanDisintegrate=false
|
||||||
|
FuseTime=0.35
|
||||||
|
NumCrackers=6
|
||||||
|
bNetTemporary=true
|
||||||
|
}
|
95
ServerExt/Classes/ExtProj_SUPERGrenade.uc
Normal file
95
ServerExt/Classes/ExtProj_SUPERGrenade.uc
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// Written by Marco.
|
||||||
|
class ExtProj_SUPERGrenade extends KFProj_FragGrenade
|
||||||
|
hidedropdown;
|
||||||
|
|
||||||
|
/** On Contact demo skill can turn our grenade into an insta boom device */
|
||||||
|
var bool bExplodeOnContact;
|
||||||
|
|
||||||
|
var class<KFProj_Grenade> ClusterNades;
|
||||||
|
var() byte NumClusters;
|
||||||
|
|
||||||
|
simulated function PostBeginPlay()
|
||||||
|
{
|
||||||
|
local KFPerk InstigatorPerk;
|
||||||
|
local KFPawn InstigatorPawn;
|
||||||
|
|
||||||
|
InstigatorPawn = KFPawn(Instigator);
|
||||||
|
if( InstigatorPawn != none )
|
||||||
|
{
|
||||||
|
InstigatorPerk = InstigatorPawn.GetPerk();
|
||||||
|
if( InstigatorPerk != none )
|
||||||
|
bExplodeOnContact = InstigatorPerk.IsOnContactActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
Super.PostBeginPlay();
|
||||||
|
if( Instigator!=None && ExtPlayerReplicationInfo(Instigator.PlayerReplicationInfo)!=None && ExtPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ECurrentPerk!=None )
|
||||||
|
ClusterNades = ExtPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ECurrentPerk.Default.PerkGrenade;
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function ProcessTouch(Actor Other, Vector HitLocation, Vector HitNormal)
|
||||||
|
{
|
||||||
|
if( bExplodeOnContact && Other != Instigator && !Other.bWorldGeometry && Pawn(Other)!=None && Pawn(Other).GetTeamNum() != GetTeamNum() )
|
||||||
|
{
|
||||||
|
// For opposing team, make the grenade explode instantly
|
||||||
|
GetExplodeEffectLocation( HitLocation, HitNormal, Other );
|
||||||
|
TriggerExplosion( HitLocation, HitNormal, Other );
|
||||||
|
}
|
||||||
|
else super.ProcessTouch( Other, HitLocation, HitNormal );
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function Disintegrate( rotator inDisintegrateEffectRotation ); // Nope!
|
||||||
|
|
||||||
|
simulated function TriggerExplosion(Vector HitLocation, Vector HitNormal, Actor HitActor)
|
||||||
|
{
|
||||||
|
local byte i;
|
||||||
|
local KFProj_Grenade P;
|
||||||
|
|
||||||
|
if( bHasExploded )
|
||||||
|
return;
|
||||||
|
if( InstigatorController==None && WorldInfo.NetMode!=NM_Client ) // Prevent Team-Kill.
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Super.TriggerExplosion(HitLocation,HitNormal,HitActor);
|
||||||
|
if( WorldInfo.NetMode!=NM_Client )
|
||||||
|
{
|
||||||
|
for( i=0; i<NumClusters; ++i )
|
||||||
|
{
|
||||||
|
P = Spawn(ClusterNades,,,Location);
|
||||||
|
if( P!=None )
|
||||||
|
{
|
||||||
|
P.InstigatorController = InstigatorController;
|
||||||
|
P.Init(VRand());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bHasExploded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function Destroyed()
|
||||||
|
{
|
||||||
|
local Actor HitActor;
|
||||||
|
local vector HitLocation, HitNormal;
|
||||||
|
|
||||||
|
// Final Failsafe check for explosion effect
|
||||||
|
if( !bHasExploded && WorldInfo.NetMode==NM_Client )
|
||||||
|
{
|
||||||
|
GetExplodeEffectLocation(HitLocation, HitNormal, HitActor);
|
||||||
|
TriggerExplosion(HitLocation, HitNormal, HitActor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
bCanDisintegrate=false
|
||||||
|
ClusterNades=class'KFProj_FragGrenade'
|
||||||
|
DrawScale=2
|
||||||
|
NumClusters=6
|
||||||
|
ProjFlightTemplate=ParticleSystem'ZED_Hans_EMIT.FX_Grenade_Explosive_01'
|
||||||
|
|
||||||
|
Begin Object Name=ExploTemplate0
|
||||||
|
Damage=500
|
||||||
|
DamageRadius=1000
|
||||||
|
End Object
|
||||||
|
}
|
61
ServerExt/Classes/ExtProj_SUPERMedGrenade.uc
Normal file
61
ServerExt/Classes/ExtProj_SUPERMedGrenade.uc
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Written by Marco.
|
||||||
|
class ExtProj_SUPERMedGrenade extends KFProj_MedicGrenade
|
||||||
|
hidedropdown;
|
||||||
|
|
||||||
|
var() byte NumClusters;
|
||||||
|
|
||||||
|
simulated function Disintegrate( rotator inDisintegrateEffectRotation ); // Nope!
|
||||||
|
|
||||||
|
simulated function TriggerExplosion(Vector HitLocation, Vector HitNormal, Actor HitActor)
|
||||||
|
{
|
||||||
|
local byte i;
|
||||||
|
local KFProj_MedicGrenade P;
|
||||||
|
|
||||||
|
if( bHasExploded )
|
||||||
|
return;
|
||||||
|
if( InstigatorController==None && WorldInfo.NetMode!=NM_Client ) // Prevent Team-Kill.
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Super.TriggerExplosion(HitLocation,HitNormal,HitActor);
|
||||||
|
if( WorldInfo.NetMode!=NM_Client )
|
||||||
|
{
|
||||||
|
for( i=0; i<NumClusters; ++i )
|
||||||
|
{
|
||||||
|
P = Spawn(class'KFProj_MedicGrenade',,,Location);
|
||||||
|
if( P!=None )
|
||||||
|
{
|
||||||
|
P.InstigatorController = InstigatorController;
|
||||||
|
P.Init(VRand());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bHasExploded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function Destroyed()
|
||||||
|
{
|
||||||
|
local Actor HitActor;
|
||||||
|
local vector HitLocation, HitNormal;
|
||||||
|
|
||||||
|
// Final Failsafe check for explosion effect
|
||||||
|
if( !bHasExploded && WorldInfo.NetMode==NM_Client )
|
||||||
|
{
|
||||||
|
GetExplodeEffectLocation(HitLocation, HitNormal, HitActor);
|
||||||
|
TriggerExplosion(HitLocation, HitNormal, HitActor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
bCanDisintegrate=false
|
||||||
|
DrawScale=2
|
||||||
|
NumClusters=5
|
||||||
|
ProjFlightTemplate=ParticleSystem'ZED_Hans_EMIT.FX_Grenade_Explosive_01'
|
||||||
|
|
||||||
|
Begin Object Name=ExploTemplate0
|
||||||
|
Damage=170
|
||||||
|
DamageRadius=800
|
||||||
|
End Object
|
||||||
|
}
|
21
ServerExt/Classes/ExtProj_SUPERMolotov.uc
Normal file
21
ServerExt/Classes/ExtProj_SUPERMolotov.uc
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Written by Marco.
|
||||||
|
class ExtProj_SUPERMolotov extends KFProj_MolotovGrenade;
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
Speed=2500
|
||||||
|
TerminalVelocity=3500
|
||||||
|
TossZ=450
|
||||||
|
|
||||||
|
bCanDisintegrate=false
|
||||||
|
DrawScale=2.5
|
||||||
|
|
||||||
|
NumResidualFlames=10
|
||||||
|
ResidualFlameProjClass=class'ExtProj_SUPERMolotovS'
|
||||||
|
|
||||||
|
// explosion
|
||||||
|
Begin Object Name=ExploTemplate0
|
||||||
|
Damage=750
|
||||||
|
DamageRadius=500
|
||||||
|
End Object
|
||||||
|
}
|
12
ServerExt/Classes/ExtProj_SUPERMolotovS.uc
Normal file
12
ServerExt/Classes/ExtProj_SUPERMolotovS.uc
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
class ExtProj_SUPERMolotovS extends KFProj_MolotovSplash;
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
DrawScale=2
|
||||||
|
|
||||||
|
// explosion
|
||||||
|
Begin Object Class=KFGameExplosion Name=ExploTemplate0
|
||||||
|
Damage=40
|
||||||
|
DamageRadius=200
|
||||||
|
End Object
|
||||||
|
}
|
9
ServerExt/Classes/ExtSM_Siren_Scream.uc
Normal file
9
ServerExt/Classes/ExtSM_Siren_Scream.uc
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
class ExtSM_Siren_Scream extends KFSM_Siren_Scream;
|
||||||
|
|
||||||
|
DefaultProperties
|
||||||
|
{
|
||||||
|
// explosion
|
||||||
|
Begin Object Name=ExploTemplate0
|
||||||
|
ActorClassToIgnoreForDamage=class'KFPawn_ZedSirenX'
|
||||||
|
End Object
|
||||||
|
}
|
42
ServerExt/Classes/ExtSaveDataBase.uc
Normal file
42
ServerExt/Classes/ExtSaveDataBase.uc
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Serialization system in UnrealScript, written by Marco.
|
||||||
|
Interface ExtSaveDataBase;
|
||||||
|
|
||||||
|
// File accessor helpers.
|
||||||
|
// MaxVal for integers are as follow (the lower number you use, the less bits will be reserved):
|
||||||
|
/* 0: 0-255
|
||||||
|
1: 0-65535
|
||||||
|
2: 0-16777215
|
||||||
|
3: -2147483647 - 2147483647
|
||||||
|
*/
|
||||||
|
function SaveInt( int Value, optional byte MaxVal );
|
||||||
|
function int ReadInt( optional byte MaxVal );
|
||||||
|
function SaveStr( string S );
|
||||||
|
function string ReadStr();
|
||||||
|
|
||||||
|
// File offset management.
|
||||||
|
function int TellOffset();
|
||||||
|
function SeekOffset( int Offset );
|
||||||
|
function int TotalSize();
|
||||||
|
function ToEnd();
|
||||||
|
function ToStart();
|
||||||
|
function bool AtEnd();
|
||||||
|
function SkipBytes( int Count );
|
||||||
|
|
||||||
|
// Wipe out any saved data.
|
||||||
|
function FlushData();
|
||||||
|
|
||||||
|
// Get file contents in a byte array line.
|
||||||
|
function GetData( out array<byte> Res );
|
||||||
|
function SetData( out array<byte> S );
|
||||||
|
|
||||||
|
// Archive version (to allow modder to make upgraded stat binarily compatible)
|
||||||
|
function int GetArVer();
|
||||||
|
function SetArVer( int Ver );
|
||||||
|
|
||||||
|
// Push/Pop file limitators (to prevent it from reading EoF in sub sections).
|
||||||
|
function PushEOFLimit( int EndOffset );
|
||||||
|
function PopEOFLimit();
|
||||||
|
|
||||||
|
// Get most recent save version for this user.
|
||||||
|
function int GetSaveVersion();
|
||||||
|
function SetSaveVersion( int Num );
|
157
ServerExt/Classes/ExtSpawnPointHelper.uc
Normal file
157
ServerExt/Classes/ExtSpawnPointHelper.uc
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
// Helper actor to find all possible spawnpoints for humans on the map.
|
||||||
|
Class ExtSpawnPointHelper extends Info
|
||||||
|
transient;
|
||||||
|
|
||||||
|
var transient array<NavigationPoint> PendingList,CheckedList;
|
||||||
|
var array<Actor> ValidSpawnSpots;
|
||||||
|
|
||||||
|
static final function ExtSpawnPointHelper FindHelper( WorldInfo Level )
|
||||||
|
{
|
||||||
|
local ExtSpawnPointHelper H;
|
||||||
|
|
||||||
|
foreach Level.DynamicActors(class'ExtSpawnPointHelper',H)
|
||||||
|
return H;
|
||||||
|
return Level.Spawn(class'ExtSpawnPointHelper');
|
||||||
|
}
|
||||||
|
final function Actor PickBestSpawn()
|
||||||
|
{
|
||||||
|
local Actor N,BestN;
|
||||||
|
local KFPawn P;
|
||||||
|
local float Score,BestScore,Dist;
|
||||||
|
local KFPawn_Human H;
|
||||||
|
|
||||||
|
BestN = None;
|
||||||
|
BestScore = 0;
|
||||||
|
foreach ValidSpawnSpots(N)
|
||||||
|
{
|
||||||
|
if( Rand(4)==0 )
|
||||||
|
{
|
||||||
|
Score = FRand();
|
||||||
|
foreach WorldInfo.AllPawns(class'KFPawn',P,N.Location,2000.f)
|
||||||
|
{
|
||||||
|
if( !P.IsAliveAndWell() )
|
||||||
|
continue;
|
||||||
|
Dist = VSize(N.Location-P.Location);
|
||||||
|
if( FastTrace(P.Location,N.Location) )
|
||||||
|
Dist*=0.75;
|
||||||
|
if( P.IsA('KFPawn_Human') )
|
||||||
|
Score+=(3000.f-Dist)/2000.f;
|
||||||
|
else Score-=(3500.f-Dist)/2500.f;
|
||||||
|
}
|
||||||
|
if( BestN==None || Score>BestScore )
|
||||||
|
{
|
||||||
|
BestN = N;
|
||||||
|
BestScore = Score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if can spawn ontop of other players.
|
||||||
|
foreach WorldInfo.AllPawns(class'KFPawn_Human',H)
|
||||||
|
{
|
||||||
|
if( !H.IsAliveAndWell() || H.Physics==PHYS_Falling || (ExtHumanPawn(H)!=None && ExtHumanPawn(H).bFeigningDeath) )
|
||||||
|
continue;
|
||||||
|
Score = FRand();
|
||||||
|
foreach WorldInfo.AllPawns(class'KFPawn',P,H.Location,2000.f)
|
||||||
|
{
|
||||||
|
if( !P.IsAliveAndWell() )
|
||||||
|
continue;
|
||||||
|
Dist = VSize(H.Location-P.Location);
|
||||||
|
if( FastTrace(P.Location,H.Location) )
|
||||||
|
Dist*=0.75;
|
||||||
|
if( P.IsA('KFPawn_Human') )
|
||||||
|
Score+=(3000.f-Dist)/3000.f;
|
||||||
|
else Score-=(3500.f-Dist)/3500.f;
|
||||||
|
}
|
||||||
|
if( BestN==None || Score>BestScore )
|
||||||
|
{
|
||||||
|
BestN = H;
|
||||||
|
BestScore = Score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return BestN;
|
||||||
|
}
|
||||||
|
|
||||||
|
function PreBeginPlay()
|
||||||
|
{
|
||||||
|
SetTimer(0.2,false,'InitChecker');
|
||||||
|
}
|
||||||
|
function InitChecker()
|
||||||
|
{
|
||||||
|
local PlayerStart PS,Fallback;
|
||||||
|
|
||||||
|
foreach WorldInfo.AllNavigationPoints(class'PlayerStart',PS)
|
||||||
|
{
|
||||||
|
Fallback = PS;
|
||||||
|
if( PS.bEnabled && PS.TeamIndex==0 )
|
||||||
|
{
|
||||||
|
CheckSpawn(PS);
|
||||||
|
if( PendingList.Length!=0 )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( PendingList.Length==0 && Fallback!=None )
|
||||||
|
CheckSpawn(Fallback);
|
||||||
|
SetTimer(0.001,true,'NextCheck');
|
||||||
|
}
|
||||||
|
function NextCheck()
|
||||||
|
{
|
||||||
|
local NavigationPoint N;
|
||||||
|
local byte i;
|
||||||
|
|
||||||
|
if( PendingList.Length!=0 )
|
||||||
|
{
|
||||||
|
while( ++i<5 && PendingList.Length!=0 )
|
||||||
|
{
|
||||||
|
N = PendingList[PendingList.Length-1];
|
||||||
|
PendingList.Remove(PendingList.Length-1,1);
|
||||||
|
CheckSpawn(N);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ClearTimer('NextCheck');
|
||||||
|
CheckedList.Length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final function CheckSpawn( NavigationPoint N )
|
||||||
|
{
|
||||||
|
local vector V;
|
||||||
|
local ReachSpec R;
|
||||||
|
local NavigationPoint E;
|
||||||
|
local KFPawnBlockingVolume P;
|
||||||
|
|
||||||
|
V = N.Location;
|
||||||
|
if( N.MaxPathSize.Radius>30 && N.MaxPathSize.Height>80 && FindSpot(vect(36,36,86),V) && KFDoorMarker(N)==None && PickupFactory(N)==None )
|
||||||
|
{
|
||||||
|
//DrawDebugLine(V,V+vect(0,0,50),255,255,255,true);
|
||||||
|
ValidSpawnSpots.AddItem(N);
|
||||||
|
}
|
||||||
|
CheckedList.AddItem(N);
|
||||||
|
|
||||||
|
foreach N.PathList(R)
|
||||||
|
{
|
||||||
|
E = R.GetEnd();
|
||||||
|
if( E==None || R.CollisionRadius<30 || R.CollisionHeight<80 || R.Class==Class'ProscribedReachSpec' )
|
||||||
|
{
|
||||||
|
//if( E!=None )
|
||||||
|
// DrawDebugLine(E.Location,N.Location,255,255,0,true);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if( CheckedList.Find(E)!=INDEX_NONE )
|
||||||
|
continue;
|
||||||
|
// DO NOT go through any blocking volumes.
|
||||||
|
V = (N.Location+E.Location) * 0.5;
|
||||||
|
foreach OverlappingActors(class'KFPawnBlockingVolume',P,VSize(N.Location-V),V)
|
||||||
|
{
|
||||||
|
if( P.bBlockPlayers && TraceComponent(V,V,P.CollisionComponent,E.Location,N.Location,vect(36,36,50)) )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( P==None )
|
||||||
|
{
|
||||||
|
//DrawDebugLine(E.Location,N.Location,0,255,0,true);
|
||||||
|
PendingList.AddItem(E);
|
||||||
|
}
|
||||||
|
//else DrawDebugLine(E.Location,N.Location,255,0,0,true);
|
||||||
|
}
|
||||||
|
}
|
7
ServerExt/Classes/ExtStatWriter.uc
Normal file
7
ServerExt/Classes/ExtStatWriter.uc
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// Interface class for outputting stats into a file or something.
|
||||||
|
Interface ExtStatWriter;
|
||||||
|
|
||||||
|
function WriteValue( string Key, string Value );
|
||||||
|
function StartIntendent( string Section, optional string Key, optional string Value );
|
||||||
|
function EndIntendent();
|
||||||
|
function ResetFile();
|
53
ServerExt/Classes/ExtTraderContainer_Filter.uc
Normal file
53
ServerExt/Classes/ExtTraderContainer_Filter.uc
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
class ExtTraderContainer_Filter extends KFGFxTraderContainer_Filter;
|
||||||
|
|
||||||
|
function SetPerkFilterData(byte FilterIndex)
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
local GFxObject DataProvider;
|
||||||
|
local GFxObject FilterObject;
|
||||||
|
local ExtPlayerController KFPC;
|
||||||
|
local KFPlayerReplicationInfo KFPRI;
|
||||||
|
local ExtPerkManager PrM;
|
||||||
|
|
||||||
|
SetBool("filterVisibliity", true);
|
||||||
|
|
||||||
|
KFPC = ExtPlayerController( GetPC() );
|
||||||
|
if ( KFPC != none )
|
||||||
|
{
|
||||||
|
PrM = KFPC.ActivePerkManager;
|
||||||
|
KFPRI = KFPlayerReplicationInfo(KFPC.PlayerReplicationInfo);
|
||||||
|
if ( KFPRI != none && PrM!=None )
|
||||||
|
{
|
||||||
|
i = Max(PrM.UserPerks.Find(PrM.CurrentPerk),0);
|
||||||
|
SetInt("selectedIndex", i);
|
||||||
|
|
||||||
|
// Set the title of this filter based on either the perk or the off perk string
|
||||||
|
if( FilterIndex < PrM.UserPerks.Length )
|
||||||
|
{
|
||||||
|
SetString("filterText", PrM.UserPerks[FilterIndex].PerkName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetString("filterText", OffPerkString);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataProvider = CreateArray();
|
||||||
|
for (i = 0; i < PrM.UserPerks.Length; i++)
|
||||||
|
{
|
||||||
|
FilterObject = CreateObject( "Object" );
|
||||||
|
FilterObject.SetString("source", PrM.UserPerks[i].GetPerkIconPath(PrM.UserPerks[i].CurrentLevel));
|
||||||
|
DataProvider.SetElementObject( i, FilterObject );
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterObject = CreateObject( "Object" );
|
||||||
|
FilterObject.SetString("source", "img://"$class'KFGFxObject_TraderItems'.default.OffPerkIconPath);
|
||||||
|
DataProvider.SetElementObject( i, FilterObject );
|
||||||
|
|
||||||
|
SetObject( "filterSource", DataProvider );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
}
|
55
ServerExt/Classes/ExtTraderContainer_PlayerInfo.uc
Normal file
55
ServerExt/Classes/ExtTraderContainer_PlayerInfo.uc
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
class ExtTraderContainer_PlayerInfo extends KFGFxTraderContainer_PlayerInfo;
|
||||||
|
|
||||||
|
function SetPerkInfo()
|
||||||
|
{
|
||||||
|
local Ext_PerkBase CurrentPerk;
|
||||||
|
local ExtPlayerController KFPC;
|
||||||
|
local float V;
|
||||||
|
|
||||||
|
KFPC = ExtPlayerController(GetPC());
|
||||||
|
if( KFPC!=none && KFPC.ActivePerkManager!=None && KFPC.ActivePerkManager.CurrentPerk!=None )
|
||||||
|
{
|
||||||
|
CurrentPerk = KFPC.ActivePerkManager.CurrentPerk;
|
||||||
|
SetString("perkName", CurrentPerk.PerkName);
|
||||||
|
SetString("perkIconPath", CurrentPerk.GetPerkIconPath(CurrentPerk.CurrentLevel));
|
||||||
|
SetInt("perkLevel", CurrentPerk.CurrentLevel);
|
||||||
|
V = CurrentPerk.GetProgressPercent()*100.f;
|
||||||
|
SetInt("xpBarValue", int(V));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function SetPerkList()
|
||||||
|
{
|
||||||
|
local GFxObject PerkObject;
|
||||||
|
local GFxObject DataProvider;
|
||||||
|
local ExtPlayerController KFPC;
|
||||||
|
local byte i;
|
||||||
|
local float PerkPercent;
|
||||||
|
local Ext_PerkBase P;
|
||||||
|
|
||||||
|
KFPC = ExtPlayerController(GetPC());
|
||||||
|
if( KFPC != none && KFPC.ActivePerkManager!=None )
|
||||||
|
{
|
||||||
|
DataProvider = CreateArray();
|
||||||
|
|
||||||
|
for (i = 0; i < KFPC.ActivePerkManager.UserPerks.Length; i++)
|
||||||
|
{
|
||||||
|
P = KFPC.ActivePerkManager.UserPerks[i];
|
||||||
|
PerkObject = CreateObject( "Object" );
|
||||||
|
PerkObject.SetString("name", P.PerkName);
|
||||||
|
PerkObject.SetString("perkIconSource", P.GetPerkIconPath(P.CurrentLevel));
|
||||||
|
PerkObject.SetInt("level", P.CurrentLevel);
|
||||||
|
|
||||||
|
PerkPercent = P.GetProgressPercent()*100.f;
|
||||||
|
PerkObject.SetInt("perkXP", int(PerkPercent));
|
||||||
|
|
||||||
|
DataProvider.SetElementObject(i, PerkObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetObject("perkList", DataProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
}
|
73
ServerExt/Classes/ExtTraderContainer_Store.uc
Normal file
73
ServerExt/Classes/ExtTraderContainer_Store.uc
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
class ExtTraderContainer_Store extends KFGFxTraderContainer_Store;
|
||||||
|
|
||||||
|
function RefreshWeaponListByPerk(byte FilterIndex, const out array<STraderItem> ItemList)
|
||||||
|
{
|
||||||
|
local int i, SlotIndex;
|
||||||
|
local GFxObject ItemDataArray; // This array of information is sent to ActionScript to update the Item data
|
||||||
|
local array<STraderItem> OnPerkWeapons, SecondaryWeapons, OffPerkWeapons;
|
||||||
|
local class<KFPerk> TargetPerkClass;
|
||||||
|
local ExtPlayerController EKFPC;
|
||||||
|
|
||||||
|
EKFPC = ExtPlayerController(KFPC);
|
||||||
|
if ( EKFPC!=none && EKFPC.ActivePerkManager!=None)
|
||||||
|
{
|
||||||
|
if( FilterIndex<EKFPC.ActivePerkManager.UserPerks.Length )
|
||||||
|
TargetPerkClass = EKFPC.ActivePerkManager.UserPerks[FilterIndex].BasePerk;
|
||||||
|
|
||||||
|
SlotIndex = 0;
|
||||||
|
ItemDataArray = CreateArray();
|
||||||
|
|
||||||
|
for (i = 0; i < ItemList.Length; i++)
|
||||||
|
{
|
||||||
|
if ( IsItemFiltered(ItemList[i]) )
|
||||||
|
{
|
||||||
|
continue; // Skip this item if it's in our inventory
|
||||||
|
}
|
||||||
|
else if ( ItemList[i].AssociatedPerkClasses.length > 0 && ItemList[i].AssociatedPerkClasses[0] != none && TargetPerkClass != class'KFPerk_Survivalist'
|
||||||
|
&& (TargetPerkClass==None || ItemList[i].AssociatedPerkClasses.Find(TargetPerkClass) == INDEX_NONE ) )
|
||||||
|
{
|
||||||
|
continue; // filtered by perk
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(ItemList[i].AssociatedPerkClasses.length > 0)
|
||||||
|
{
|
||||||
|
switch (ItemList[i].AssociatedPerkClasses.Find(TargetPerkClass))
|
||||||
|
{
|
||||||
|
case 0: //primary perk
|
||||||
|
OnPerkWeapons.AddItem(ItemList[i]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: //secondary perk
|
||||||
|
SecondaryWeapons.AddItem(ItemList[i]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: //off perk
|
||||||
|
OffPerkWeapons.AddItem(ItemList[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < OnPerkWeapons.length; i++)
|
||||||
|
{
|
||||||
|
SetItemInfo(ItemDataArray, OnPerkWeapons[i], SlotIndex);
|
||||||
|
SlotIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < SecondaryWeapons.length; i++)
|
||||||
|
{
|
||||||
|
SetItemInfo(ItemDataArray, SecondaryWeapons[i], SlotIndex);
|
||||||
|
SlotIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < OffPerkWeapons.length; i++)
|
||||||
|
{
|
||||||
|
SetItemInfo(ItemDataArray, OffPerkWeapons[i], SlotIndex);
|
||||||
|
SlotIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetObject("shopData", ItemDataArray);
|
||||||
|
}
|
||||||
|
}
|
62
ServerExt/Classes/ExtWebAdmin_UI.uc
Normal file
62
ServerExt/Classes/ExtWebAdmin_UI.uc
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Webadmin playinfo config variables.
|
||||||
|
// Just an information holder.
|
||||||
|
Class ExtWebAdmin_UI extends Object
|
||||||
|
transient;
|
||||||
|
|
||||||
|
/* List of PropTypes:
|
||||||
|
0 = Integer
|
||||||
|
1 = Boolean
|
||||||
|
2 = string
|
||||||
|
3 = multiline text field
|
||||||
|
*/
|
||||||
|
struct FWebAdminConfigInfo
|
||||||
|
{
|
||||||
|
var byte PropType;
|
||||||
|
var name PropName;
|
||||||
|
var string UIName,UIDesc;
|
||||||
|
var int NumElements;
|
||||||
|
|
||||||
|
structdefaultproperties
|
||||||
|
{
|
||||||
|
NumElements=1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct FPropGroup
|
||||||
|
{
|
||||||
|
var string PageName;
|
||||||
|
var class<Object> ObjClass;
|
||||||
|
var array<FWebAdminConfigInfo> Configs;
|
||||||
|
var delegate<OnGetValue> GetValue;
|
||||||
|
var delegate<OnSetValue> SetValue;
|
||||||
|
var int Dupes;
|
||||||
|
};
|
||||||
|
var array<FPropGroup> ConfigList;
|
||||||
|
|
||||||
|
// Value accessors.
|
||||||
|
Delegate string OnGetValue( name PropName, int ElementIndex );
|
||||||
|
Delegate OnSetValue( name PropName, int ElementIndex, string Value );
|
||||||
|
|
||||||
|
final function Cleanup()
|
||||||
|
{
|
||||||
|
ConfigList.Length = 0;
|
||||||
|
}
|
||||||
|
final function AddSettingsPage( string PageName, class<Object> Obj, const out array<FWebAdminConfigInfo> Configs, delegate<OnGetValue> GetFunc, delegate<OnSetValue> SetFunc )
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
i = ConfigList.Find('PageName',PageName);
|
||||||
|
if( i>=0 ) // Make sure no dupe pages.
|
||||||
|
PageName $= "_"$(ConfigList[i].Dupes++);
|
||||||
|
|
||||||
|
i = ConfigList.Length;
|
||||||
|
ConfigList.Length = i+1;
|
||||||
|
ConfigList[i].PageName = PageName;
|
||||||
|
ConfigList[i].ObjClass = Obj;
|
||||||
|
ConfigList[i].Configs = Configs;
|
||||||
|
ConfigList[i].GetValue = GetFunc;
|
||||||
|
ConfigList[i].SetValue = SetFunc;
|
||||||
|
}
|
||||||
|
final function bool HasConfigFor( class<Object> Obj )
|
||||||
|
{
|
||||||
|
return (ConfigList.Find('ObjClass',Obj)>=0);
|
||||||
|
}
|
131
ServerExt/Classes/ExtWidget_BossHealthBar.uc
Normal file
131
ServerExt/Classes/ExtWidget_BossHealthBar.uc
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
class ExtWidget_BossHealthBar extends KFGFxWidget_BossHealthBar;
|
||||||
|
|
||||||
|
var transient array<KFPawn_Monster> BossList;
|
||||||
|
var transient float NextBossDistTime,LastHP,LastShield;
|
||||||
|
var transient byte NumBosses;
|
||||||
|
var transient bool bVisib,bHasInit;
|
||||||
|
|
||||||
|
function TickHud(float DeltaTime)
|
||||||
|
{
|
||||||
|
if( !KFPC.bHideBossHealthBar && BossList.Length>0 )
|
||||||
|
{
|
||||||
|
if( KFPC.WorldInfo.RealTimeSeconds>LastUpdateTime && HasBossesAlive() )
|
||||||
|
{
|
||||||
|
LastUpdateTime = KFPC.WorldInfo.RealTimeSeconds + UpdateTickTime;
|
||||||
|
if( !bVisib )
|
||||||
|
{
|
||||||
|
LastHP = -1;
|
||||||
|
LastShield = -1;
|
||||||
|
bVisib = true;
|
||||||
|
SetVisible(true);
|
||||||
|
}
|
||||||
|
UpdateBossInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( bHasInit )
|
||||||
|
{
|
||||||
|
NumBosses = 0;
|
||||||
|
bHasInit = false;
|
||||||
|
BossList.Length = 0;
|
||||||
|
if( bVisib )
|
||||||
|
{
|
||||||
|
bVisib = false;
|
||||||
|
SetVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final function bool HasBossesAlive()
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
for( i=(BossList.Length-1); i>=0; --i )
|
||||||
|
{
|
||||||
|
if( BossList[i]==None || BossList[i].bDeleteMe || BossList[i].GetTeamNum()==0 )
|
||||||
|
{
|
||||||
|
BossList.Remove(i,1);
|
||||||
|
--NumBosses;
|
||||||
|
}
|
||||||
|
else if( !BossList[i].IsAliveAndWell() )
|
||||||
|
BossList.Remove(i,1);
|
||||||
|
}
|
||||||
|
return (BossList.Length>0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SetBossPawn(KFPawn_Monster NewBossPawn)
|
||||||
|
{
|
||||||
|
if( !KFPC.bHideBossHealthBar && NewBossPawn!=None && NewBossPawn.IsAliveAndWell() )
|
||||||
|
{
|
||||||
|
bHasInit = true;
|
||||||
|
++NumBosses;
|
||||||
|
BossList.AddItem(NewBossPawn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final function UpdateBossInfo()
|
||||||
|
{
|
||||||
|
local float V;
|
||||||
|
local KFPawn_Monster B;
|
||||||
|
|
||||||
|
if( NextBossDistTime<KFPC.WorldInfo.RealTimeSeconds )
|
||||||
|
{
|
||||||
|
NextBossDistTime = KFPC.WorldInfo.RealTimeSeconds + 1.f;
|
||||||
|
CheckBestBoss();
|
||||||
|
}
|
||||||
|
|
||||||
|
V = (BossPawn!=None ? FClamp(float(BossPawn.Health) / float(BossPawn.HealthMax),0.f,1.f) : 0.f);
|
||||||
|
if( LastHP!=V )
|
||||||
|
{
|
||||||
|
LastHP = V;
|
||||||
|
SetFloat("currentHealthPercentValue",V);
|
||||||
|
}
|
||||||
|
|
||||||
|
V = 0.f;
|
||||||
|
if( NumBosses>1 )
|
||||||
|
{
|
||||||
|
foreach BossList(B)
|
||||||
|
V += FClamp(float(B.Health) / float(B.HealthMax),0.f,1.f);
|
||||||
|
V /= NumBosses;
|
||||||
|
}
|
||||||
|
if( LastShield!=V )
|
||||||
|
{
|
||||||
|
LastShield = V;
|
||||||
|
SetFloat("currentShieldPercecntValue",V);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final function CheckBestBoss()
|
||||||
|
{
|
||||||
|
local KFPawn_Monster B,Best;
|
||||||
|
local vector Pos;
|
||||||
|
local float Dist,BestDist;
|
||||||
|
|
||||||
|
Pos = (KFPC.ViewTarget!=None ? KFPC.ViewTarget.Location : KFPC.Location);
|
||||||
|
foreach BossList(B)
|
||||||
|
{
|
||||||
|
Dist = VSizeSq(Pos-B.Location);
|
||||||
|
if( Best==None || Dist<BestDist )
|
||||||
|
{
|
||||||
|
Best = B;
|
||||||
|
BestDist = Dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( Best!=BossPawn )
|
||||||
|
{
|
||||||
|
BossPawn = Best;
|
||||||
|
SetBossName(Best.BossName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function OnNamePlateHidden();
|
||||||
|
|
||||||
|
function UpdateBossHealth();
|
||||||
|
|
||||||
|
function UpdateBossBattlePhase(int BattlePhase);
|
||||||
|
|
||||||
|
function UpdateBossShield(float NewShieldPercect);
|
||||||
|
|
||||||
|
DefaultProperties
|
||||||
|
{
|
||||||
|
}
|
87
ServerExt/Classes/ExtWidget_PartyInGame.uc
Normal file
87
ServerExt/Classes/ExtWidget_PartyInGame.uc
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
class ExtWidget_PartyInGame extends KFGFxWidget_PartyInGame;
|
||||||
|
|
||||||
|
var class<Ext_PerkBase> PPerkSlots[6];
|
||||||
|
var byte PPerkLevels[6];
|
||||||
|
|
||||||
|
function GFxObject RefreshSlot(int SlotIndex, KFPlayerReplicationInfo KFPRI)
|
||||||
|
{
|
||||||
|
local string PlayerName;
|
||||||
|
local UniqueNetId AdminId;
|
||||||
|
local bool bIsLeader;
|
||||||
|
local bool bIsMyPlayer;
|
||||||
|
local PlayerController PC;
|
||||||
|
local GFxObject PlayerInfoObject;
|
||||||
|
local class<Ext_PerkBase> CurrentPerkClass;
|
||||||
|
local int CurrentPerkLevel;
|
||||||
|
local ExtPlayerReplicationInfo EPRI;
|
||||||
|
|
||||||
|
PlayerInfoObject = CreateObject("Object");
|
||||||
|
EPRI = ExtPlayerReplicationInfo(KFPRI);
|
||||||
|
PC = GetPC();
|
||||||
|
|
||||||
|
if(OnlineLobby != none)
|
||||||
|
{
|
||||||
|
OnlineLobby.GetLobbyAdmin( OnlineLobby.GetCurrentLobbyId(), AdminId);
|
||||||
|
}
|
||||||
|
|
||||||
|
//leader
|
||||||
|
bIsLeader = (KFPRI.UniqueId == AdminId);
|
||||||
|
PlayerInfoObject.SetBool("bLeader", bIsLeader);
|
||||||
|
//my player
|
||||||
|
bIsMyPlayer = PC.PlayerReplicationInfo.UniqueId == KFPRI.UniqueId;
|
||||||
|
MemberSlots[SlotIndex].PlayerUID = KFPRI.UniqueId;
|
||||||
|
MemberSlots[SlotIndex].PRI = KFPRI;
|
||||||
|
PlayerInfoObject.SetBool("myPlayer", bIsMyPlayer);
|
||||||
|
|
||||||
|
// Update this players perk information
|
||||||
|
CurrentPerkClass = (EPRI!=None ? EPRI.ECurrentPerk : None);
|
||||||
|
CurrentPerkLevel = (EPRI!=None ? EPRI.ECurrentPerkLevel : 0);
|
||||||
|
|
||||||
|
if ( PPerkSlots[SlotIndex] != CurrentPerkClass || PPerkLevels[SlotIndex] != CurrentPerkLevel )
|
||||||
|
{
|
||||||
|
PPerkSlots[SlotIndex] = CurrentPerkClass;
|
||||||
|
PPerkLevels[SlotIndex] = CurrentPerkLevel;
|
||||||
|
PlayerInfoObject.SetString("perkLevel", string(CurrentPerkLevel) @ CurrentPerkClass.default.PerkName);
|
||||||
|
PlayerInfoObject.SetString("perkIconPath", CurrentPerkClass.Static.GetPerkIconPath(CurrentPerkLevel));
|
||||||
|
}
|
||||||
|
|
||||||
|
//perk info
|
||||||
|
if(MemberSlots[SlotIndex].PerkClass != none)
|
||||||
|
{
|
||||||
|
PlayerInfoObject.SetString("perkLevel", MemberSlots[SlotIndex].PerkLevel @MemberSlots[SlotIndex].PerkClass.default.PerkName);
|
||||||
|
PlayerInfoObject.SetString("perkIconPath", "img://"$MemberSlots[SlotIndex].PerkClass.static.GetPerkIconPath());
|
||||||
|
}
|
||||||
|
//perk info
|
||||||
|
if(!bIsMyPlayer)
|
||||||
|
{
|
||||||
|
PlayerInfoObject.SetBool("muted", PC.IsPlayerMuted(KFPRI.UniqueId));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// E3 build force update of player name
|
||||||
|
if( class'WorldInfo'.static.IsE3Build() )
|
||||||
|
{
|
||||||
|
// Update this slots player name
|
||||||
|
PlayerName = KFPRI.PlayerName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PlayerName = KFPRI.PlayerName;
|
||||||
|
}
|
||||||
|
PlayerInfoObject.SetString("playerName", PlayerName);
|
||||||
|
//player icon
|
||||||
|
if( class'WorldInfo'.static.IsConsoleBuild(CONSOLE_Orbis) )
|
||||||
|
{
|
||||||
|
PlayerInfoObject.SetString("profileImageSource", KFPC.GetPS4Avatar(PlayerName));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PlayerInfoObject.SetString("profileImageSource", KFPC.GetSteamAvatar(KFPRI.UniqueId));
|
||||||
|
}
|
||||||
|
if(KFGRI != none)
|
||||||
|
{
|
||||||
|
PlayerInfoObject.SetBool("ready", KFPRI.bReadyToPlay && !KFGRI.bMatchHasBegun);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PlayerInfoObject;
|
||||||
|
}
|
155
ServerExt/Classes/Ext_AICommandBasePet.uc
Normal file
155
ServerExt/Classes/Ext_AICommandBasePet.uc
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
class Ext_AICommandBasePet extends AICommand_Base_Zed;
|
||||||
|
|
||||||
|
var transient Pawn OwnerPawn;
|
||||||
|
var transient float NextSightCheckTime;
|
||||||
|
|
||||||
|
final function vector PickPointNearOwner()
|
||||||
|
{
|
||||||
|
local byte i;
|
||||||
|
local vector V,HL,HN,Start;
|
||||||
|
|
||||||
|
Start = OwnerPawn.Location;
|
||||||
|
if( OwnerPawn.Physics==PHYS_Falling )
|
||||||
|
{
|
||||||
|
if( Pawn.Trace(HL,HN,OwnerPawn.Location-vect(0,0,5000),OwnerPawn.Location,false,vect(20,20,60))!=None )
|
||||||
|
Start = HL;
|
||||||
|
}
|
||||||
|
while( true )
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
V.X = FRand()-0.5;
|
||||||
|
V.Y = FRand()-0.5;
|
||||||
|
V = Start + Normal2D(V) * (100.f+FRand()*500.f);
|
||||||
|
|
||||||
|
if( i<20 && !FastTrace(V,Start) ) // Destination is inside a wall.
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( i<20 && FastTrace(V-vect(0,0,100),V) ) // Destination is above a pit.
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
OwnerPawn = None;
|
||||||
|
return V;
|
||||||
|
}
|
||||||
|
final function bool CanSeeOwner()
|
||||||
|
{
|
||||||
|
local Pawn P;
|
||||||
|
|
||||||
|
NextSightCheckTime = WorldInfo.TimeSeconds+1.f + FRand();
|
||||||
|
P = Ext_T_MonsterPRI(PlayerReplicationInfo)!=None ? Ext_T_MonsterPRI(PlayerReplicationInfo).OwnerController.Pawn : None;
|
||||||
|
if( P!=None && !LineOfSightTo(P) )
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
state ZedBaseCommand
|
||||||
|
{
|
||||||
|
Begin:
|
||||||
|
if( Pawn.Physics == PHYS_Falling )
|
||||||
|
{
|
||||||
|
DisableMeleeRangeEventProbing();
|
||||||
|
WaitForLanding();
|
||||||
|
}
|
||||||
|
EnableMeleeRangeEventProbing();
|
||||||
|
// Check for any interrupt transitions
|
||||||
|
CheckInterruptCombatTransitions();
|
||||||
|
|
||||||
|
// Select nearest enemy if current enemy is invalid
|
||||||
|
if( Enemy == none || Enemy.Health <= 0 || !IsValidAttackTarget(KFPawn(Enemy)) )
|
||||||
|
SelectEnemy();
|
||||||
|
|
||||||
|
// Handle special case if I'm supposed to be attacking a door
|
||||||
|
if( DoorEnemy != none && DoorEnemy.Health > 0 && VSizeSq( DoorEnemy.Location - Pawn.Location ) < (DoorMeleeDistance * DoorMeleeDistance) ) //200UU
|
||||||
|
{
|
||||||
|
`AILog( self$" DoorEnemy: "$DoorEnemy$" starting melee attack", 'Command_Base' );
|
||||||
|
UpdateHistoryString( "[Attacking : "$DoorEnemy$" at "$WorldInfo.TimeSeconds$"]" );
|
||||||
|
class'AICommand_Attack_Melee'.static.Melee( Outer, DoorEnemy );
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if we are close to our owner
|
||||||
|
RecheckOwner:
|
||||||
|
OwnerPawn = Ext_T_MonsterPRI(PlayerReplicationInfo)!=None ? Ext_T_MonsterPRI(PlayerReplicationInfo).OwnerController.Pawn : None;
|
||||||
|
if( OwnerPawn!=None )
|
||||||
|
{
|
||||||
|
if( Enemy!=None && LineOfSightTo(OwnerPawn) && LineOfSightTo(Enemy) ) // We have sight to our owner and can see enemy, go for it!
|
||||||
|
{
|
||||||
|
OwnerPawn = None;
|
||||||
|
|
||||||
|
bWaitingOnMovementPlugIn = true;
|
||||||
|
SetEnemyMoveGoal(self, true,,, ShouldAttackWhileMoving() );
|
||||||
|
NextSightCheckTime = WorldInfo.TimeSeconds+2.f;
|
||||||
|
while( bWaitingOnMovementPlugIn && bUsePluginsForMovement )
|
||||||
|
{
|
||||||
|
if( NextSightCheckTime<WorldInfo.TimeSeconds && !CanSeeOwner() )
|
||||||
|
{
|
||||||
|
ClearMovementInfo();
|
||||||
|
GoTo'RecheckOwner';
|
||||||
|
}
|
||||||
|
Sleep(0.03);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( VSizeSq(OwnerPawn.Location-Pawn.Location)>640000.f || !LineOfSightTo(OwnerPawn) ) // 800.f - Need to move closer to our owner.
|
||||||
|
{
|
||||||
|
bWaitingOnMovementPlugIn = true;
|
||||||
|
SetMovePoint(PickPointNearOwner(),OwnerPawn,,300.f);
|
||||||
|
|
||||||
|
while( bWaitingOnMovementPlugIn && bUsePluginsForMovement )
|
||||||
|
{
|
||||||
|
Sleep(0.03);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // Standing next to our owner.
|
||||||
|
{
|
||||||
|
OwnerPawn = None;
|
||||||
|
Sleep(0.2+FRand()*0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( IsValidAttackTarget(KFPawn(Enemy)) )
|
||||||
|
{
|
||||||
|
`AILog( "Calling SetEnemyMoveGoal [Dist:"$VSize(Enemy.Location - Pawn.Location)$"] using offset of "$AttackRange$", because IsWithinBasicMeleeRange() returned false ", 'Command_Base' );
|
||||||
|
bWaitingOnMovementPlugIn = true;
|
||||||
|
SetEnemyMoveGoal(self, true,,, ShouldAttackWhileMoving() );
|
||||||
|
|
||||||
|
while( bWaitingOnMovementPlugIn && bUsePluginsForMovement )
|
||||||
|
{
|
||||||
|
Sleep(0.03);
|
||||||
|
}
|
||||||
|
`AiLog("Back from waiting for the movement plug in!!!");
|
||||||
|
|
||||||
|
if( Enemy == none )
|
||||||
|
{
|
||||||
|
Sleep( FRand() + 0.1f );
|
||||||
|
Goto( 'Begin' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
`AILog("Enemy is invalid melee target" @ Enemy, 'Command_Base');
|
||||||
|
bFailedToMoveToEnemy = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check combat transitions
|
||||||
|
CheckCombatTransition();
|
||||||
|
if( bFailedToMoveToEnemy )
|
||||||
|
{
|
||||||
|
if( bFailedPathfind )
|
||||||
|
{
|
||||||
|
bFailedPathfind = false;
|
||||||
|
Sleep( 0.f );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Sleep( 0.f );
|
||||||
|
}
|
||||||
|
SetEnemy( GetClosestEnemy( Enemy ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Sleep(0.f);
|
||||||
|
}
|
||||||
|
Goto('Begin');
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultProperties
|
||||||
|
{
|
||||||
|
}
|
16
ServerExt/Classes/Ext_AINoTaunt.uc
Normal file
16
ServerExt/Classes/Ext_AINoTaunt.uc
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
class Ext_AINoTaunt extends KFSM_PlaySingleAnim;
|
||||||
|
|
||||||
|
function SpecialMoveStarted(bool bForced, Name PrevMove)
|
||||||
|
{
|
||||||
|
KFPOwner.EndSpecialMove();
|
||||||
|
}
|
||||||
|
function SpecialMoveEnded(Name PrevMove, Name NextMove)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultProperties
|
||||||
|
{
|
||||||
|
Handle=KFSM_Taunt
|
||||||
|
bDisableMovement=true
|
||||||
|
bDisablesWeaponFiring=true
|
||||||
|
}
|
1444
ServerExt/Classes/Ext_PerkBase.uc
Normal file
1444
ServerExt/Classes/Ext_PerkBase.uc
Normal file
File diff suppressed because it is too large
Load Diff
56
ServerExt/Classes/Ext_PerkBerserker.uc
Normal file
56
ServerExt/Classes/Ext_PerkBerserker.uc
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
Class Ext_PerkBerserker extends Ext_PerkBase;
|
||||||
|
|
||||||
|
var float VampRegenRate,ZedTimeMeleeAtkRate;
|
||||||
|
|
||||||
|
replication
|
||||||
|
{
|
||||||
|
// Things the server should send to the client.
|
||||||
|
if ( true )
|
||||||
|
ZedTimeMeleeAtkRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function ModifyMeleeAttackSpeed( out float InDuration )
|
||||||
|
{
|
||||||
|
InDuration *= Modifiers[4];
|
||||||
|
if( ZedTimeMeleeAtkRate<1.f && WorldInfo.TimeDilation<1.f )
|
||||||
|
InDuration *= ZedTimeMeleeAtkRate;
|
||||||
|
}
|
||||||
|
simulated function ModifyRateOfFire( out float InRate, KFWeapon KFW )
|
||||||
|
{
|
||||||
|
if( IsWeaponOnPerk(KFW) )
|
||||||
|
{
|
||||||
|
InRate *= Modifiers[4];
|
||||||
|
if( ZedTimeMeleeAtkRate<1.f && WorldInfo.TimeDilation<1.f )
|
||||||
|
InRate *= ZedTimeMeleeAtkRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function PlayerKilled( KFPawn_Monster Victim, class<DamageType> DT )
|
||||||
|
{
|
||||||
|
if( VampRegenRate>0 && PlayerOwner.Pawn!=None && PlayerOwner.Pawn.Health>0 && class<KFDamageType>(DT)!=None && class<KFDamageType>(DT).Default.ModifierPerkList.Find(BasePerk)>=0 )
|
||||||
|
PlayerOwner.Pawn.HealDamage( Max(PlayerOwner.Pawn.HealthMax*VampRegenRate,1), PlayerOwner, class'KFDT_Healing', false, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
PerkName="Berserker"
|
||||||
|
PerkIcon=Texture2D'UI_PerkIcons_TEX.UI_PerkIcon_Berserker'
|
||||||
|
DefTraitList.Add(class'Ext_TraitWPBers')
|
||||||
|
DefTraitList.Add(class'Ext_TraitUnGrab')
|
||||||
|
DefTraitList.Add(class'Ext_TraitVampire')
|
||||||
|
DefTraitList.Add(class'Ext_TraitSpartan')
|
||||||
|
DefPerkStats(15)=(bHiddenConfig=false) // Poison damage.
|
||||||
|
BasePerk=class'KFPerk_Berserker'
|
||||||
|
|
||||||
|
PrimaryMelee=class'KFWeap_Knife_Berserker'
|
||||||
|
PrimaryWeapon=class'KFWeap_Blunt_Crovel'
|
||||||
|
PerkGrenade=class'KFProj_EMPGrenade'
|
||||||
|
|
||||||
|
PrimaryWeaponDef=class'KFWeapDef_Crovel'
|
||||||
|
KnifeWeaponDef=class'KFweapDef_Knife_Berserker'
|
||||||
|
GrenadeWeaponDef=class'KFWeapDef_Grenade_Berserker'
|
||||||
|
|
||||||
|
AutoBuyLoadOutPath=(class'KFWeapDef_Crovel', class'KFWeapDef_Nailgun', class'KFWeapDef_Pulverizer', class'KFWeapDef_Eviscerator')
|
||||||
|
|
||||||
|
ZedTimeMeleeAtkRate=1.0
|
||||||
|
}
|
27
ServerExt/Classes/Ext_PerkCommando.uc
Normal file
27
ServerExt/Classes/Ext_PerkCommando.uc
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Class Ext_PerkCommando extends Ext_PerkBase;
|
||||||
|
|
||||||
|
simulated function bool GetUsingTactialReload( KFWeapon KFW )
|
||||||
|
{
|
||||||
|
return (IsWeaponOnPerk(KFW) ? Modifiers[5]<0.65 : false);
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
PerkName="Commando"
|
||||||
|
PerkIcon=Texture2D'UI_PerkIcons_TEX.UI_PerkIcon_Commando'
|
||||||
|
DefTraitList.Add(class'Ext_TraitWPComm')
|
||||||
|
DefTraitList.Add(class'Ext_TraitUnCloak')
|
||||||
|
DefTraitList.Add(class'Ext_TraitEnemyHP')
|
||||||
|
DefTraitList.Add(class'Ext_TraitEliteReload')
|
||||||
|
BasePerk=class'KFPerk_Commando'
|
||||||
|
|
||||||
|
PrimaryMelee=class'KFWeap_Knife_Commando'
|
||||||
|
PrimaryWeapon=class'KFWeap_AssaultRifle_AR15'
|
||||||
|
PerkGrenade=class'KFProj_HEGrenade'
|
||||||
|
|
||||||
|
PrimaryWeaponDef=class'KFWeapDef_AR15'
|
||||||
|
KnifeWeaponDef=class'KFweapDef_Knife_Commando'
|
||||||
|
GrenadeWeaponDef=class'KFWeapDef_Grenade_Commando'
|
||||||
|
|
||||||
|
AutoBuyLoadOutPath=(class'KFWeapDef_AR15', class'KFWeapDef_Bullpup', class'KFWeapDef_AK12', class'KFWeapDef_SCAR')
|
||||||
|
}
|
25
ServerExt/Classes/Ext_PerkDemolition.uc
Normal file
25
ServerExt/Classes/Ext_PerkDemolition.uc
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
Class Ext_PerkDemolition extends Ext_PerkBase;
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
PerkName="Demolitionist"
|
||||||
|
PerkIcon=Texture2D'UI_PerkIcons_TEX.UI_PerkIcon_Demolition'
|
||||||
|
DefTraitList.Add(class'Ext_TraitWPDemo')
|
||||||
|
DefTraitList.Add(class'Ext_TraitBoomWeld')
|
||||||
|
DefTraitList.Add(class'Ext_TraitContactNade')
|
||||||
|
DefTraitList.Add(class'Ext_TraitSupplyGren')
|
||||||
|
BasePerk=class'KFPerk_Demolitionist'
|
||||||
|
|
||||||
|
PrimaryMelee=class'KFWeap_Knife_Demolitionist'
|
||||||
|
PrimaryWeapon=class'KFWeap_GrenadeLauncher_HX25'
|
||||||
|
PerkGrenade=class'KFProj_DynamiteGrenade'
|
||||||
|
|
||||||
|
PrimaryWeaponDef=class'KFWeapDef_HX25'
|
||||||
|
KnifeWeaponDef=class'KFWeapDef_Knife_Demo'
|
||||||
|
GrenadeWeaponDef=class'KFWeapDef_Grenade_Demo'
|
||||||
|
|
||||||
|
AutoBuyLoadOutPath=(class'KFWeapDef_HX25', class'KFWeapDef_M79', class'KFWeapDef_M16M203', class'KFWeapDef_RPG7')
|
||||||
|
|
||||||
|
DefPerkStats(10)=(bHiddenConfig=true) // No support for mag size on demo.
|
||||||
|
DefPerkStats(13)=(bHiddenConfig=false) // Self damage.
|
||||||
|
}
|
83
ServerExt/Classes/Ext_PerkFieldMedic.uc
Normal file
83
ServerExt/Classes/Ext_PerkFieldMedic.uc
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
Class Ext_PerkFieldMedic extends Ext_PerkBase;
|
||||||
|
|
||||||
|
var float RepairArmorRate,AirborneAgentHealRate;
|
||||||
|
var byte AirborneAgentLevel;
|
||||||
|
|
||||||
|
function bool RepairArmor( Pawn HealTarget )
|
||||||
|
{
|
||||||
|
local KFPawn_Human KFPH;
|
||||||
|
|
||||||
|
if( RepairArmorRate>0 )
|
||||||
|
{
|
||||||
|
KFPH = KFPawn_Human(Healtarget);
|
||||||
|
if( KFPH != none && KFPH.Armor < KFPH.MaxArmor )
|
||||||
|
{
|
||||||
|
KFPH.AddArmor( Round( float(KFPH.MaxArmor) * RepairArmorRate ) );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function bool ModifyHealAmount( out float HealAmount )
|
||||||
|
{
|
||||||
|
HealAmount*=Modifiers[9];
|
||||||
|
return (RepairArmorRate>0);
|
||||||
|
}
|
||||||
|
simulated function ModifyHealerRechargeTime( out float RechargeRate )
|
||||||
|
{
|
||||||
|
RechargeRate/=Modifiers[9];
|
||||||
|
}
|
||||||
|
|
||||||
|
function CheckForAirborneAgent( KFPawn HealTarget, class<DamageType> DamType, int HealAmount )
|
||||||
|
{
|
||||||
|
if( (AirborneAgentLevel==1 && WorldInfo.TimeDilation<1.f) || AirborneAgentLevel>1 )
|
||||||
|
GiveMedicAirborneAgentHealth( HealTarget, DamType, HealAmount );
|
||||||
|
}
|
||||||
|
|
||||||
|
function GiveMedicAirborneAgentHealth( KFPawn HealTarget, class<DamageType> DamType, int HealAmount )
|
||||||
|
{
|
||||||
|
local KFPawn KFP;
|
||||||
|
local int RoundedExtraHealAmount;
|
||||||
|
|
||||||
|
RoundedExtraHealAmount = FCeil( float(HealAmount) * AirborneAgentHealRate );
|
||||||
|
|
||||||
|
foreach WorldInfo.Allpawns(class'KFPawn', KFP, HealTarget.Location, 500.f)
|
||||||
|
{
|
||||||
|
if( KFP.IsAliveAndWell() && WorldInfo.GRI.OnSameTeam( HealTarget, KFP ) )
|
||||||
|
{
|
||||||
|
if ( HealTarget == KFP )
|
||||||
|
KFP.HealDamage( RoundedExtraHealAmount, PlayerOwner, DamType );
|
||||||
|
else KFP.HealDamage( RoundedExtraHealAmount + HealAmount, PlayerOwner, DamType );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
PerkName="Field Medic"
|
||||||
|
PerkIcon=Texture2D'UI_PerkIcons_TEX.UI_PerkIcon_Medic'
|
||||||
|
DefTraitList.Remove(class'Ext_TraitMedicPistol')
|
||||||
|
DefTraitList.Add(class'Ext_TraitAirborne')
|
||||||
|
DefTraitList.Add(class'Ext_TraitWPMedic')
|
||||||
|
DefTraitList.Add(class'Ext_TraitArmorRep')
|
||||||
|
DefTraitList.Add(class'Ext_TraitToxicDart')
|
||||||
|
BasePerk=class'KFPerk_FieldMedic'
|
||||||
|
HealExpUpNum=3
|
||||||
|
|
||||||
|
DefPerkStats(0)=(MaxValue=70)
|
||||||
|
DefPerkStats(9)=(bHiddenConfig=false) // Heal efficiency
|
||||||
|
DefPerkStats(15)=(bHiddenConfig=false) // Toxic resistance
|
||||||
|
DefPerkStats(16)=(bHiddenConfig=false) // Sonic resistance
|
||||||
|
DefPerkStats(17)=(bHiddenConfig=false) // Fire resistance
|
||||||
|
|
||||||
|
PrimaryMelee=class'KFWeap_Knife_FieldMedic'
|
||||||
|
PrimaryWeapon=class'KFWeap_Pistol_Medic'
|
||||||
|
PerkGrenade=class'KFProj_MedicGrenade'
|
||||||
|
SuperGrenade=class'ExtProj_SUPERMedGrenade'
|
||||||
|
|
||||||
|
PrimaryWeaponDef=class'KFWeapDef_MedicPistol'
|
||||||
|
KnifeWeaponDef=class'KFWeapDef_Knife_Medic'
|
||||||
|
GrenadeWeaponDef=class'KFWeapDef_Grenade_Medic'
|
||||||
|
|
||||||
|
AutoBuyLoadOutPath=(class'KFWeapDef_MedicPistol', class'KFWeapDef_MedicSMG', class'KFWeapDef_MedicShotgun', class'KFWeapDef_MedicRifle')
|
||||||
|
}
|
26
ServerExt/Classes/Ext_PerkFirebug.uc
Normal file
26
ServerExt/Classes/Ext_PerkFirebug.uc
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
Class Ext_PerkFirebug extends Ext_PerkBase;
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
PerkName="Firebug"
|
||||||
|
PerkIcon=Texture2D'UI_PerkIcons_TEX.UI_PerkIcon_Firebug'
|
||||||
|
DefTraitList.Add(class'Ext_TraitWPFire')
|
||||||
|
DefTraitList.Add(class'Ext_TraitNapalm')
|
||||||
|
DefTraitList.Add(class'Ext_TraitFireExplode')
|
||||||
|
DefTraitList.Add(class'Ext_TraitFireRange')
|
||||||
|
BasePerk=class'KFPerk_Firebug'
|
||||||
|
|
||||||
|
PrimaryMelee=class'KFWeap_Knife_Firebug'
|
||||||
|
PrimaryWeapon=class'KFWeap_Flame_CaulkBurn'
|
||||||
|
PerkGrenade=class'KFProj_MolotovGrenade'
|
||||||
|
SuperGrenade=class'ExtProj_SUPERMolotov'
|
||||||
|
|
||||||
|
PrimaryWeaponDef=class'KFWeapDef_CaulkBurn'
|
||||||
|
KnifeWeaponDef=class'KFWeapDef_Knife_Firebug'
|
||||||
|
GrenadeWeaponDef=class'KFWeapDef_Grenade_Firebug'
|
||||||
|
|
||||||
|
AutoBuyLoadOutPath=(class'KFWeapDef_CaulkBurn', class'KFWeapDef_DragonsBreath', class'KFWeapDef_FlameThrower', class'KFWeapDef_MicrowaveGun')
|
||||||
|
|
||||||
|
DefPerkStats(13)=(Progress=3,bHiddenConfig=false) // Self damage.
|
||||||
|
DefPerkStats(17)=(bHiddenConfig=false) // Fire resistance
|
||||||
|
}
|
43
ServerExt/Classes/Ext_PerkGunslinger.uc
Normal file
43
ServerExt/Classes/Ext_PerkGunslinger.uc
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
Class Ext_PerkGunslinger extends Ext_PerkRhythmPerkBase;
|
||||||
|
|
||||||
|
var bool bHasUberAmmo,bHasFanfire;
|
||||||
|
|
||||||
|
replication
|
||||||
|
{
|
||||||
|
// Things the server should send to the client.
|
||||||
|
if ( true )
|
||||||
|
bHasUberAmmo,bHasFanfire;
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function bool GetIsUberAmmoActive( KFWeapon KFW )
|
||||||
|
{
|
||||||
|
return bHasUberAmmo && IsWeaponOnPerk(KFW) && WorldInfo.TimeDilation < 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function float GetZedTimeModifier( KFWeapon W )
|
||||||
|
{
|
||||||
|
if( bHasFanfire && WorldInfo.TimeDilation<1.f && IsWeaponOnPerk(W) && BasePerk.Default.ZedTimeModifyingStates.Find(W.GetStateName()) != INDEX_NONE )
|
||||||
|
return 0.9f;
|
||||||
|
return 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
PerkName="Gunslinger"
|
||||||
|
DefTraitList.Add(class'Ext_TraitWPGuns')
|
||||||
|
DefTraitList.Add(class'Ext_TraitUberAmmo')
|
||||||
|
DefTraitList.Add(class'Ext_TraitFanfire')
|
||||||
|
DefTraitList.Add(class'Ext_TraitRackEmUp')
|
||||||
|
PerkIcon=Texture2D'UI_PerkIcons_TEX.UI_PerkIcon_Gunslinger'
|
||||||
|
BasePerk=class'KFPerk_Gunslinger'
|
||||||
|
|
||||||
|
PrimaryMelee=class'KFWeap_Knife_Gunslinger'
|
||||||
|
PrimaryWeapon=class'KFWeap_Revolver_DualRem1858'
|
||||||
|
PerkGrenade=class'KFProj_NailBombGrenade'
|
||||||
|
|
||||||
|
PrimaryWeaponDef=class'KFWeapDef_Remington1858Dual'
|
||||||
|
KnifeWeaponDef=class'KFWeapDef_Knife_Gunslinger'
|
||||||
|
GrenadeWeaponDef=class'KFWeapDef_Grenade_Gunslinger'
|
||||||
|
|
||||||
|
AutoBuyLoadOutPath=(class'KFWeapDef_Remington1858', class'KFWeapDef_Remington1858Dual', class'KFWeapDef_Colt1911', class'KFWeapDef_Colt1911Dual',class'KFWeapDef_Deagle', class'KFWeapDef_DeagleDual', class'KFWeapDef_SW500', class'KFWeapDef_SW500Dual')
|
||||||
|
}
|
106
ServerExt/Classes/Ext_PerkRhythmPerkBase.uc
Normal file
106
ServerExt/Classes/Ext_PerkRhythmPerkBase.uc
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
Class Ext_PerkRhythmPerkBase extends Ext_PerkBase;
|
||||||
|
|
||||||
|
var byte HeadShotComboCount,MaxRhythmCombo,MissComboCount;
|
||||||
|
var float RhythmComboDmg;
|
||||||
|
|
||||||
|
simulated function ModifyDamageGiven( out int InDamage, optional Actor DamageCauser, optional KFPawn_Monster MyKFPM, optional KFPlayerController DamageInstigator, optional class<KFDamageType> DamageType, optional int HitZoneIdx )
|
||||||
|
{
|
||||||
|
Super.ModifyDamageGiven(InDamage,DamageCauser,MyKFPM,DamageInstigator,DamageType,HitZoneIdx);
|
||||||
|
if( RhythmComboDmg>0 && BasePerk==None || (DamageType!=None && DamageType.Default.ModifierPerkList.Find(BasePerk)>=0) || IsWeaponOnPerk(KFWeapon(DamageCauser)) )
|
||||||
|
InDamage *= (1.f+RhythmComboDmg);
|
||||||
|
}
|
||||||
|
|
||||||
|
final function SetMaxRhythm( byte MaxCombo )
|
||||||
|
{
|
||||||
|
MaxRhythmCombo = MaxCombo;
|
||||||
|
}
|
||||||
|
final function ResetRhythm()
|
||||||
|
{
|
||||||
|
MaxRhythmCombo = 0;
|
||||||
|
HeadShotComboCount = 0;
|
||||||
|
RhythmComboDmg = 0;
|
||||||
|
MissComboCount = 0;
|
||||||
|
HeadShotMessage(0,true,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
final function UpdateDmgScale( bool bUp )
|
||||||
|
{
|
||||||
|
if( bUp )
|
||||||
|
{
|
||||||
|
MissComboCount = 0;
|
||||||
|
HeadShotComboCount = Min(HeadShotComboCount+1,255);
|
||||||
|
HeadShotMessage(HeadShotComboCount,false,MaxRhythmCombo);
|
||||||
|
}
|
||||||
|
else if( HeadShotComboCount>0 && ++MissComboCount==3 )
|
||||||
|
{
|
||||||
|
--HeadShotComboCount;
|
||||||
|
HeadShotMessage(HeadShotComboCount,true,MaxRhythmCombo);
|
||||||
|
MissComboCount = 0;
|
||||||
|
}
|
||||||
|
else return;
|
||||||
|
RhythmComboDmg = FMin(HeadShotComboCount,MaxRhythmCombo)*0.075;
|
||||||
|
}
|
||||||
|
function UpdatePerkHeadShots( ImpactInfo Impact, class<DamageType> DamageType, int NumHit )
|
||||||
|
{
|
||||||
|
local int HitZoneIdx;
|
||||||
|
local KFPawn_Monster KFPM;
|
||||||
|
|
||||||
|
if( MaxRhythmCombo<=0 )
|
||||||
|
return;
|
||||||
|
KFPM = KFPawn_Monster(Impact.HitActor);
|
||||||
|
if( KFPM==none || KFPM.GetTeamNum()==0 )
|
||||||
|
{
|
||||||
|
if( NumHit < 1 && HeadShotComboCount>0 )
|
||||||
|
UpdateDmgScale(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HitZoneIdx = KFPM.HitZones.Find('ZoneName', Impact.HitInfo.BoneName);
|
||||||
|
if( HitZoneIdx == HZI_Head && KFPM.IsAliveAndWell() )
|
||||||
|
{
|
||||||
|
if( class<KFDamageType>(DamageType)!=None && class<KFDamageType>(DamageType).Default.ModifierPerkList.Find(BasePerk)>=0 )
|
||||||
|
UpdateDmgScale(true);
|
||||||
|
else if( HeadShotComboCount>0 )
|
||||||
|
UpdateDmgScale(false);
|
||||||
|
}
|
||||||
|
else if( NumHit < 1 && HeadShotComboCount>0 )
|
||||||
|
UpdateDmgScale(false);
|
||||||
|
}
|
||||||
|
reliable client function HeadShotMessage( byte HeadShotNum, bool bMissed, byte MaxHits )
|
||||||
|
{
|
||||||
|
local AkEvent TempAkEvent;
|
||||||
|
local KFPlayerController PC;
|
||||||
|
|
||||||
|
PC = KFPlayerController(PlayerOwner);
|
||||||
|
if( PC==none || PC.MyGFxHUD==none )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PC.MyGFxHUD.RhythmCounterWidget.SetInt("count", HeadShotNum);
|
||||||
|
PC.MyGFxHUD.RhythmCounterWidget.SetBonusPercentage(float(HeadShotNum) / float(MaxHits));
|
||||||
|
|
||||||
|
if( HeadshotNum==0 )
|
||||||
|
TempAkEvent = AkEvent'WW_UI_PlayerCharacter.Play_R_Method_Reset';
|
||||||
|
else if( HeadShotNum<MaxHits )
|
||||||
|
{
|
||||||
|
if( !bMissed )
|
||||||
|
{
|
||||||
|
//PC.ClientSpawnCameraLensEffect(class'KFCameraLensEmit_RackemHeadShot');
|
||||||
|
TempAkEvent = AkEvent'WW_UI_PlayerCharacter.Play_R_Method_Hit';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( !bMissed )
|
||||||
|
{
|
||||||
|
//PC.ClientSpawnCameraLensEffect(class'KFCameraLensEmit_RackemHeadShotPing');
|
||||||
|
TempAkEvent = AkEvent'WW_UI_PlayerCharacter.Play_R_Method_Top';
|
||||||
|
HeadshotNum = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( TempAkEvent != none )
|
||||||
|
PC.PlayRMEffect( TempAkEvent, 'R_Method', HeadshotNum );
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
}
|
41
ServerExt/Classes/Ext_PerkSWAT.uc
Normal file
41
ServerExt/Classes/Ext_PerkSWAT.uc
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
Class Ext_PerkSWAT extends Ext_PerkBase;
|
||||||
|
|
||||||
|
var byte RepTacticalMove;
|
||||||
|
var float MoveSpeedMods[3];
|
||||||
|
|
||||||
|
replication
|
||||||
|
{
|
||||||
|
// Things the server should send to the client.
|
||||||
|
if ( true )
|
||||||
|
RepTacticalMove;
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function float GetIronSightSpeedModifier( KFWeapon KFW )
|
||||||
|
{
|
||||||
|
return ((RepTacticalMove>0 && IsWeaponOnPerk(KFW)) ? MoveSpeedMods[RepTacticalMove-1] : 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
PerkName="SWAT"
|
||||||
|
PerkIcon=Texture2D'UI_PerkIcons_TEX.UI_PerkIcon_SWAT'
|
||||||
|
DefTraitList.Add(class'Ext_TraitWPSWAT')
|
||||||
|
DefTraitList.Add(class'Ext_TraitHeavyArmor')
|
||||||
|
DefTraitList.Add(class'Ext_TraitTacticalMove')
|
||||||
|
DefTraitList.Add(class'Ext_TraitSWATEnforcer')
|
||||||
|
BasePerk=class'KFPerk_SWAT'
|
||||||
|
|
||||||
|
PrimaryMelee=class'KFWeap_Knife_SWAT'
|
||||||
|
PrimaryWeapon=class'KFWeap_SMG_MP7'
|
||||||
|
PerkGrenade=class'KFProj_FlashBangGrenade'
|
||||||
|
|
||||||
|
PrimaryWeaponDef=class'KFWeapDef_MP7'
|
||||||
|
KnifeWeaponDef=class'KFweapDef_Knife_SWAT'
|
||||||
|
GrenadeWeaponDef=class'KFWeapDef_Grenade_SWAT'
|
||||||
|
|
||||||
|
AutoBuyLoadOutPath=(class'KFWeapDef_MP7', class'KFWeapDef_MP5RAS', class'KFWeapDef_P90', class'KFWeapDef_Kriss')
|
||||||
|
|
||||||
|
MoveSpeedMods(0)=1.3
|
||||||
|
MoveSpeedMods(1)=1.5
|
||||||
|
MoveSpeedMods(2)=2
|
||||||
|
}
|
48
ServerExt/Classes/Ext_PerkSharpshooter.uc
Normal file
48
ServerExt/Classes/Ext_PerkSharpshooter.uc
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
Class Ext_PerkSharpshooter extends Ext_PerkRhythmPerkBase;
|
||||||
|
|
||||||
|
var bool bHasDireReload;
|
||||||
|
var float ZEDTimeStunPower,DireReloadSpeed;
|
||||||
|
|
||||||
|
replication
|
||||||
|
{
|
||||||
|
// Things the server should send to the client.
|
||||||
|
if ( true )
|
||||||
|
bHasDireReload;
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function float GetReloadRateScale(KFWeapon KFW)
|
||||||
|
{
|
||||||
|
if( bHasDireReload && PlayerOwner.Pawn!=None && PlayerOwner.Pawn.Health<40 )
|
||||||
|
return Super.GetReloadRateScale(KFW)*DireReloadSpeed;
|
||||||
|
return Super.GetReloadRateScale(KFW);
|
||||||
|
}
|
||||||
|
function float GetStunPowerModifier( optional class<DamageType> DamageType, optional byte HitZoneIdx )
|
||||||
|
{
|
||||||
|
if( ZEDTimeStunPower>0 && HitZoneIdx==HZI_Head && WorldInfo.TimeDilation<1.f && (class<KFDamageType>(DamageType)!=None && class<KFDamageType>(DamageType).Default.ModifierPerkList.Find(BasePerk)>=0) )
|
||||||
|
return Super.GetStunPowerModifier(DamageType,HitZoneIdx) + ZEDTimeStunPower;
|
||||||
|
return Super.GetStunPowerModifier(DamageType,HitZoneIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
PerkName="Sharpshooter"
|
||||||
|
PerkIcon=Texture2D'UI_PerkIcons_TEX.UI_PerkIcon_Sharpshooter'
|
||||||
|
DefTraitList.Add(class'Ext_TraitWPSharp')
|
||||||
|
DefTraitList.Add(class'Ext_TraitRackEmUp')
|
||||||
|
DefTraitList.Add(class'Ext_TraitRanger')
|
||||||
|
DefTraitList.Add(class'Ext_TraitDireReload')
|
||||||
|
DefTraitList.Add(class'Ext_TraitEliteReload')
|
||||||
|
BasePerk=class'KFPerk_Sharpshooter'
|
||||||
|
|
||||||
|
PrimaryMelee=class'KFWeap_Knife_Sharpshooter'
|
||||||
|
PrimaryWeapon=class'KFWeap_Rifle_Winchester1894'
|
||||||
|
PerkGrenade=class'KFProj_FreezeGrenade'
|
||||||
|
|
||||||
|
PrimaryWeaponDef=class'KFWeapDef_Winchester1894'
|
||||||
|
KnifeWeaponDef=class'KFWeapDef_Knife_Sharpshooter'
|
||||||
|
GrenadeWeaponDef=class'KFWeapDef_Grenade_Sharpshooter'
|
||||||
|
|
||||||
|
AutoBuyLoadOutPath=(class'KFWeapDef_Winchester1894', class'KFWeapDef_Crossbow', class'KFWeapDef_M14EBR', class'KFWeapDef_RailGun')
|
||||||
|
|
||||||
|
DireReloadSpeed=0.25f
|
||||||
|
}
|
24
ServerExt/Classes/Ext_PerkSupport.uc
Normal file
24
ServerExt/Classes/Ext_PerkSupport.uc
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
Class Ext_PerkSupport extends Ext_PerkBase;
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
PerkName="Support"
|
||||||
|
PerkIcon=Texture2D'UI_PerkIcons_TEX.UI_PerkIcon_Support'
|
||||||
|
DefTraitList.Add(class'Ext_TraitWPSupp')
|
||||||
|
DefTraitList.Add(class'Ext_TraitSupply')
|
||||||
|
DefTraitList(0)=class'Ext_TraitGrenadeSUpg'
|
||||||
|
BasePerk=class'KFPerk_Support'
|
||||||
|
WeldExpUpNum=80
|
||||||
|
|
||||||
|
DefPerkStats(0)=(MaxValue=20,CostPerValue=2)
|
||||||
|
DefPerkStats(8)=(bHiddenConfig=false)
|
||||||
|
|
||||||
|
PrimaryMelee=class'KFWeap_Knife_Support'
|
||||||
|
PrimaryWeapon=class'KFWeap_Shotgun_MB500'
|
||||||
|
|
||||||
|
PrimaryWeaponDef=class'KFWeapDef_MB500'
|
||||||
|
KnifeWeaponDef=class'KFWeapDef_Knife_Support'
|
||||||
|
GrenadeWeaponDef=class'KFWeapDef_Grenade_Support'
|
||||||
|
|
||||||
|
AutoBuyLoadOutPath=(class'KFWeapDef_MB500', class'KFWeapDef_DoubleBarrel', class'KFWeapDef_M4', class'KFWeapDef_AA12')
|
||||||
|
}
|
20
ServerExt/Classes/Ext_PerkSurvivalist.uc
Normal file
20
ServerExt/Classes/Ext_PerkSurvivalist.uc
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
Class Ext_PerkSurvivalist extends Ext_PerkBase;
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
PerkName="Survivalist"
|
||||||
|
PerkIcon=Texture2D'UI_PerkIcons_TEX.UI_PerkIcon_Survivalist'
|
||||||
|
DefTraitList.Add(class'Ext_TraitWPSurv')
|
||||||
|
//DefTraitList.Add(class'Ext_TraitHeavyArmor')
|
||||||
|
BasePerk=class'KFPerk_Survivalist'
|
||||||
|
|
||||||
|
PrimaryMelee=class'KFWeap_Random'
|
||||||
|
PrimaryWeapon=class'KFWeap_Knife_Support'
|
||||||
|
PerkGrenade=class'KFProj_HEGrenade'
|
||||||
|
|
||||||
|
PrimaryWeaponDef=class'KFWeapDef_Random'
|
||||||
|
KnifeWeaponDef=class'KFweapDef_Knife_Support'
|
||||||
|
GrenadeWeaponDef=class'KFWeapDef_Grenade_Commando'
|
||||||
|
|
||||||
|
AutoBuyLoadOutPath=(class'KFWeapDef_DragonsBreath', class'KFWeapDef_M16M203', class'KFWeapDef_MedicRifle')
|
||||||
|
}
|
34
ServerExt/Classes/Ext_TGroupBase.uc
Normal file
34
ServerExt/Classes/Ext_TGroupBase.uc
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Trait group info.
|
||||||
|
Class Ext_TGroupBase extends Object
|
||||||
|
abstract;
|
||||||
|
|
||||||
|
var() string GroupInfo;
|
||||||
|
var() bool bLimitToOne; // Limit to only one trait for this group.
|
||||||
|
|
||||||
|
static function string GetUIInfo( Ext_PerkBase Perk )
|
||||||
|
{
|
||||||
|
return (Default.bLimitToOne ? Default.GroupInfo$" (MAX 1)" : Default.GroupInfo);
|
||||||
|
}
|
||||||
|
static function string GetUIDesc()
|
||||||
|
{
|
||||||
|
return Default.GroupInfo$" trait group";
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if group is already using up limitation.
|
||||||
|
static function bool GroupLimited( Ext_PerkBase Perk, class<Ext_TraitBase> Trait )
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
if( Default.bLimitToOne )
|
||||||
|
{
|
||||||
|
for( i=0; i<Perk.PerkTraits.Length; ++i )
|
||||||
|
if( Perk.PerkTraits[i].CurrentLevel>0 && Perk.PerkTraits[i].TraitType!=Trait && Perk.PerkTraits[i].TraitType.Default.TraitGroup==Default.Class )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
GroupInfo="Group"
|
||||||
|
}
|
6
ServerExt/Classes/Ext_TGroupMonster.uc
Normal file
6
ServerExt/Classes/Ext_TGroupMonster.uc
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
class Ext_TGroupMonster extends Ext_TGroupBase;
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
GroupInfo="Monster"
|
||||||
|
}
|
34
ServerExt/Classes/Ext_TGroupRegen.uc
Normal file
34
ServerExt/Classes/Ext_TGroupRegen.uc
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
class Ext_TGroupRegen extends Ext_TGroupBase;
|
||||||
|
|
||||||
|
static function string GetUIInfo( Ext_PerkBase Perk )
|
||||||
|
{
|
||||||
|
return Default.GroupInfo$" (MAX "$GetMaxLimit(Perk)$")";
|
||||||
|
}
|
||||||
|
static function string GetUIDesc()
|
||||||
|
{
|
||||||
|
return Super.GetUIDesc()$"|To buy additional regen abilities:|-Prestige level 1 + Perk level 100 = MAX 2 traits|-Prestige level 5 + Perk level 150 = MAX 3 traits";
|
||||||
|
}
|
||||||
|
|
||||||
|
static function bool GroupLimited( Ext_PerkBase Perk, class<Ext_TraitBase> Trait )
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
local byte n;
|
||||||
|
|
||||||
|
n = GetMaxLimit(Perk);
|
||||||
|
for( i=0; i<Perk.PerkTraits.Length; ++i )
|
||||||
|
if( Perk.PerkTraits[i].CurrentLevel>0 && Perk.PerkTraits[i].TraitType!=Trait && Perk.PerkTraits[i].TraitType.Default.TraitGroup==Default.Class && --n==0 )
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function byte GetMaxLimit( Ext_PerkBase Perk )
|
||||||
|
{
|
||||||
|
if( Perk.CurrentPrestige<1 || Perk.CurrentLevel<100 )
|
||||||
|
return 1;
|
||||||
|
return ((Perk.CurrentPrestige<5 || Perk.CurrentLevel<150) ? 2 : 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
GroupInfo="Regeneration"
|
||||||
|
}
|
39
ServerExt/Classes/Ext_T_AmmoRegHelp.uc
Normal file
39
ServerExt/Classes/Ext_T_AmmoRegHelp.uc
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
Class Ext_T_AmmoRegHelp extends Info
|
||||||
|
transient;
|
||||||
|
|
||||||
|
var Pawn PawnOwner;
|
||||||
|
var float RegCount;
|
||||||
|
|
||||||
|
function PostBeginPlay()
|
||||||
|
{
|
||||||
|
PawnOwner = Pawn(Owner);
|
||||||
|
if( PawnOwner==None )
|
||||||
|
Destroy();
|
||||||
|
else SetTimer(29+FRand(),true);
|
||||||
|
}
|
||||||
|
function Timer()
|
||||||
|
{
|
||||||
|
local KFWeapon W;
|
||||||
|
local byte i;
|
||||||
|
|
||||||
|
if( PawnOwner==None || PawnOwner.Health<=0 || PawnOwner.InvManager==None )
|
||||||
|
Destroy();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach PawnOwner.InvManager.InventoryActors(class'KFWeapon',W)
|
||||||
|
{
|
||||||
|
for( i=0; i<2; ++i )
|
||||||
|
{
|
||||||
|
if( W.SpareAmmoCount[i]<W.SpareAmmoCapacity[i] )
|
||||||
|
{
|
||||||
|
W.SpareAmmoCount[i] = Min(W.SpareAmmoCount[i]+FMax(float(W.SpareAmmoCapacity[i])*RegCount,1.f),W.SpareAmmoCapacity[i]);
|
||||||
|
W.bNetDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
}
|
16
ServerExt/Classes/Ext_T_ArmorRegHelp.uc
Normal file
16
ServerExt/Classes/Ext_T_ArmorRegHelp.uc
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
Class Ext_T_ArmorRegHelp extends Ext_T_HealthRegHelp
|
||||||
|
transient;
|
||||||
|
|
||||||
|
function Timer()
|
||||||
|
{
|
||||||
|
if( PawnOwner==None || PawnOwner.Health<=0 )
|
||||||
|
Destroy();
|
||||||
|
else if( PawnOwner.Armor<PawnOwner.MaxArmor )
|
||||||
|
{
|
||||||
|
PawnOwner.Armor = Min(PawnOwner.Armor+RegCount,PawnOwner.MaxArmor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
}
|
55
ServerExt/Classes/Ext_T_AutoFireHelper.uc
Normal file
55
ServerExt/Classes/Ext_T_AutoFireHelper.uc
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
Class Ext_T_AutoFireHelper extends Info
|
||||||
|
transient;
|
||||||
|
|
||||||
|
var class<KFPerk> AssociatedPerkClass;
|
||||||
|
var Pawn PawnOwner;
|
||||||
|
var PlayerController LocalPC;
|
||||||
|
var bool bNetworkOwner;
|
||||||
|
|
||||||
|
replication
|
||||||
|
{
|
||||||
|
if ( bNetOwner )
|
||||||
|
PawnOwner,AssociatedPerkClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
function PostBeginPlay()
|
||||||
|
{
|
||||||
|
PawnOwner = Pawn(Owner);
|
||||||
|
if( PawnOwner==None )
|
||||||
|
Destroy();
|
||||||
|
else SetTimer(0.5+FRand()*0.4,true);
|
||||||
|
}
|
||||||
|
function Timer()
|
||||||
|
{
|
||||||
|
if( PawnOwner==None || PawnOwner.Health<=0 || PawnOwner.InvManager==None )
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
simulated function Tick( float Delta )
|
||||||
|
{
|
||||||
|
if( WorldInfo.NetMode==NM_DedicatedServer || PawnOwner==None || PawnOwner.InvManager==None || KFWeapon(PawnOwner.Weapon)==None || KFWeapon(PawnOwner.Weapon).GetWeaponPerkClass(AssociatedPerkClass)!=AssociatedPerkClass )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Find local playercontroller.
|
||||||
|
if( LocalPC==None )
|
||||||
|
{
|
||||||
|
LocalPC = PlayerController(PawnOwner.Controller);
|
||||||
|
if( LocalPC==None )
|
||||||
|
return;
|
||||||
|
bNetworkOwner = (LocalPlayer(LocalPC.Player)!=None);
|
||||||
|
}
|
||||||
|
if( !bNetworkOwner )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Force always to pending fire.
|
||||||
|
if( LocalPC.bFire!=0 && !PawnOwner.InvManager.IsPendingFire(None,0) )
|
||||||
|
PawnOwner.Weapon.StartFire(0);
|
||||||
|
else if( LocalPC.bAltFire!=0 && !PawnOwner.InvManager.IsPendingFire(None,1) )
|
||||||
|
PawnOwner.Weapon.StartFire(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
Components.Empty()
|
||||||
|
RemoteRole=ROLE_SimulatedProxy
|
||||||
|
bOnlyRelevantToOwner=true
|
||||||
|
}
|
124
ServerExt/Classes/Ext_T_GhostHelper.uc
Normal file
124
ServerExt/Classes/Ext_T_GhostHelper.uc
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
Class Ext_T_GhostHelper extends Ext_TraitDataStore;
|
||||||
|
|
||||||
|
var KFPawn_Human LastDied;
|
||||||
|
var float LastDiedTimer,TeleTime;
|
||||||
|
var vector ResPoint,TeleStartPoint;
|
||||||
|
var ExtSpawnPointHelper SpawnPointer;
|
||||||
|
var bool bTeleporting,bIsDelayed;
|
||||||
|
|
||||||
|
function bool CanResPlayer( KFPawn_Human Other, byte Level )
|
||||||
|
{
|
||||||
|
if( bTeleporting )
|
||||||
|
{
|
||||||
|
if( LastDied!=None )
|
||||||
|
LastDied.Health = 9999;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( LastDied==Other )
|
||||||
|
{
|
||||||
|
if( Level==1 || LastDiedTimer>WorldInfo.TimeSeconds )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if( Level==1 && Rand(2)==0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
LastDied = Other;
|
||||||
|
bTeleporting = true;
|
||||||
|
if( SpawnPointer==None )
|
||||||
|
SpawnPointer = class'ExtSpawnPointHelper'.Static.FindHelper(WorldInfo);
|
||||||
|
ResPoint = SpawnPointer.PickBestSpawn().Location;
|
||||||
|
LastDied.FindSpot(vect(36,36,86),ResPoint);
|
||||||
|
if( VSizeSq(LastDied.Location-ResPoint)<1.f ) // Prevent division by zero errors in future.
|
||||||
|
ResPoint.Z+=5;
|
||||||
|
Enable('Tick');
|
||||||
|
StartResurrect();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final function StartResurrect()
|
||||||
|
{
|
||||||
|
TeleStartPoint = LastDied.Location;
|
||||||
|
LastDied.Health = 9999;
|
||||||
|
LastDied.LastStartTime = WorldInfo.TimeSeconds;
|
||||||
|
|
||||||
|
if( ExtHumanPawn(LastDied)!=None )
|
||||||
|
{
|
||||||
|
ExtHumanPawn(LastDied).bCanBecomeRagdoll = false;
|
||||||
|
if( !ExtHumanPawn(LastDied).CanBeRedeemed() )
|
||||||
|
{
|
||||||
|
bIsDelayed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LastDied.SetCollision(false);
|
||||||
|
LastDied.bIgnoreForces = true;
|
||||||
|
LastDied.bAmbientCreature = true;
|
||||||
|
LastDied.SetPhysics(PHYS_None);
|
||||||
|
LastDied.bCollideWorld = false;
|
||||||
|
TeleTime = FClamp(VSize(ResPoint-TeleStartPoint)/900.f,1.f,10.f);
|
||||||
|
LastDiedTimer = WorldInfo.TimeSeconds+TeleTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Tick( float Delta )
|
||||||
|
{
|
||||||
|
if( !bTeleporting )
|
||||||
|
{
|
||||||
|
Disable('Tick');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( LastDied==None || LastDied.Health<=0 )
|
||||||
|
{
|
||||||
|
bTeleporting = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( bIsDelayed )
|
||||||
|
{
|
||||||
|
bIsDelayed = false;
|
||||||
|
StartResurrect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Delta = (LastDiedTimer-WorldInfo.TimeSeconds);
|
||||||
|
if( Delta<=0 )
|
||||||
|
{
|
||||||
|
EndGhostTeleport();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Delta /= TeleTime;
|
||||||
|
LastDied.Velocity = Normal(ResPoint-TeleStartPoint)*900.f;
|
||||||
|
LastDied.SetLocation(TeleStartPoint*Delta+ResPoint*(1.f-Delta));
|
||||||
|
if( LastDied.Physics!=PHYS_None )
|
||||||
|
LastDied.SetPhysics(PHYS_None);
|
||||||
|
}
|
||||||
|
|
||||||
|
final function EndGhostTeleport()
|
||||||
|
{
|
||||||
|
LastDiedTimer = WorldInfo.TimeSeconds+180.f;
|
||||||
|
bTeleporting = false;
|
||||||
|
LastDied.Health = LastDied.HealthMax;
|
||||||
|
LastDied.SetCollision(true);
|
||||||
|
LastDied.bIgnoreForces = false;
|
||||||
|
LastDied.bAmbientCreature = false;
|
||||||
|
LastDied.bCollideWorld = true;
|
||||||
|
LastDied.FindSpot(vect(36,36,86),ResPoint);
|
||||||
|
LastDied.SetLocation(ResPoint);
|
||||||
|
LastDied.SetPhysics(PHYS_Falling);
|
||||||
|
LastDied.Velocity = vect(0,0,0);
|
||||||
|
LastDied.LastStartTime = WorldInfo.TimeSeconds; // For spawn protection, if any.
|
||||||
|
if( LastDied.IsDoingSpecialMove() ) // Stop any grabbing zeds.
|
||||||
|
LastDied.EndSpecialMove();
|
||||||
|
|
||||||
|
if( ExtHumanPawn(LastDied)!=None )
|
||||||
|
ExtHumanPawn(LastDied).bCanBecomeRagdoll = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Destroyed()
|
||||||
|
{
|
||||||
|
if( bTeleporting && LastDied!=None && LastDied.Health>0 )
|
||||||
|
EndGhostTeleport();
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
}
|
26
ServerExt/Classes/Ext_T_HealthRegHelp.uc
Normal file
26
ServerExt/Classes/Ext_T_HealthRegHelp.uc
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
Class Ext_T_HealthRegHelp extends Info
|
||||||
|
transient;
|
||||||
|
|
||||||
|
var KFPawn_Human PawnOwner;
|
||||||
|
var byte RegCount;
|
||||||
|
|
||||||
|
function PostBeginPlay()
|
||||||
|
{
|
||||||
|
PawnOwner = KFPawn_Human(Owner);
|
||||||
|
if( PawnOwner==None )
|
||||||
|
Destroy();
|
||||||
|
else SetTimer(9+FRand(),true);
|
||||||
|
}
|
||||||
|
function Timer()
|
||||||
|
{
|
||||||
|
if( PawnOwner==None || PawnOwner.Health<=0 )
|
||||||
|
Destroy();
|
||||||
|
else if( PawnOwner.Health<PawnOwner.HealthMax )
|
||||||
|
{
|
||||||
|
PawnOwner.Health = Min(PawnOwner.Health+RegCount,PawnOwner.HealthMax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
}
|
63
ServerExt/Classes/Ext_T_MonsterPRI.uc
Normal file
63
ServerExt/Classes/Ext_T_MonsterPRI.uc
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
Class Ext_T_MonsterPRI extends PlayerReplicationInfo;
|
||||||
|
|
||||||
|
var repnotify class<Pawn> MonsterType;
|
||||||
|
var repnotify PlayerReplicationInfo OwnerPRI;
|
||||||
|
var Controller OwnerController;
|
||||||
|
var string MonsterName;
|
||||||
|
var int HealthStatus,HealthMax;
|
||||||
|
var Pawn PawnOwner;
|
||||||
|
var KFExtendedHUD OwnerHUD;
|
||||||
|
|
||||||
|
replication
|
||||||
|
{
|
||||||
|
// Things the server should send to the client.
|
||||||
|
if (bNetDirty)
|
||||||
|
OwnerPRI,MonsterType,HealthStatus,HealthMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make no efforts with this one.
|
||||||
|
simulated event PostBeginPlay()
|
||||||
|
{
|
||||||
|
if( WorldInfo.NetMode!=NM_Client )
|
||||||
|
SetTimer(1,true);
|
||||||
|
}
|
||||||
|
simulated event Destroyed()
|
||||||
|
{
|
||||||
|
if( OwnerHUD!=None )
|
||||||
|
{
|
||||||
|
OwnerHUD.MyCurrentPet.RemoveItem(Self);
|
||||||
|
OwnerHUD = None;
|
||||||
|
}
|
||||||
|
if ( WorldInfo.GRI != None )
|
||||||
|
WorldInfo.GRI.RemovePRI(self);
|
||||||
|
}
|
||||||
|
simulated event ReplicatedEvent(name VarName)
|
||||||
|
{
|
||||||
|
if( VarName=='OwnerPRI' && OwnerPRI!=None )
|
||||||
|
NotifyOwner();
|
||||||
|
else if( VarName=='MonsterType' && MonsterType!=None )
|
||||||
|
MonsterName = Class'KFExtendedHUD'.Static.GetNameOf(MonsterType);
|
||||||
|
}
|
||||||
|
simulated function Timer()
|
||||||
|
{
|
||||||
|
if( PawnOwner==None || PawnOwner.Health<=0 )
|
||||||
|
Destroy();
|
||||||
|
else if( HealthStatus!=PawnOwner.Health )
|
||||||
|
HealthStatus = PawnOwner.Health;
|
||||||
|
}
|
||||||
|
simulated final function NotifyOwner()
|
||||||
|
{
|
||||||
|
local PlayerController PC;
|
||||||
|
|
||||||
|
PC = GetALocalPlayerController();
|
||||||
|
if( PC==None || PC.PlayerReplicationInfo!=OwnerPRI || KFExtendedHUD(PC.MyHUD)==None )
|
||||||
|
return;
|
||||||
|
OwnerHUD = KFExtendedHUD(PC.MyHUD);
|
||||||
|
OwnerHUD.MyCurrentPet.AddItem(Self);
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
bBot=true
|
||||||
|
MonsterName="Petty"
|
||||||
|
}
|
205
ServerExt/Classes/Ext_T_SupplierInteract.uc
Normal file
205
ServerExt/Classes/Ext_T_SupplierInteract.uc
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
class Ext_T_SupplierInteract extends KFUsablePerkTrigger;
|
||||||
|
|
||||||
|
struct FActiveUsers
|
||||||
|
{
|
||||||
|
var Pawn Player;
|
||||||
|
var transient float NextUseTime;
|
||||||
|
};
|
||||||
|
var array<FActiveUsers> ActiveUsers;
|
||||||
|
|
||||||
|
var repnotify KFPawn_Human PlayerOwner;
|
||||||
|
var Ext_PerkBase PerkOwner;
|
||||||
|
|
||||||
|
var() float ReuseTime;
|
||||||
|
var bool bGrenades;
|
||||||
|
|
||||||
|
replication
|
||||||
|
{
|
||||||
|
if( true )
|
||||||
|
PlayerOwner,bGrenades;
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated event ReplicatedEvent(name VarName)
|
||||||
|
{
|
||||||
|
if( VarName=='PlayerOwner' && PlayerOwner!=None )
|
||||||
|
{
|
||||||
|
SetLocation(PlayerOwner.Location);
|
||||||
|
SetBase(PlayerOwner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function int GetInteractionIndex( Pawn User )
|
||||||
|
{
|
||||||
|
return (bGrenades ? IMT_ReceiveGrenades : InteractionIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated event Touch(Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal)
|
||||||
|
{
|
||||||
|
local KFPawn_Human KFP;
|
||||||
|
|
||||||
|
Super.Touch(Other, OtherComp, HitLocation, HitNormal);
|
||||||
|
|
||||||
|
KFP = KFPawn_Human(Other);
|
||||||
|
if( KFP != none && KFP.Controller != none && KFP != PlayerOwner )
|
||||||
|
{
|
||||||
|
KFPlayerController(KFP.Controller).SetPendingInteractionMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated event UnTouch(Actor Other)
|
||||||
|
{
|
||||||
|
local KFPawn_Human KFP;
|
||||||
|
|
||||||
|
super.UnTouch( Other );
|
||||||
|
|
||||||
|
KFP = KFPawn_Human(Other);
|
||||||
|
if( KFP != none && KFP.Controller != none && KFP != PlayerOwner )
|
||||||
|
{
|
||||||
|
KFPlayerController(KFP.Controller).SetPendingInteractionMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function RecheckUser()
|
||||||
|
{
|
||||||
|
local KFPawn_Human Toucher;
|
||||||
|
|
||||||
|
// Notify local player owner that this is available again.
|
||||||
|
foreach TouchingActors(class'KFPawn_Human', Toucher)
|
||||||
|
{
|
||||||
|
if( Toucher.IsLocallyControlled() )
|
||||||
|
Touch(Toucher,None,Location,vect(1,0,0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function bool GetCanInteract( Pawn User, optional bool bInteractIfTrue = false)
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
local ExtPlayerReplicationInfo PRI;
|
||||||
|
|
||||||
|
if( PlayerOwner==None || User==PlayerOwner || KFPawn_Human(User)==None || User.Health<=0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( WorldInfo.NetMode==NM_Client )
|
||||||
|
{
|
||||||
|
PRI = ExtPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo);
|
||||||
|
if( !User.IsLocallyControlled() || PRI==None || !PRI.CanUseSupply(User) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( bInteractIfTrue )
|
||||||
|
{
|
||||||
|
PRI.UsedSupply(User,ReuseTime);
|
||||||
|
SetTimer(ReuseTime+0.1,false,'RecheckUser');
|
||||||
|
|
||||||
|
if( KFPlayerController(User.Controller)!=None )
|
||||||
|
KFPlayerController(User.Controller).SetPendingInteractionMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i = ActiveUsers.Find('Player',User);
|
||||||
|
if( i>=0 && ActiveUsers[i].NextUseTime>WorldInfo.TimeSeconds )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( bInteractIfTrue )
|
||||||
|
{
|
||||||
|
if( i==-1 )
|
||||||
|
{
|
||||||
|
i = ActiveUsers.Length;
|
||||||
|
ActiveUsers.Length = i+1;
|
||||||
|
ActiveUsers[i].Player = User;
|
||||||
|
SetTimer(10.f,true,'CleanupUsers');
|
||||||
|
}
|
||||||
|
ActiveUsers[i].NextUseTime = WorldInfo.TimeSeconds+ReuseTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( bInteractIfTrue && WorldInfo.NetMode!=NM_Client )
|
||||||
|
{
|
||||||
|
GiveAmmunition(KFPawn_Human(User));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function CleanupUsers()
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
for( i=(ActiveUsers.Length-1); i>=0; --i )
|
||||||
|
if( ActiveUsers[i].Player==None || ActiveUsers[i].Player.Health<=0 || ActiveUsers[i].NextUseTime<WorldInfo.TimeSeconds )
|
||||||
|
ActiveUsers.Remove(i,1);
|
||||||
|
if( ActiveUsers.Length==0 )
|
||||||
|
ClearTimer('CleanupUsers');
|
||||||
|
}
|
||||||
|
final function GiveAmmunition( KFPawn_Human Other )
|
||||||
|
{
|
||||||
|
local KFWeapon KFW;
|
||||||
|
|
||||||
|
if( PlayerController(PlayerOwner.Controller)!=None )
|
||||||
|
PlayerController(PlayerOwner.Controller).ReceiveLocalizedMessage( class'KFLocalMessage_Game', (bGrenades ? GMT_GaveGrenadesTo : GMT_GaveAmmoTo), Other.PlayerReplicationInfo );
|
||||||
|
if( PlayerController(Other.Controller)!=None )
|
||||||
|
{
|
||||||
|
PlayerController(Other.Controller).ReceiveLocalizedMessage( class'KFLocalMessage_Game', (bGrenades ? GMT_ReceivedGrenadesFrom : GMT_ReceivedAmmoFrom), PlayerOwner.PlayerReplicationInfo );
|
||||||
|
if( ExtPlayerController(Other.Controller)!=None )
|
||||||
|
ExtPlayerController(Other.Controller).ClientUsedAmmo(Self);
|
||||||
|
}
|
||||||
|
if( PerkOwner!=None )
|
||||||
|
PerkOwner.EarnedEXP(25);
|
||||||
|
|
||||||
|
if( bGrenades )
|
||||||
|
{
|
||||||
|
if( KFInventoryManager(Other.InvManager)!=None )
|
||||||
|
KFInventoryManager(Other.InvManager).AddGrenades(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach Other.InvManager.InventoryActors( class'KFWeapon', KFW )
|
||||||
|
{
|
||||||
|
if( KFW.DenyPerkResupply() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// resupply 1 mag for every 5 initial mags
|
||||||
|
KFW.AddAmmo( Max( KFW.InitialSpareMags[0] / 3, 1 ) * KFW.MagazineCapacity[0] );
|
||||||
|
|
||||||
|
if( KFW.CanRefillSecondaryAmmo() )
|
||||||
|
{
|
||||||
|
// resupply 1 mag for every 5 initial mags
|
||||||
|
KFW.AddSecondaryAmmo( Max( KFW.InitialSpareMags[1] / 3, 1 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
simulated final function UsedOnClient( Pawn User )
|
||||||
|
{
|
||||||
|
local ExtPlayerReplicationInfo PRI;
|
||||||
|
|
||||||
|
PRI = ExtPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo);
|
||||||
|
if( PRI!=None )
|
||||||
|
PRI.UsedSupply(User,ReuseTime);
|
||||||
|
SetTimer(ReuseTime+0.1,false,'RecheckUser');
|
||||||
|
|
||||||
|
if( WorldInfo.NetMode==NM_Client && KFPlayerController(User.Controller)!=None )
|
||||||
|
KFPlayerController(User.Controller).SetPendingInteractionMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
simulated function Destroyed()
|
||||||
|
{
|
||||||
|
local KFPawn_Human Toucher;
|
||||||
|
|
||||||
|
//notify all touching actors that they are not touching this non existing trigger anymore
|
||||||
|
foreach TouchingActors(class'KFPawn_Human', Toucher)
|
||||||
|
{
|
||||||
|
UnTouch(Toucher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultProperties
|
||||||
|
{
|
||||||
|
InteractionIndex=IMT_ReceiveAmmo
|
||||||
|
RemoteRole=ROLE_SimulatedProxy
|
||||||
|
bSkipActorPropertyReplication=true
|
||||||
|
bHidden=false
|
||||||
|
ReuseTime=90
|
||||||
|
bProjTarget=false
|
||||||
|
|
||||||
|
Components.Empty()
|
||||||
|
Components.Add(CollisionCylinder)
|
||||||
|
}
|
30
ServerExt/Classes/Ext_T_UnCloakHelper.uc
Normal file
30
ServerExt/Classes/Ext_T_UnCloakHelper.uc
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
Class Ext_T_UnCloakHelper extends Info
|
||||||
|
transient;
|
||||||
|
|
||||||
|
var Pawn PawnOwner;
|
||||||
|
var float HandleRadius;
|
||||||
|
|
||||||
|
function PostBeginPlay()
|
||||||
|
{
|
||||||
|
PawnOwner = Pawn(Owner);
|
||||||
|
if( PawnOwner==None )
|
||||||
|
Destroy();
|
||||||
|
else SetTimer(0.5+FRand()*0.1,true);
|
||||||
|
}
|
||||||
|
function Timer()
|
||||||
|
{
|
||||||
|
local KFPawn_Monster M;
|
||||||
|
|
||||||
|
if( PawnOwner==None || PawnOwner.Health<=0 )
|
||||||
|
Destroy();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach WorldInfo.AllPawns(class'KFPawn_Monster',M,PawnOwner.Location,HandleRadius)
|
||||||
|
if( M.bCanCloak )
|
||||||
|
M.CallOutCloaking();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
}
|
243
ServerExt/Classes/Ext_T_ZEDHelper.uc
Normal file
243
ServerExt/Classes/Ext_T_ZEDHelper.uc
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
Class Ext_T_ZEDHelper extends Info
|
||||||
|
transient
|
||||||
|
DependsOn(Ext_TraitZED_Summon)
|
||||||
|
config(ServerExt);
|
||||||
|
|
||||||
|
var config array<FZEDTypes> ZedTypes; // Dummy hack, not really config but merely just for being able to set class on defaults.
|
||||||
|
|
||||||
|
var() float FriendlyScalar;
|
||||||
|
var Pawn PawnOwner;
|
||||||
|
var byte CurLevel,RespawnHelperTime,NoLiveCounter;
|
||||||
|
var KFPawn_Monster LiveHelper;
|
||||||
|
var class<KFPawn_Monster> PrevMonster;
|
||||||
|
var float PrevMonsterHP;
|
||||||
|
|
||||||
|
var float HPScale,DamageScale;
|
||||||
|
var int OldKillsValue;
|
||||||
|
var bool bNeedsKillZed,bIsExtra;
|
||||||
|
|
||||||
|
function PostBeginPlay()
|
||||||
|
{
|
||||||
|
PawnOwner = Pawn(Owner);
|
||||||
|
bNeedsKillZed = true;
|
||||||
|
if( PawnOwner==None )
|
||||||
|
Destroy();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OldKillsValue = PawnOwner.PlayerReplicationInfo.Kills;
|
||||||
|
SetTimer(1+(FRand()*0.1),true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function Timer()
|
||||||
|
{
|
||||||
|
if( PawnOwner==None || PawnOwner.Health<=0 || PawnOwner.PlayerReplicationInfo==None )
|
||||||
|
Destroy();
|
||||||
|
else if( bNeedsKillZed )
|
||||||
|
{
|
||||||
|
if( RespawnHelperTime>1 )
|
||||||
|
--RespawnHelperTime;
|
||||||
|
if( OldKillsValue==PawnOwner.PlayerReplicationInfo.Kills )
|
||||||
|
return;
|
||||||
|
bNeedsKillZed = false;
|
||||||
|
}
|
||||||
|
else if( RespawnHelperTime>0 )
|
||||||
|
{
|
||||||
|
if( --RespawnHelperTime==0 )
|
||||||
|
SpawnHelper();
|
||||||
|
}
|
||||||
|
else if( LiveHelper==None || LiveHelper.Health<=0 )
|
||||||
|
{
|
||||||
|
OldKillsValue = PawnOwner.PlayerReplicationInfo.Kills;
|
||||||
|
bNeedsKillZed = true;
|
||||||
|
RespawnHelperTime = 60;
|
||||||
|
}
|
||||||
|
else if( !HasLiveZeds() )
|
||||||
|
{
|
||||||
|
if( NoLiveCounter==0 )
|
||||||
|
{
|
||||||
|
PrevMonster = LiveHelper.Class;
|
||||||
|
PrevMonsterHP = (float(LiveHelper.Health) / LiveHelper.HealthMax);
|
||||||
|
LiveHelper.Died(None,class'KFDT_Healing',vect(0,0,0));
|
||||||
|
RespawnHelperTime = 5;
|
||||||
|
}
|
||||||
|
else --NoLiveCounter;
|
||||||
|
}
|
||||||
|
else NoLiveCounter = 5;
|
||||||
|
}
|
||||||
|
function Destroyed()
|
||||||
|
{
|
||||||
|
if( LiveHelper!=None && LiveHelper.Health>0 )
|
||||||
|
LiveHelper.Died(None,class'DmgType_Suicided',vect(0,0,0));
|
||||||
|
}
|
||||||
|
final function bool HasLiveZeds()
|
||||||
|
{
|
||||||
|
local KFPawn_Monster M;
|
||||||
|
|
||||||
|
if( KFGameReplicationInfo(WorldInfo.GRI).WaveNum>KFGameReplicationInfo(WorldInfo.GRI).WaveMax ) // No pets on possible bonus waves.
|
||||||
|
return false;
|
||||||
|
|
||||||
|
foreach WorldInfo.AllPawns(Class'KFPawn_Monster',M)
|
||||||
|
if( M.Health>0 && M.GetTeamNum()!=0 )
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final function SpawnHelper()
|
||||||
|
{
|
||||||
|
local class<KFPawn_Monster> MC;
|
||||||
|
local byte i;
|
||||||
|
local vector V;
|
||||||
|
local rotator R;
|
||||||
|
local Controller C;
|
||||||
|
local Ext_T_MonsterPRI PRI;
|
||||||
|
local AkBaseSoundObject TempSound;
|
||||||
|
local bool bFinalWave;
|
||||||
|
|
||||||
|
if( PawnOwner.PlayerReplicationInfo==None || !HasLiveZeds() )
|
||||||
|
{
|
||||||
|
RespawnHelperTime = 3;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NoLiveCounter = 5;
|
||||||
|
bFinalWave = KFGameReplicationInfo(WorldInfo.GRI).IsFinalWave();
|
||||||
|
if( bFinalWave && Class<KFPawn_MonsterBoss>(PrevMonster)!=None )
|
||||||
|
PrevMonster = None;
|
||||||
|
MC = (PrevMonster!=None ? PrevMonster : PickRandomMonster(CurLevel,bFinalWave));
|
||||||
|
|
||||||
|
if( MC!=None )
|
||||||
|
{
|
||||||
|
R.Yaw = Rand(65536);
|
||||||
|
if( MC.Default.SoundGroupArch!=None )
|
||||||
|
{
|
||||||
|
// Make no entrance roam (for FP's and Scrakes).
|
||||||
|
TempSound = MC.Default.SoundGroupArch.EntranceSound;
|
||||||
|
MC.Default.SoundGroupArch.EntranceSound = None;
|
||||||
|
}
|
||||||
|
for( i=0; i<40; ++i )
|
||||||
|
{
|
||||||
|
V = PawnOwner.Location;
|
||||||
|
V.X += (FRand()*300.f-150.f);
|
||||||
|
V.Y += (FRand()*300.f-150.f);
|
||||||
|
if( !PawnOwner.FastTrace(V,PawnOwner.Location) )
|
||||||
|
continue;
|
||||||
|
LiveHelper = Spawn(MC,,,V,R);
|
||||||
|
if( LiveHelper!=None )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( MC.Default.SoundGroupArch!=None )
|
||||||
|
MC.Default.SoundGroupArch.EntranceSound = TempSound;
|
||||||
|
}
|
||||||
|
if( LiveHelper==None )
|
||||||
|
RespawnHelperTime = 2;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Downscale.
|
||||||
|
LiveHelper.SetDrawScale(LiveHelper.DrawScale*FriendlyScalar);
|
||||||
|
LiveHelper.SetCollisionSize(LiveHelper.GetCollisionRadius()*FriendlyScalar,LiveHelper.GetCollisionHeight()*FriendlyScalar);
|
||||||
|
|
||||||
|
// Setup AI
|
||||||
|
C = Spawn(LiveHelper.ControllerClass);
|
||||||
|
if( KFAIController(C)!=None )
|
||||||
|
{
|
||||||
|
KFAIController(C).bCanTeleportCloser = false;
|
||||||
|
KFAIController(C).DefaultCommandClass = class'Ext_AICommandBasePet';
|
||||||
|
KFAIController(C).StuckCheckInterval = 100000.f; // ~27 hours
|
||||||
|
KFAIController(C).LastStuckCheckTime = WorldInfo.TimeSeconds;
|
||||||
|
}
|
||||||
|
LiveHelper.SpecialMoveHandler.SpecialMoveClasses[SM_Taunt] = class'Ext_AINoTaunt';
|
||||||
|
C.Possess(LiveHelper,false);
|
||||||
|
|
||||||
|
// Set HP.
|
||||||
|
LiveHelper.HealthMax = Clamp(LiveHelper.Default.Health,180,900)*HPScale;
|
||||||
|
LiveHelper.Health = LiveHelper.HealthMax;
|
||||||
|
LiveHelper.DamageScaling = DamageScale;
|
||||||
|
LiveHelper.SetWeakGrabCoolDown(28800.f); // Never get grabbed (for 80 hours).
|
||||||
|
LiveHelper.bWeakZedGrab = true;
|
||||||
|
LiveHelper.bCanGrabAttack = false;
|
||||||
|
|
||||||
|
// Scale by previous zed HP.
|
||||||
|
if( PrevMonster!=None )
|
||||||
|
{
|
||||||
|
LiveHelper.Health *= PrevMonsterHP;
|
||||||
|
PrevMonster = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup PRI.
|
||||||
|
if( C.PlayerReplicationInfo!=None )
|
||||||
|
C.PlayerReplicationInfo.Destroy();
|
||||||
|
PRI = Spawn(class'Ext_T_MonsterPRI',LiveHelper);
|
||||||
|
LiveHelper.PlayerReplicationInfo = PRI;
|
||||||
|
C.PlayerReplicationInfo = PRI;
|
||||||
|
PRI.PawnOwner = LiveHelper;
|
||||||
|
PRI.HealthMax = LiveHelper.HealthMax;
|
||||||
|
PRI.MonsterName = Class'KFExtendedHUD'.Static.GetNameOf(MC);
|
||||||
|
PRI.OwnerPRI = PawnOwner.PlayerReplicationInfo;
|
||||||
|
PRI.MonsterType = MC;
|
||||||
|
PRI.PlayerName = PawnOwner.PlayerReplicationInfo.PlayerName$"'s "$PRI.MonsterName;
|
||||||
|
PRI.OwnerController = PawnOwner.Controller;
|
||||||
|
if( PawnOwner.PlayerReplicationInfo.Team!=None )
|
||||||
|
PawnOwner.PlayerReplicationInfo.Team.AddToTeam(C);
|
||||||
|
PRI.Timer();
|
||||||
|
if( WorldInfo.NetMode!=NM_DedicatedServer )
|
||||||
|
PRI.NotifyOwner();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final function SetDamageScale( float Sc )
|
||||||
|
{
|
||||||
|
DamageScale = Default.DamageScale*Sc;
|
||||||
|
if( LiveHelper!=None )
|
||||||
|
LiveHelper.DamageScaling = DamageScale;
|
||||||
|
}
|
||||||
|
final function SetHealthScale( float Sc )
|
||||||
|
{
|
||||||
|
HPScale = Default.HPScale*Sc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function LoadMonsterList()
|
||||||
|
{
|
||||||
|
local int i,j;
|
||||||
|
local array<string> SA;
|
||||||
|
local class<KFPawn_Monster> C;
|
||||||
|
|
||||||
|
Default.ZedTypes.Length = class'Ext_TraitZED_Summon'.Default.ZedTypes.Length;
|
||||||
|
|
||||||
|
for( i=0; i<Default.ZedTypes.Length; ++i )
|
||||||
|
{
|
||||||
|
SA.Length = 0;
|
||||||
|
ParseStringIntoArray(class'Ext_TraitZED_Summon'.Default.ZedTypes[i],SA,",",true);
|
||||||
|
|
||||||
|
for( j=0; j<SA.Length; ++j )
|
||||||
|
{
|
||||||
|
C = class<KFPawn_Monster>(DynamicLoadObject(SA[j],Class'Class'));
|
||||||
|
if( C==None )
|
||||||
|
continue;
|
||||||
|
Default.ZedTypes[i].Zeds[Default.ZedTypes[i].Zeds.Length] = C;
|
||||||
|
}
|
||||||
|
if( Default.ZedTypes[i].Zeds.Length==0 )
|
||||||
|
Default.ZedTypes[i].Zeds[Default.ZedTypes[i].Zeds.Length] = Class'KFPawn_ZedClot_Alpha';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static final function class<KFPawn_Monster> PickRandomMonster( byte Level, bool bNotBoss )
|
||||||
|
{
|
||||||
|
local byte i;
|
||||||
|
local class<KFPawn_Monster> Res;
|
||||||
|
|
||||||
|
Level = Min(Default.ZedTypes.Length-1,Level);
|
||||||
|
for( i=0; i<5; ++i )
|
||||||
|
{
|
||||||
|
Res = Default.ZedTypes[Level].Zeds[Rand(Default.ZedTypes[Level].Zeds.Length)];
|
||||||
|
if( !bNotBoss || class<KFPawn_MonsterBoss>(Res)==None )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( bNotBoss && class<KFPawn_MonsterBoss>(Res)!=None )
|
||||||
|
Res = Class'KFPawn_ZedFleshpound';
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
RespawnHelperTime=1
|
||||||
|
HPScale=0.5
|
||||||
|
DamageScale=2
|
||||||
|
FriendlyScalar=0.65
|
||||||
|
}
|
30
ServerExt/Classes/Ext_TraitAirborne.uc
Normal file
30
ServerExt/Classes/Ext_TraitAirborne.uc
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
Class Ext_TraitAirborne extends Ext_TraitBase;
|
||||||
|
|
||||||
|
var array<float> HealRates;
|
||||||
|
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Ext_PerkFieldMedic(Perk).AirborneAgentHealRate = Default.HealRates[Level-1];
|
||||||
|
Ext_PerkFieldMedic(Perk).AirborneAgentLevel = (Level<4 ? 1 : 2);
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Ext_PerkFieldMedic(Perk).AirborneAgentLevel = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
SupportedPerk=class'Ext_PerkFieldMedic'
|
||||||
|
TraitName="Airborne Agent"
|
||||||
|
DefLevelCosts(0)=20
|
||||||
|
DefLevelCosts(1)=10
|
||||||
|
DefLevelCosts(2)=10
|
||||||
|
DefLevelCosts(3)=60
|
||||||
|
HealRates(0)=0.05
|
||||||
|
HealRates(1)=0.1
|
||||||
|
HealRates(2)=0.2
|
||||||
|
HealRates(3)=0.15
|
||||||
|
NumLevels=4
|
||||||
|
DefMinLevel=50
|
||||||
|
Description="Give extra health boost and area of heal effect for medic darts during ZED-time,|each level gives extra amount of heal boost at a rate of:|Lv 1-3: +5%, +10%, +20%|Lv 4: +15%, but works outside of ZED-time too!"
|
||||||
|
}
|
33
ServerExt/Classes/Ext_TraitAmmoReg.uc
Normal file
33
ServerExt/Classes/Ext_TraitAmmoReg.uc
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
Class Ext_TraitAmmoReg extends Ext_TraitBase;
|
||||||
|
|
||||||
|
var array<float> RegenValues;
|
||||||
|
|
||||||
|
static function ApplyEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
local Ext_T_AmmoRegHelp H;
|
||||||
|
|
||||||
|
H = Player.Spawn(class'Ext_T_AmmoRegHelp',Player);
|
||||||
|
if( H!=None )
|
||||||
|
H.RegCount = Default.RegenValues[Level-1];
|
||||||
|
}
|
||||||
|
static function CancelEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
local Ext_T_AmmoRegHelp H;
|
||||||
|
|
||||||
|
foreach Player.ChildActors(class'Ext_T_AmmoRegHelp',H)
|
||||||
|
H.Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitGroup=class'Ext_TGroupRegen'
|
||||||
|
TraitName="Ammo Regeneration"
|
||||||
|
NumLevels=3
|
||||||
|
DefLevelCosts(0)=10
|
||||||
|
DefLevelCosts(1)=20
|
||||||
|
DefLevelCosts(2)=40
|
||||||
|
Description="With this trait all your weapons ammo (not grenades) will regen every half minute at rate of:|Lvl1-3: 2%, 5%, 10% of max ammo"
|
||||||
|
RegenValues.Add(0.02)
|
||||||
|
RegenValues.Add(0.05)
|
||||||
|
RegenValues.Add(0.1)
|
||||||
|
}
|
27
ServerExt/Classes/Ext_TraitArmorReg.uc
Normal file
27
ServerExt/Classes/Ext_TraitArmorReg.uc
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Class Ext_TraitArmorReg extends Ext_TraitHealthReg;
|
||||||
|
|
||||||
|
static function ApplyEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
local Ext_T_ArmorRegHelp H;
|
||||||
|
|
||||||
|
H = Player.Spawn(class'Ext_T_ArmorRegHelp',Player);
|
||||||
|
if( H!=None )
|
||||||
|
H.RegCount = Default.RegenValues[Level-1];
|
||||||
|
}
|
||||||
|
static function CancelEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
local Ext_T_ArmorRegHelp H;
|
||||||
|
|
||||||
|
foreach Player.ChildActors(class'Ext_T_ArmorRegHelp',H)
|
||||||
|
H.Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Armor Regeneration"
|
||||||
|
Description="With this trait your armor will regen every 10 seconds at a rate of:|Lvl1-3: +7pts, +12pts, +25pts"
|
||||||
|
RegenValues.Empty()
|
||||||
|
RegenValues.Add(7)
|
||||||
|
RegenValues.Add(12)
|
||||||
|
RegenValues.Add(25)
|
||||||
|
}
|
23
ServerExt/Classes/Ext_TraitArmorRep.uc
Normal file
23
ServerExt/Classes/Ext_TraitArmorRep.uc
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Class Ext_TraitArmorRep extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Ext_PerkFieldMedic(Perk).RepairArmorRate = float(Level)*0.05f;
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Ext_PerkFieldMedic(Perk).RepairArmorRate = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
SupportedPerk=class'Ext_PerkFieldMedic'
|
||||||
|
TraitName="Armor Repair"
|
||||||
|
NumLevels=5
|
||||||
|
DefLevelCosts(0)=10
|
||||||
|
DefLevelCosts(1)=15
|
||||||
|
DefLevelCosts(2)=20
|
||||||
|
DefLevelCosts(3)=25
|
||||||
|
DefLevelCosts(4)=35
|
||||||
|
Description="With this trait you will repair armor as you heal, for each level will repair armor with a rate of:|Lv1-5: +5%, +10%, +15%, +20%, +25%"
|
||||||
|
}
|
23
ServerExt/Classes/Ext_TraitAutoFire.uc
Normal file
23
ServerExt/Classes/Ext_TraitAutoFire.uc
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Class Ext_TraitAutoFire extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function ApplyEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
local Ext_T_AutoFireHelper H;
|
||||||
|
|
||||||
|
H = Player.Spawn(class'Ext_T_AutoFireHelper',Player);
|
||||||
|
H.AssociatedPerkClass = Perk.BasePerk;
|
||||||
|
}
|
||||||
|
static function CancelEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
local Ext_T_AutoFireHelper H;
|
||||||
|
|
||||||
|
foreach Player.ChildActors(class'Ext_T_AutoFireHelper',H)
|
||||||
|
H.Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Auto-Fire weapons"
|
||||||
|
DefLevelCosts(0)=50
|
||||||
|
Description="Make all perked weapons fully automatic."
|
||||||
|
}
|
251
ServerExt/Classes/Ext_TraitBase.uc
Normal file
251
ServerExt/Classes/Ext_TraitBase.uc
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
Class Ext_TraitBase extends Object
|
||||||
|
abstract
|
||||||
|
config(ServerExt)
|
||||||
|
DependsOn(ExtWebAdmin_UI);
|
||||||
|
|
||||||
|
var array<FWebAdminConfigInfo> WebConfigs;
|
||||||
|
|
||||||
|
var() class<Ext_TGroupBase> TraitGroup; // With groups you can prevent player from buying multiple traits of same group.
|
||||||
|
var() string TraitName,Description; // UI name.
|
||||||
|
var() byte NumLevels; // Maximum number of levels.
|
||||||
|
var config array<int> LevelCosts;
|
||||||
|
var() array<int> DefLevelCosts; // Point price tag for each level.
|
||||||
|
var() class<Ext_TraitDataStore> TraitData; // Optional additional data that this trait requires for each player.
|
||||||
|
var config int MinLevel; // Minimum perk level player needs to be in order to be allowed to get this trait.
|
||||||
|
var() int DefMinLevel;
|
||||||
|
var() const byte LoadPriority; // Order of loading the trait class, if for example one trait depends on progress of another trait.
|
||||||
|
var() class<Ext_PerkBase> SupportedPerk; // Only functions on this perk.
|
||||||
|
|
||||||
|
// Config init stuff.
|
||||||
|
var config int ConfigVersion;
|
||||||
|
var const int CurrentConfigVer;
|
||||||
|
|
||||||
|
var config bool bDisabled; // This trait is currently disabled on server.
|
||||||
|
|
||||||
|
var() bool bGroupLimitToOne, // TraitGroup should limit so you can only buy one of them.
|
||||||
|
bHighPriorityDeath, // Should receive PreventDeath call before any other trait.
|
||||||
|
bPostApplyEffect; // Apply effects on second pass (relies on that another trait is activated first).
|
||||||
|
|
||||||
|
// Check if trait is enabled and usable on this perk.
|
||||||
|
static function bool IsEnabled( Ext_PerkBase Perk )
|
||||||
|
{
|
||||||
|
return !Default.bDisabled && (Default.SupportedPerk==None || ClassIsChildOf(Perk.Class,Default.SupportedPerk));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if player meets the requirements to buy this trait.
|
||||||
|
static function bool MeetsRequirements( byte Lvl, Ext_PerkBase Perk )
|
||||||
|
{
|
||||||
|
// First check level.
|
||||||
|
if( Perk.CurrentLevel<Default.MinLevel )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Then check grouping.
|
||||||
|
if( Lvl==0 && Default.TraitGroup!=None && Default.TraitGroup.Static.GroupLimited(Perk,Default.Class) )
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return UI description player will see before bying this trait.
|
||||||
|
static function string GetPerkDescription()
|
||||||
|
{
|
||||||
|
local string S;
|
||||||
|
local byte i;
|
||||||
|
|
||||||
|
for( i=0; i<Default.NumLevels; ++i )
|
||||||
|
{
|
||||||
|
if( i==0 )
|
||||||
|
S = string(GetTraitCost(i));
|
||||||
|
else S $= ", "$GetTraitCost(i);
|
||||||
|
}
|
||||||
|
S = "Max level: #{9FF781}"$Default.NumLevels$"#{DEF}|Level costs: #{F3F781}"$S$"#{DEF}";
|
||||||
|
if( Default.MinLevel>0 )
|
||||||
|
S = "Min perk level: #{FF4000}"$Default.MinLevel$"#{DEF}|"$S;
|
||||||
|
return Default.Description$"||"$S;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return tooltip description of this trait
|
||||||
|
static function string GetTooltipInfo()
|
||||||
|
{
|
||||||
|
return Default.TraitName$"|"$Default.Description;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return level specific trait prices.
|
||||||
|
static function int GetTraitCost( byte LevelNum )
|
||||||
|
{
|
||||||
|
if( Default.LevelCosts.Length>0 )
|
||||||
|
{
|
||||||
|
if( LevelNum<Default.LevelCosts.Length )
|
||||||
|
return Default.LevelCosts[LevelNum];
|
||||||
|
return Default.LevelCosts[Default.LevelCosts.Length-1];
|
||||||
|
}
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trait initialization/cleanup.
|
||||||
|
static function Ext_TraitDataStore InitializeFor( Ext_PerkBase Perk, ExtPlayerController Player )
|
||||||
|
{
|
||||||
|
local Ext_TraitDataStore T;
|
||||||
|
|
||||||
|
T = None;
|
||||||
|
if( Default.TraitData!=None )
|
||||||
|
{
|
||||||
|
T = Player.Spawn(Default.TraitData,Player);
|
||||||
|
T.Perk = Perk;
|
||||||
|
T.PlayerOwner = Player;
|
||||||
|
T.TraitClass = Default.Class;
|
||||||
|
}
|
||||||
|
return T;
|
||||||
|
}
|
||||||
|
static function CleanupTrait( ExtPlayerController Player, Ext_PerkBase Perk, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
if( Data!=None )
|
||||||
|
Data.Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when trait is first activated/deactivated (might even have a dead pawn).
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data );
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data );
|
||||||
|
|
||||||
|
// Called everytime player spawns in on the game (cancel effect is called on level up/level reset/perk change).
|
||||||
|
static function ApplyEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data );
|
||||||
|
static function CancelEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data );
|
||||||
|
|
||||||
|
// Owner died with this trait active.
|
||||||
|
static function PlayerDied( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data );
|
||||||
|
|
||||||
|
// Prevent death.
|
||||||
|
static function bool PreventDeath( KFPawn_Human Player, Controller Instigator, Class<DamageType> DamType, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data );
|
||||||
|
|
||||||
|
// Give/modify default inventory.
|
||||||
|
static function AddDefaultInventory( KFPawn Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data );
|
||||||
|
|
||||||
|
// Data that server should replicate to client.
|
||||||
|
static final function string IntToStr( int Value, optional byte MaxVal ) // Helper function to put integer into one character of string.
|
||||||
|
{
|
||||||
|
switch( MaxVal )
|
||||||
|
{
|
||||||
|
case 0: // 0-65535
|
||||||
|
return Chr(Max(Value,0)+1);
|
||||||
|
case 1: // 0-1073741823
|
||||||
|
return Chr((Value & 32767)+1) $ Chr(((Value >> 15) & 32767)+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static final function string InlineString( string Str ) // Helper function to append a string line to a text using a length char in front.
|
||||||
|
{
|
||||||
|
return IntToStr(Len(Str))$Str;
|
||||||
|
}
|
||||||
|
static final function int StrToInt( out string Value, optional byte MaxVal ) // Reverse.
|
||||||
|
{
|
||||||
|
local int Res;
|
||||||
|
|
||||||
|
switch( MaxVal )
|
||||||
|
{
|
||||||
|
case 0: // 0-65535
|
||||||
|
Res = Asc(Left(Value,1))-1;
|
||||||
|
Value = Mid(Value,1);
|
||||||
|
break;
|
||||||
|
case 1: // 0-1073741823
|
||||||
|
Res =(Asc(Mid(Value,0,1))-1) | ((Asc(Mid(Value,1,1)) << 15)-1);
|
||||||
|
Value = Mid(Value,2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
static final function string GetInlineStr( out string S ) // Reverse.
|
||||||
|
{
|
||||||
|
local int l;
|
||||||
|
local string Res;
|
||||||
|
|
||||||
|
l = StrToInt(S);
|
||||||
|
Res = Left(S,l);
|
||||||
|
S = Mid(S,l);
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function string GetRepData()
|
||||||
|
{
|
||||||
|
local string S;
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
S = IntToStr(Default.MinLevel)$IntToStr(Default.LevelCosts.Length);
|
||||||
|
for( i=0; i<Default.LevelCosts.Length; ++i )
|
||||||
|
S $= IntToStr(Default.LevelCosts[i]);
|
||||||
|
return S;
|
||||||
|
}
|
||||||
|
static function string ClientSetRepData( string S )
|
||||||
|
{
|
||||||
|
local int i;
|
||||||
|
|
||||||
|
Default.MinLevel = StrToInt(S);
|
||||||
|
Default.LevelCosts.Length = StrToInt(S);
|
||||||
|
for( i=0; i<Default.LevelCosts.Length; ++i )
|
||||||
|
Default.LevelCosts[i] = StrToInt(S);
|
||||||
|
return S;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure initialization.
|
||||||
|
static function CheckConfig()
|
||||||
|
{
|
||||||
|
if( Default.ConfigVersion!=Default.CurrentConfigVer )
|
||||||
|
{
|
||||||
|
UpdateConfigs(Default.ConfigVersion);
|
||||||
|
Default.ConfigVersion = Default.CurrentConfigVer;
|
||||||
|
StaticSaveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static function UpdateConfigs( int OldVer )
|
||||||
|
{
|
||||||
|
if( OldVer==0 )
|
||||||
|
{
|
||||||
|
Default.LevelCosts = Default.DefLevelCosts;
|
||||||
|
Default.MinLevel = Default.DefMinLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebAdmin UI
|
||||||
|
static function InitWebAdmin( ExtWebAdmin_UI UI )
|
||||||
|
{
|
||||||
|
UI.AddSettingsPage("Trait "$Default.TraitName,Default.Class,Default.WebConfigs,GetValue,ApplyValue);
|
||||||
|
}
|
||||||
|
static function string GetValue( name PropName, int ElementIndex )
|
||||||
|
{
|
||||||
|
switch( PropName )
|
||||||
|
{
|
||||||
|
case 'MinLevel':
|
||||||
|
return string(Default.MinLevel);
|
||||||
|
case 'LevelCosts':
|
||||||
|
return (ElementIndex==-1 ? string(Default.LevelCosts.Length) : string(Default.LevelCosts[ElementIndex]));
|
||||||
|
case 'bDisabled':
|
||||||
|
return string(Default.bDisabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static function ApplyValue( name PropName, int ElementIndex, string Value )
|
||||||
|
{
|
||||||
|
switch( PropName )
|
||||||
|
{
|
||||||
|
case 'MinLevel':
|
||||||
|
Default.MinLevel = int(Value); break;
|
||||||
|
case 'LevelCosts':
|
||||||
|
Default.LevelCosts.Length = Default.DefLevelCosts.Length;
|
||||||
|
if( Value!="#DELETE" && ElementIndex<Default.LevelCosts.Length )
|
||||||
|
Default.LevelCosts[ElementIndex] = int(Value);
|
||||||
|
break;
|
||||||
|
case 'bDisabled':
|
||||||
|
Default.bDisabled = bool(Value); break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StaticSaveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
CurrentConfigVer=1
|
||||||
|
DefLevelCosts.Add(5)
|
||||||
|
NumLevels=1
|
||||||
|
DefMinLevel=0
|
||||||
|
|
||||||
|
WebConfigs.Add((PropType=1,PropName="bDisabled",UIName="Disabled",UIDesc="Disable this trait (hides from UI and makes it unusable)!"))
|
||||||
|
WebConfigs.Add((PropType=0,PropName="MinLevel",UIName="Minimum Level",UIDesc="Minimum Level required for this trait"))
|
||||||
|
WebConfigs.Add((PropType=0,PropName="LevelCosts",UIName="Level Costs",UIDesc="EXP cost for each trait level (array length is a constant)!",NumElements=-1))
|
||||||
|
}
|
18
ServerExt/Classes/Ext_TraitBoomWeld.uc
Normal file
18
ServerExt/Classes/Ext_TraitBoomWeld.uc
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Class Ext_TraitBoomWeld extends Ext_TraitBase
|
||||||
|
abstract;
|
||||||
|
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.bExplosiveWeld = true;
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.bExplosiveWeld = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Explosive Weld"
|
||||||
|
DefLevelCosts(0)=30
|
||||||
|
Description="Cases welded doors explode when broken by zeds. The more you weld one door, the bigger explosion."
|
||||||
|
}
|
20
ServerExt/Classes/Ext_TraitBunnyHop.uc
Normal file
20
ServerExt/Classes/Ext_TraitBunnyHop.uc
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
Class Ext_TraitBunnyHop extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function ApplyEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
if( ExtHumanPawn(Player)!=None )
|
||||||
|
ExtHumanPawn(Player).bHasBunnyHop = true;
|
||||||
|
}
|
||||||
|
static function CancelEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
if( ExtHumanPawn(Player)!=None )
|
||||||
|
ExtHumanPawn(Player).bHasBunnyHop = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Bunny Hop"
|
||||||
|
DefLevelCosts(0)=50
|
||||||
|
DefMinLevel=100
|
||||||
|
Description="Enable player to do bunny hopping. It means the more you continiously make successful jumps while moving forward you will keep accelerating in speed."
|
||||||
|
}
|
37
ServerExt/Classes/Ext_TraitCarryCap.uc
Normal file
37
ServerExt/Classes/Ext_TraitCarryCap.uc
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
Class Ext_TraitCarryCap extends Ext_TraitBase;
|
||||||
|
|
||||||
|
var array<byte> CarryAdds;
|
||||||
|
|
||||||
|
static function ApplyEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
local KFInventoryManager M;
|
||||||
|
|
||||||
|
M = KFInventoryManager(Player.InvManager);
|
||||||
|
if( M!=None )
|
||||||
|
M.MaxCarryBlocks = M.Default.MaxCarryBlocks+Default.CarryAdds[Level-1];
|
||||||
|
}
|
||||||
|
static function CancelEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
local KFInventoryManager M;
|
||||||
|
|
||||||
|
M = KFInventoryManager(Player.InvManager);
|
||||||
|
if( M!=None )
|
||||||
|
M.MaxCarryBlocks = M.Default.MaxCarryBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Carry Capacity"
|
||||||
|
NumLevels=5
|
||||||
|
DefLevelCosts(0)=10
|
||||||
|
DefLevelCosts(1)=15
|
||||||
|
DefLevelCosts(2)=20
|
||||||
|
DefLevelCosts(3)=25
|
||||||
|
DefLevelCosts(4)=50
|
||||||
|
Description="With this trait you can carry more.|Lv1-5: +2,+4,+6,+8,+15 slots"
|
||||||
|
CarryAdds.Add(2)
|
||||||
|
CarryAdds.Add(4)
|
||||||
|
CarryAdds.Add(6)
|
||||||
|
CarryAdds.Add(8)
|
||||||
|
CarryAdds.Add(15)
|
||||||
|
}
|
17
ServerExt/Classes/Ext_TraitContactNade.uc
Normal file
17
ServerExt/Classes/Ext_TraitContactNade.uc
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Class Ext_TraitContactNade extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.bExplodeOnContact = true;
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.bExplodeOnContact = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Explode on Contact"
|
||||||
|
DefLevelCosts(0)=25
|
||||||
|
Description="Make dynamites explode on contact with the ZED."
|
||||||
|
}
|
11
ServerExt/Classes/Ext_TraitDataStore.uc
Normal file
11
ServerExt/Classes/Ext_TraitDataStore.uc
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Optional additional player specific data for a trait.
|
||||||
|
Class Ext_TraitDataStore extends Info
|
||||||
|
abstract;
|
||||||
|
|
||||||
|
var Ext_PerkBase Perk;
|
||||||
|
var ExtPlayerController PlayerOwner;
|
||||||
|
var class<Ext_TraitBase> TraitClass;
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
}
|
18
ServerExt/Classes/Ext_TraitDireReload.uc
Normal file
18
ServerExt/Classes/Ext_TraitDireReload.uc
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Class Ext_TraitDireReload extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Ext_PerkSharpshooter(Perk).bHasDireReload = true;
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Ext_PerkSharpshooter(Perk).bHasDireReload = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
SupportedPerk=class'Ext_PerkSharpshooter'
|
||||||
|
TraitName="Dire reloader"
|
||||||
|
DefLevelCosts(0)=35
|
||||||
|
Description="This trait will make you reload much faster when you have less then 40 health."
|
||||||
|
}
|
29
ServerExt/Classes/Ext_TraitDuracell.uc
Normal file
29
ServerExt/Classes/Ext_TraitDuracell.uc
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
Class Ext_TraitDuracell extends Ext_TraitBase;
|
||||||
|
|
||||||
|
var array<float> BatteryCharges;
|
||||||
|
|
||||||
|
static function ApplyEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
if( ExtHumanPawn(Player)!=None )
|
||||||
|
ExtHumanPawn(Player).SetBatteryRate(Default.BatteryCharges[Level-1]);
|
||||||
|
}
|
||||||
|
static function CancelEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
if( ExtHumanPawn(Player)!=None )
|
||||||
|
ExtHumanPawn(Player).SetBatteryRate(1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Duracell Batteries"
|
||||||
|
NumLevels=4
|
||||||
|
DefLevelCosts(0)=5
|
||||||
|
DefLevelCosts(1)=10
|
||||||
|
DefLevelCosts(2)=20
|
||||||
|
DefLevelCosts(3)=25
|
||||||
|
Description="With this trait your flashlight batteries becomes extra durable.|Lv1-4: +30,+100,+300,+1000% lifetime"
|
||||||
|
BatteryCharges.Add(0.77)
|
||||||
|
BatteryCharges.Add(0.5)
|
||||||
|
BatteryCharges.Add(0.333)
|
||||||
|
BatteryCharges.Add(0.1)
|
||||||
|
}
|
18
ServerExt/Classes/Ext_TraitEliteReload.uc
Normal file
18
ServerExt/Classes/Ext_TraitEliteReload.uc
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Class Ext_TraitEliteReload extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function ApplyEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.bTacticalReload = true;
|
||||||
|
}
|
||||||
|
static function CancelEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.bTacticalReload = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Tactical Reload"
|
||||||
|
DefLevelCosts(0)=50
|
||||||
|
Description="With this trait you will have extra speedy tactical reload moves for your perked weapons."
|
||||||
|
DefMinLevel=50
|
||||||
|
}
|
21
ServerExt/Classes/Ext_TraitEnemyHP.uc
Normal file
21
ServerExt/Classes/Ext_TraitEnemyHP.uc
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
Class Ext_TraitEnemyHP extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.EnemyHealthRange = Level;
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.EnemyHealthRange = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Enemy Health Bar"
|
||||||
|
NumLevels=4
|
||||||
|
DefLevelCosts(0)=25
|
||||||
|
DefLevelCosts(1)=15
|
||||||
|
DefLevelCosts(2)=20
|
||||||
|
DefLevelCosts(3)=30
|
||||||
|
Description="This trait lets you see enemy health bars. The distance is increased by every level in:|Lv1-4: 5m, 7m, 10m, 16m"
|
||||||
|
}
|
18
ServerExt/Classes/Ext_TraitFanfire.uc
Normal file
18
ServerExt/Classes/Ext_TraitFanfire.uc
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Class Ext_TraitFanfire extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Ext_PerkGunslinger(Perk).bHasFanfire = true;
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Ext_PerkGunslinger(Perk).bHasFanfire = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
SupportedPerk=class'Ext_PerkGunslinger'
|
||||||
|
TraitName="ZED TIME - Fanfire"
|
||||||
|
DefLevelCosts(0)=30
|
||||||
|
Description="Make perked weapons fire at normal firerate during ZED-time."
|
||||||
|
}
|
17
ServerExt/Classes/Ext_TraitFireExplode.uc
Normal file
17
ServerExt/Classes/Ext_TraitFireExplode.uc
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Class Ext_TraitFireExplode extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.bFireExplode = true;
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.bFireExplode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Fire Explosion"
|
||||||
|
DefLevelCosts(0)=50
|
||||||
|
Description="Make zombies sometimes explode when burned to death."
|
||||||
|
}
|
17
ServerExt/Classes/Ext_TraitFireRange.uc
Normal file
17
ServerExt/Classes/Ext_TraitFireRange.uc
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Class Ext_TraitFireRange extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
KFPlayerReplicationInfo(Perk.PlayerOwner.PlayerReplicationInfo).bExtraFireRange = true;
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
KFPlayerReplicationInfo(Perk.PlayerOwner.PlayerReplicationInfo).bExtraFireRange = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Extra Fire Range"
|
||||||
|
DefLevelCosts(0)=35
|
||||||
|
Description="Add some additional fire range to flamethrowers."
|
||||||
|
}
|
34
ServerExt/Classes/Ext_TraitGhost.uc
Normal file
34
ServerExt/Classes/Ext_TraitGhost.uc
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
Class Ext_TraitGhost extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function bool PreventDeath( KFPawn_Human Player, Controller Instigator, Class<DamageType> DamType, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
local Controller C;
|
||||||
|
|
||||||
|
if( (Instigator==None || Instigator==Player.Controller) && DamType==Class'DmgType_Suicided' )
|
||||||
|
return false; // Allow normal suicide to go ahead.
|
||||||
|
|
||||||
|
if( Ext_T_GhostHelper(Data).CanResPlayer(Player,Level) )
|
||||||
|
{
|
||||||
|
// Abort current special move
|
||||||
|
if( Player.IsDoingSpecialMove() )
|
||||||
|
Player.SpecialMoveHandler.EndSpecialMove();
|
||||||
|
|
||||||
|
// Notify AI to stop hunting me.
|
||||||
|
foreach Player.WorldInfo.AllControllers(class'Controller',C)
|
||||||
|
C.NotifyKilled(Instigator,Player.Controller,Player,DamType);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
bHighPriorityDeath=true
|
||||||
|
NumLevels=2
|
||||||
|
TraitData=class'Ext_T_GhostHelper'
|
||||||
|
TraitName="Redemption"
|
||||||
|
DefLevelCosts(0)=30
|
||||||
|
DefLevelCosts(1)=30
|
||||||
|
DefMinLevel=30
|
||||||
|
Description="With this trait you will turn into ghost when you die and redeem at another spot in the map.|Level 1: Works 50 % of the time, but never again until you respawned after death.|Level 2: Always works, and it lets you redeem again after 3 minutes"
|
||||||
|
}
|
29
ServerExt/Classes/Ext_TraitGrenadeCap.uc
Normal file
29
ServerExt/Classes/Ext_TraitGrenadeCap.uc
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
Class Ext_TraitGrenadeCap extends Ext_TraitCarryCap;
|
||||||
|
|
||||||
|
static function ApplyEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data );
|
||||||
|
static function CancelEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data );
|
||||||
|
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.PerkManager.SetGrenadeCap(Default.CarryAdds[Level-1]);
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.PerkManager.SetGrenadeCap(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Grenade Capacity"
|
||||||
|
DefLevelCosts(0)=40
|
||||||
|
DefLevelCosts(1)=55
|
||||||
|
DefLevelCosts(2)=70
|
||||||
|
DefLevelCosts(3)=90
|
||||||
|
DefLevelCosts(4)=150
|
||||||
|
Description="With this trait you can carry more grenades.|Lv1-5: +1,+2,+3,+5,+8 grenades"
|
||||||
|
CarryAdds(0)=1
|
||||||
|
CarryAdds(1)=2
|
||||||
|
CarryAdds(2)=3
|
||||||
|
CarryAdds(3)=5
|
||||||
|
CarryAdds(4)=8
|
||||||
|
}
|
19
ServerExt/Classes/Ext_TraitGrenadeSUpg.uc
Normal file
19
ServerExt/Classes/Ext_TraitGrenadeSUpg.uc
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Class Ext_TraitGrenadeSUpg extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
if( Level==1 )
|
||||||
|
Perk.GrenadeClass = Perk.SuperGrenade;
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.GrenadeClass = Perk.Default.GrenadeClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Grenade Upgrade"
|
||||||
|
DefLevelCosts(0)=50
|
||||||
|
Description="With this upgrade you will upgrade to your perk specific grenades.|Level 1: SUPER grenade"
|
||||||
|
DefMinLevel=50
|
||||||
|
}
|
28
ServerExt/Classes/Ext_TraitGrenadeUpg.uc
Normal file
28
ServerExt/Classes/Ext_TraitGrenadeUpg.uc
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
Class Ext_TraitGrenadeUpg extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function bool MeetsRequirements( byte Lvl, Ext_PerkBase Perk )
|
||||||
|
{
|
||||||
|
if( Lvl>=1 && Perk.CurrentLevel<50 )
|
||||||
|
return false;
|
||||||
|
return Super.MeetsRequirements(Lvl,Perk);
|
||||||
|
}
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
if( Level==1 )
|
||||||
|
Perk.GrenadeClass = Perk.PerkGrenade;
|
||||||
|
else if( Level==2 )
|
||||||
|
Perk.GrenadeClass = Perk.SuperGrenade;
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.GrenadeClass = Perk.Default.GrenadeClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Grenade Upgrade"
|
||||||
|
NumLevels=2
|
||||||
|
DefLevelCosts(0)=5
|
||||||
|
DefLevelCosts(1)=50
|
||||||
|
Description="With this upgrade you will upgrade to your perk specific grenades.|Level 1: Normal perk grenade|Level 2: Perk SUPER grenade (REQUIRES perk level 50 to buy)!"
|
||||||
|
}
|
33
ServerExt/Classes/Ext_TraitHealthReg.uc
Normal file
33
ServerExt/Classes/Ext_TraitHealthReg.uc
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
Class Ext_TraitHealthReg extends Ext_TraitBase;
|
||||||
|
|
||||||
|
var array<byte> RegenValues;
|
||||||
|
|
||||||
|
static function ApplyEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
local Ext_T_HealthRegHelp H;
|
||||||
|
|
||||||
|
H = Player.Spawn(class'Ext_T_HealthRegHelp',Player);
|
||||||
|
if( H!=None )
|
||||||
|
H.RegCount = Default.RegenValues[Level-1];
|
||||||
|
}
|
||||||
|
static function CancelEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
local Ext_T_HealthRegHelp H;
|
||||||
|
|
||||||
|
foreach Player.ChildActors(class'Ext_T_HealthRegHelp',H)
|
||||||
|
H.Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitGroup=class'Ext_TGroupRegen'
|
||||||
|
TraitName="Health Regeneration"
|
||||||
|
NumLevels=3
|
||||||
|
DefLevelCosts(0)=10
|
||||||
|
DefLevelCosts(1)=20
|
||||||
|
DefLevelCosts(2)=40
|
||||||
|
Description="With this trait your health will regen every 10 seconds at a rate of:|Lvl1-3: +5HP, +10HP, +20HP"
|
||||||
|
RegenValues.Add(5)
|
||||||
|
RegenValues.Add(10)
|
||||||
|
RegenValues.Add(20)
|
||||||
|
}
|
21
ServerExt/Classes/Ext_TraitHeavyArmor.uc
Normal file
21
ServerExt/Classes/Ext_TraitHeavyArmor.uc
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
Class Ext_TraitHeavyArmor extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.bHeavyArmor = true;
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.bHeavyArmor = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Heavy Armor"
|
||||||
|
NumLevels=3
|
||||||
|
DefLevelCosts(0)=50
|
||||||
|
DefLevelCosts(1)=20
|
||||||
|
DefLevelCosts(2)=60
|
||||||
|
DefMinLevel=50
|
||||||
|
Description="Makes your armor stop all damage (except for Siren scream and fall damage).|Level 2 makes you in addition spawn with 50 points of armor.|Level 3 makes you spawn with full armor."
|
||||||
|
}
|
29
ServerExt/Classes/Ext_TraitKnockback.uc
Normal file
29
ServerExt/Classes/Ext_TraitKnockback.uc
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
Class Ext_TraitKnockback extends Ext_TraitRagdoll;
|
||||||
|
|
||||||
|
static function ApplyEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
if( ExtHumanPawn(Player)!=None )
|
||||||
|
ExtHumanPawn(Player).KnockbackResist = Default.ChanceValues[Level-1];
|
||||||
|
}
|
||||||
|
static function CancelEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
if( ExtHumanPawn(Player)!=None )
|
||||||
|
ExtHumanPawn(Player).KnockbackResist = 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Knockback Resistance"
|
||||||
|
NumLevels=4
|
||||||
|
DefLevelCosts(0)=30
|
||||||
|
DefLevelCosts(1)=30
|
||||||
|
DefLevelCosts(2)=40
|
||||||
|
DefLevelCosts(3)=60
|
||||||
|
DefMinLevel=70
|
||||||
|
Description="Reduce the amount of knockback zeds do to you in a rate of:|Lvl1-4: -20%, -50%, -70%, -90%"
|
||||||
|
|
||||||
|
ChanceValues(0)=0.8
|
||||||
|
ChanceValues(1)=0.5
|
||||||
|
ChanceValues(2)=0.3
|
||||||
|
ChanceValues(3)=0.1
|
||||||
|
}
|
14
ServerExt/Classes/Ext_TraitMedicPistol.uc
Normal file
14
ServerExt/Classes/Ext_TraitMedicPistol.uc
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Class Ext_TraitMedicPistol extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function AddDefaultInventory( KFPawn Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Player.DefaultInventory.RemoveItem(class'KFWeap_Pistol_9mm');
|
||||||
|
Player.DefaultInventory.AddItem(class'KFWeap_Pistol_Medic');
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Medic Pistol"
|
||||||
|
DefLevelCosts(0)=20
|
||||||
|
Description="Spawn with a medic pistol instead of standard 9mm."
|
||||||
|
}
|
17
ServerExt/Classes/Ext_TraitNapalm.uc
Normal file
17
ServerExt/Classes/Ext_TraitNapalm.uc
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Class Ext_TraitNapalm extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.bNapalmFire = true;
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.bNapalmFire = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Napalm"
|
||||||
|
DefLevelCosts(0)=35
|
||||||
|
Description="Make zombies lit each other on fire."
|
||||||
|
}
|
18
ServerExt/Classes/Ext_TraitNightvision.uc
Normal file
18
ServerExt/Classes/Ext_TraitNightvision.uc
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Class Ext_TraitNightvision extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.bHasNightVision = true;
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.bHasNightVision = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Nightvision"
|
||||||
|
NumLevels=1
|
||||||
|
DefLevelCosts(0)=25
|
||||||
|
Description="Spawn with nightvision goggles."
|
||||||
|
}
|
30
ServerExt/Classes/Ext_TraitRackEmUp.uc
Normal file
30
ServerExt/Classes/Ext_TraitRackEmUp.uc
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
Class Ext_TraitRackEmUp extends Ext_TraitBase;
|
||||||
|
|
||||||
|
var array<byte> ComboSize;
|
||||||
|
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Ext_PerkRhythmPerkBase(Perk).SetMaxRhythm(Default.ComboSize[Level-1]);
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Ext_PerkRhythmPerkBase(Perk).ResetRhythm();
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
SupportedPerk=class'Ext_PerkRhythmPerkBase'
|
||||||
|
TraitName="Rack 'em up"
|
||||||
|
DefLevelCosts(0)=10
|
||||||
|
DefLevelCosts(1)=15
|
||||||
|
DefLevelCosts(2)=20
|
||||||
|
DefLevelCosts(3)=30
|
||||||
|
DefLevelCosts(4)=50
|
||||||
|
ComboSize.Add(4)
|
||||||
|
ComboSize.Add(8)
|
||||||
|
ComboSize.Add(12)
|
||||||
|
ComboSize.Add(16)
|
||||||
|
ComboSize.Add(28)
|
||||||
|
NumLevels=5
|
||||||
|
Description="Deals more damage to each consequtive headshot done to zeds by +7.5%.|For each level you can make a bigger combo and deal more damage in a rate of:|Lv1-5: +30%, +60%, +90%, +120%, +210%"
|
||||||
|
}
|
29
ServerExt/Classes/Ext_TraitRagdoll.uc
Normal file
29
ServerExt/Classes/Ext_TraitRagdoll.uc
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
Class Ext_TraitRagdoll extends Ext_TraitBase;
|
||||||
|
|
||||||
|
var float ChanceValues[4];
|
||||||
|
|
||||||
|
static function ApplyEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
if( ExtHumanPawn(Player)!=None )
|
||||||
|
ExtHumanPawn(Player).NoRagdollChance = Default.ChanceValues[Level-1];
|
||||||
|
}
|
||||||
|
static function CancelEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
if( ExtHumanPawn(Player)!=None )
|
||||||
|
ExtHumanPawn(Player).NoRagdollChance = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Knockout Resistance"
|
||||||
|
NumLevels=3
|
||||||
|
DefLevelCosts(0)=30
|
||||||
|
DefLevelCosts(1)=30
|
||||||
|
DefLevelCosts(2)=40
|
||||||
|
DefMinLevel=100
|
||||||
|
Description="Prevent you from being ragdolled. For each level you lower the chance of being knocked out by:|Lvl1-3: 20%, 50%, 80%"
|
||||||
|
|
||||||
|
ChanceValues(0)=0.2
|
||||||
|
ChanceValues(1)=0.5
|
||||||
|
ChanceValues(2)=0.8
|
||||||
|
}
|
18
ServerExt/Classes/Ext_TraitRanger.uc
Normal file
18
ServerExt/Classes/Ext_TraitRanger.uc
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Class Ext_TraitRanger extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Ext_PerkSharpshooter(Perk).ZEDTimeStunPower = 4.f;
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Ext_PerkSharpshooter(Perk).ZEDTimeStunPower = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
SupportedPerk=class'Ext_PerkSharpshooter'
|
||||||
|
TraitName="ZED TIME - Ranger"
|
||||||
|
DefLevelCosts(0)=40
|
||||||
|
Description="This will make you effectively stun enemies with headshots during ZED-time."
|
||||||
|
}
|
23
ServerExt/Classes/Ext_TraitRetali.uc
Normal file
23
ServerExt/Classes/Ext_TraitRetali.uc
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Class Ext_TraitRetali extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function bool PreventDeath( KFPawn_Human Player, Controller Instigator, Class<DamageType> DamType, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
local ExtProj_SUPERGrenade P;
|
||||||
|
|
||||||
|
P = Player.Spawn(class'ExtProj_SUPERGrenade');
|
||||||
|
if( P!=None )
|
||||||
|
{
|
||||||
|
P.bExplodeOnContact = false; // Nope!
|
||||||
|
P.InstigatorController = Player.Controller;
|
||||||
|
P.ClusterNades = class'ExtProj_CrackerGrenade';
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Retaliation"
|
||||||
|
DefLevelCosts(0)=50
|
||||||
|
DefMinLevel=40
|
||||||
|
Description="End your life with a BOOM!"
|
||||||
|
}
|
27
ServerExt/Classes/Ext_TraitSWATEnforcer.uc
Normal file
27
ServerExt/Classes/Ext_TraitSWATEnforcer.uc
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Class Ext_TraitSWATEnforcer extends Ext_TraitBase;
|
||||||
|
|
||||||
|
static function ApplyEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
if( ExtHumanPawn(Player)!=None )
|
||||||
|
ExtHumanPawn(Player).bMovesFastInZedTime = true;
|
||||||
|
}
|
||||||
|
static function CancelEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
if( ExtHumanPawn(Player)!=None )
|
||||||
|
ExtHumanPawn(Player).bMovesFastInZedTime = false;
|
||||||
|
}
|
||||||
|
static function TraitActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.bHasSWATEnforcer = true;
|
||||||
|
}
|
||||||
|
static function TraitDeActivate( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Perk.bHasSWATEnforcer = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="ZED TIME - SWAT Enforcer"
|
||||||
|
DefLevelCosts(0)=50
|
||||||
|
Description="This trait makes you move at normal speed and allows you to knock down zeds by bumping into them during ZED-time."
|
||||||
|
}
|
31
ServerExt/Classes/Ext_TraitSpartan.uc
Normal file
31
ServerExt/Classes/Ext_TraitSpartan.uc
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
Class Ext_TraitSpartan extends Ext_TraitBase;
|
||||||
|
|
||||||
|
var array<float> AtkRates;
|
||||||
|
|
||||||
|
static function ApplyEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
if( ExtHumanPawn(Player)!=None )
|
||||||
|
ExtHumanPawn(Player).bMovesFastInZedTime = true;
|
||||||
|
Ext_PerkBerserker(Perk).ZedTimeMeleeAtkRate = 1.f/Default.AtkRates[Level-1];
|
||||||
|
}
|
||||||
|
static function CancelEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
if( ExtHumanPawn(Player)!=None )
|
||||||
|
ExtHumanPawn(Player).bMovesFastInZedTime = false;
|
||||||
|
Ext_PerkBerserker(Perk).ZedTimeMeleeAtkRate = 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
SupportedPerk=class'Ext_PerkBerserker'
|
||||||
|
TraitName="ZED TIME - Spartan!"
|
||||||
|
NumLevels=3
|
||||||
|
DefLevelCosts(0)=50
|
||||||
|
DefLevelCosts(1)=40
|
||||||
|
DefLevelCosts(2)=80
|
||||||
|
Description="This trait lets you move at normal speed and attack faster in ZED-time.|Lv1-3: +50,+120,+300% atk speed"
|
||||||
|
AtkRates.Add(1.5)
|
||||||
|
AtkRates.Add(2.2)
|
||||||
|
AtkRates.Add(4.0)
|
||||||
|
DefMinLevel=100
|
||||||
|
}
|
26
ServerExt/Classes/Ext_TraitSupply.uc
Normal file
26
ServerExt/Classes/Ext_TraitSupply.uc
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
Class Ext_TraitSupply extends Ext_TraitBase;
|
||||||
|
|
||||||
|
var() Texture2D SupplyIcon;
|
||||||
|
|
||||||
|
static function ApplyEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Ext_TraitSupplyData(Data).SpawnSupplier(Player);
|
||||||
|
}
|
||||||
|
static function CancelEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Ext_TraitSupplyData(Data).RemoveSupplier();
|
||||||
|
}
|
||||||
|
static function PlayerDied( Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Ext_TraitSupplyData(Data).RemoveSupplier();
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Ammunition Supply"
|
||||||
|
DefLevelCosts(0)=50
|
||||||
|
Description="With this trait you can supply ammunition for your team mates. For each use you will receive a little bit of XP points."
|
||||||
|
TraitData=class'Ext_TraitSupplyData'
|
||||||
|
|
||||||
|
SupplyIcon=Texture2D'UI_World_TEX.Support_Supplier_HUD'
|
||||||
|
}
|
30
ServerExt/Classes/Ext_TraitSupplyData.uc
Normal file
30
ServerExt/Classes/Ext_TraitSupplyData.uc
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
Class Ext_TraitSupplyData extends Ext_TraitDataStore;
|
||||||
|
|
||||||
|
var Ext_T_SupplierInteract SupplyInteraction;
|
||||||
|
|
||||||
|
final function SpawnSupplier( KFPawn_Human H, optional bool bGrenades )
|
||||||
|
{
|
||||||
|
if( SupplyInteraction!=None )
|
||||||
|
SupplyInteraction.Destroy();
|
||||||
|
|
||||||
|
SupplyInteraction = Spawn( class'Ext_T_SupplierInteract', H,, H.Location, H.Rotation,, true );
|
||||||
|
SupplyInteraction.SetBase( H );
|
||||||
|
SupplyInteraction.PlayerOwner = H;
|
||||||
|
SupplyInteraction.PerkOwner = Perk;
|
||||||
|
SupplyInteraction.bGrenades = bGrenades;
|
||||||
|
|
||||||
|
if( PlayerOwner!=None && ExtPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo)!=None )
|
||||||
|
ExtPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).HasSupplier = class<Ext_TraitSupply>(TraitClass);
|
||||||
|
}
|
||||||
|
final function RemoveSupplier()
|
||||||
|
{
|
||||||
|
if( SupplyInteraction!=None )
|
||||||
|
SupplyInteraction.Destroy();
|
||||||
|
|
||||||
|
if( PlayerOwner!=None && ExtPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo)!=None )
|
||||||
|
ExtPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).HasSupplier = None;
|
||||||
|
}
|
||||||
|
function Destroyed()
|
||||||
|
{
|
||||||
|
RemoveSupplier();
|
||||||
|
}
|
14
ServerExt/Classes/Ext_TraitSupplyGren.uc
Normal file
14
ServerExt/Classes/Ext_TraitSupplyGren.uc
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Class Ext_TraitSupplyGren extends Ext_TraitSupply;
|
||||||
|
|
||||||
|
static function ApplyEffectOn( KFPawn_Human Player, Ext_PerkBase Perk, byte Level, optional Ext_TraitDataStore Data )
|
||||||
|
{
|
||||||
|
Ext_TraitSupplyData(Data).SpawnSupplier(Player,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultproperties
|
||||||
|
{
|
||||||
|
TraitName="Grenade Supply"
|
||||||
|
Description="With this trait you can supply grenades for your team mates. For each use you will receive a little bit of XP points."
|
||||||
|
|
||||||
|
SupplyIcon=Texture2D'UI_World_TEX.Demolitionist_Supplier_HUD'
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user