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,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 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(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].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+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