Class ExtPlayerReplicationInfo extends KFPlayerReplicationInfo; struct FCustomCharEntry { var bool bLock; var KFCharacterInfo_Human Char; var ObjectReferencer Ref; }; struct FMyCustomChar // Now without constant. { var int CharacterIndex,HeadMeshIndex,HeadSkinIndex,BodyMeshIndex,BodySkinIndex,AttachmentMeshIndices[`MAX_COSMETIC_ATTACHMENTS],AttachmentSkinIndices[`MAX_COSMETIC_ATTACHMENTS]; structdefaultproperties { AttachmentMeshIndices[0]=`CLEARED_ATTACHMENT_INDEX AttachmentMeshIndices[1]=`CLEARED_ATTACHMENT_INDEX AttachmentMeshIndices[2]=`CLEARED_ATTACHMENT_INDEX } }; // For custom trader inventory. struct FCustomTraderItem { var class WeaponDef; var class WeaponClass; }; var bool bIsMuted,bInitialPT,bIsDev,bHiddenUser,bClientUseCustom,bClientFirstChar,bClientCharListDone,bClientInitChars; var int RespawnCounter; var byte AdminType; var class ECurrentPerk; var Ext_PerkBase FCurrentPerk; 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 CustomCharList; var repnotify FMyCustomChar CustomCharacter; var transient array SaveDataObjects; var transient ExtPlayerReplicationInfo LocalOwnerPRI; // Local playercontroller owner PRI // Custom trader inventory var KFGFxObject_TraderItems CustomList; var array CustomItems; // Supplier data: var transient struct FSupplierData { var transient Pawn SuppliedPawn; var transient float NextSupplyTimer; } SupplierLimit; var repnotify class 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.NextSupplyTimer0 ? (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; L = new class'KFGFxObject_TraderItems'; L.SaleItems = L.Default.SaleItems; L.ArmorPrice = L.Default.ArmorPrice; L.GrenadePrice = L.Default.GrenadePrice; return L; } simulated static final function SetWeaponInfo(bool bDedicated, int Index, FCustomTraderItem Item, KFGFxObject_TraderItems List) { local array S; local int i; 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(Item.WeaponClass)!=None && class(Item.WeaponClass).Default.SingleClass!=None) List.SaleItems[Index].SingleClassName = class(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].MaxSpareAmmo = Item.WeaponClass.Default.SpareAmmoCapacity[0]; List.SaleItems[Index].MagazineCapacity = Item.WeaponClass.Default.MagazineCapacity[0]; List.SaleItems[Index].InitialSpareMags = Item.WeaponClass.Default.InitialSpareMags[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; List.SaleItems[Index].InitialSecondaryAmmo = Item.WeaponClass.Default.InitialSpareMags[1]; List.SaleItems[Index].WeaponUpgradeDmgMultiplier[0] = 1.0; for(i = 0;i=(CharacterArchetypes.Length+CustomCharList.Length)) return false; if(SaveDataObjects.Length<=CharIndex) SaveDataObjects.Length = CharIndex+1; if(SaveDataObjects[CharIndex]==None) { C = (CharIndex=(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+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); } simulated final function KFCharacterInfo_Human GetSelectedArch() { if(UsesCustomChar()) return (CustomCharacter.CharacterIndex=2) S = Data.ReadStr(); if(S=="") // Stock skin. return; for(i=0; i=2) S = Data.ReadStr(); if(S=="") // Stock skin. return; Data.SkipBytes(4); n = Data.ReadInt(); for(i=0; i