KF2-Server-Extension/ServerExt/Classes/ExtPlayerReplicationInfo.uc
inklesspen1scripter 23bda71718 Trader, MedicPistol and Perk fixes
MedicPistol has no weight in upgrades now
Fixed weight and damage for upgrades in trader
Fixed initial secondary ammo for weapons in trader
Fixed secondary ammo icon in trader
Fixed error when perk hasn't HeadDamage stat
2020-07-07 00:12:25 +03:00

804 lines
21 KiB
Ucode

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<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 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<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;
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<STraderItemWeaponStats> 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<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].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<Min(Item.WeaponClass.Default.WeaponUpgrades.Length, 5);i++)
{
List.SaleItems[Index].WeaponUpgradeWeight[i+1] = Item.WeaponClass.Static.GetUpgradeStatAdd(EWUS_Weight, i+1);
List.SaleItems[Index].WeaponUpgradeDmgMultiplier[i+1] = Item.WeaponClass.Static.GetUpgradeStatScale(EWUS_Damage0, i+1);
}
if( !bDedicated )
{
List.SaleItems[Index].SecondaryAmmoImagePath = Item.WeaponClass.Default.SecondaryAmmoTexture!=None ? PathName(Item.WeaponClass.Default.SecondaryAmmoTexture) : "UI_SecondaryAmmo_TEX.GasTank";
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]!=`CLEARED_ATTACHMENT_INDEX )
++c;
}
// Write attachments count.
Data.SaveInt(c);
// Write attachments.
for( i=0; i<`MAX_COSMETIC_ATTACHMENTS; ++i )
{
if( CustomCharacter.AttachmentMeshIndices[i]!=`CLEARED_ATTACHMENT_INDEX )
{
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("");
}
simulated function Texture2D GetCurrentIconToDisplay()
{
if(CurrentVoiceCommsRequest == VCT_NONE && ECurrentPerk != none)
{
return ECurrentPerk.default.PerkIcon;
}
return class'KFLocalMessage_VoiceComms'.default.VoiceCommsIcons[CurrentVoiceCommsRequest];
}
// 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"
}