Prepare fixtures
This commit is contained in:
parent
797e5ea192
commit
9c94356263
6021 changed files with 722805 additions and 22 deletions
961
kf_sources/ServerPerksMut/Classes/AdminMenuHandle.uc
Normal file
961
kf_sources/ServerPerksMut/Classes/AdminMenuHandle.uc
Normal file
|
|
@ -0,0 +1,961 @@
|
|||
Class AdminMenuHandle extends Info;
|
||||
|
||||
var bool bMainMenuOpened,bSendCat,bSendWep,bConfigDirty;
|
||||
var KFPlayerController PlayerOwner;
|
||||
var UI_Replication Rep;
|
||||
|
||||
var array<int> PlayerList;
|
||||
var int EditingIndex,EditingCategory;
|
||||
var ServerStStats EditingStats;
|
||||
var() name MainMenuID,EditStatMenuID,StatEditID,EditTraderID,AddWeaponID,EditWeaponID,AddCategoryID,EditCategoryID,ErrorID,CharacterEditID,EditSettingsID;
|
||||
var ServerPerksMut MutatorOwner;
|
||||
|
||||
var string PendingDataFeed,PendingCategories,PendingString;
|
||||
|
||||
var array<string> StatNames,NewStatValues;
|
||||
|
||||
struct FSettingType
|
||||
{
|
||||
var byte Type;
|
||||
var string ExtraValue,Name,PropName;
|
||||
};
|
||||
var array<FSettingType> SettingLines;
|
||||
|
||||
function PostBeginPlay()
|
||||
{
|
||||
PlayerOwner = KFPlayerController(Owner);
|
||||
if( PlayerOwner==None )
|
||||
Error("No KFPlayerController as owner.");
|
||||
else
|
||||
{
|
||||
Rep = Spawn(Class'UI_Replication',PlayerOwner);
|
||||
Rep.DlgWindowClosed = WindowClosed;
|
||||
Rep.DlgSubmittedValue = SubmittedValue;
|
||||
}
|
||||
}
|
||||
function Destroyed()
|
||||
{
|
||||
if( Rep!=None )
|
||||
Rep.Destroy();
|
||||
}
|
||||
|
||||
function WindowClosed( name ID )
|
||||
{
|
||||
if( ID==MainMenuID )
|
||||
Destroy();
|
||||
}
|
||||
function SubmittedValue( name ID, int CompID, string Value );
|
||||
function Tick( float Delta )
|
||||
{
|
||||
if( PlayerOwner==None || Level.Game.bGameEnded )
|
||||
{
|
||||
if( PlayerOwner!=None )
|
||||
PlayerOwner.ClientMessage("Can't edit stats anymore after endgame.");
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
auto state MainMenu
|
||||
{
|
||||
function BeginState()
|
||||
{
|
||||
if( !bMainMenuOpened )
|
||||
{
|
||||
bMainMenuOpened = true;
|
||||
Rep.ClientOpenWindow(MainMenuID,0.4,0.3,"ServerPerks Admin Menu");
|
||||
Rep.ClientAddComponent(MainMenuID,0,0,true,false,0.1,0.2,0.3,0.2,"Edit Trader","Edit the trader weapons and categories list.");
|
||||
Rep.ClientAddComponent(MainMenuID,1,0,true,false,0.6,0.2,0.3,0.2,"Edit Characters","Edit the custom characters players may use.");
|
||||
Rep.ClientAddComponent(MainMenuID,2,0,true,false,0.1,0.5,0.3,0.2,"Edit Settings","Edit misc serverperks settings.");
|
||||
Rep.ClientAddComponent(MainMenuID,3,0,true,false,0.6,0.5,0.3,0.2,"Edit Stats","Edit individual player stats.");
|
||||
Rep.ClientAddComponent(MainMenuID,4,2,true,false,0.35,0.82,0.3,0.15,"Close","Close menu");
|
||||
}
|
||||
}
|
||||
function SubmittedValue( name ID, int CompID, string Value )
|
||||
{
|
||||
if( ID==MainMenuID )
|
||||
{
|
||||
switch( CompID )
|
||||
{
|
||||
case 0:
|
||||
GoToState('EditTrader');
|
||||
break;
|
||||
case 1:
|
||||
GoToState('EditChars');
|
||||
break;
|
||||
case 2:
|
||||
GoToState('EditSettings');
|
||||
break;
|
||||
case 3:
|
||||
GoToState('EditStatsM');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state EditSettings
|
||||
{
|
||||
function BeginState()
|
||||
{
|
||||
local float X,Y;
|
||||
local int i;
|
||||
local string S;
|
||||
local byte T;
|
||||
|
||||
bConfigDirty = false;
|
||||
Rep.ClientOpenWindow(EditSettingsID,0.9,0.9,"Server settings menu");
|
||||
Rep.ClientAddComponent(EditSettingsID,0,2,true,false,0.85,0.9,0.1,0.05,"Close","Close menu");
|
||||
|
||||
X = 0.025;
|
||||
Y = 0.05;
|
||||
for( i=0; i<SettingLines.Length; ++i )
|
||||
{
|
||||
S = "";
|
||||
S = MutatorOwner.GetPropertyText(SettingLines[i].PropName);
|
||||
T = SettingLines[i].Type;
|
||||
S = SettingLines[i].ExtraValue$S;
|
||||
|
||||
Rep.ClientAddComponent(EditSettingsID,(i+1),T,true,false,X,Y,0.35,0.048,S,SettingLines[i].Name);
|
||||
Y+=0.05;
|
||||
if( Y>=0.9 )
|
||||
{
|
||||
Y = 0.05;
|
||||
X+=0.4;
|
||||
}
|
||||
}
|
||||
}
|
||||
function EndState()
|
||||
{
|
||||
if( bConfigDirty )
|
||||
MutatorOwner.SaveConfig();
|
||||
Rep.ClientCloseWindow(EditSettingsID);
|
||||
}
|
||||
function WindowClosed( name ID )
|
||||
{
|
||||
if( ID==EditSettingsID )
|
||||
GoToState('MainMenu');
|
||||
else Global.WindowClosed(ID);
|
||||
}
|
||||
function SubmittedValue( name ID, int CompID, string Value )
|
||||
{
|
||||
if( ID==EditSettingsID )
|
||||
{
|
||||
if( CompID>=1 && CompID<=SettingLines.Length )
|
||||
{
|
||||
bConfigDirty = true;
|
||||
if( SettingLines[CompID-1].Type==7 )
|
||||
MutatorOwner.SetPropertyText(SettingLines[CompID-1].PropName,Eval(Value!="0","True","False"));
|
||||
else MutatorOwner.SetPropertyText(SettingLines[CompID-1].PropName,Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state EditTrader
|
||||
{
|
||||
function BeginState()
|
||||
{
|
||||
bConfigDirty = false;
|
||||
Rep.ClientOpenWindow(EditTraderID,0.6,0.4,"Trader Weapon Editor");
|
||||
Rep.ClientAddComponent(EditTraderID,0,0,true,false,0.1,0.26,0.14,0.11,"Add","Add a new weapon class to the list.");
|
||||
Rep.ClientAddComponent(EditTraderID,1,0,true,false,0.3,0.26,0.14,0.11,"Edit","Edit the current weapon class.");
|
||||
Rep.ClientAddComponent(EditTraderID,2,0,true,false,0.6,0.26,0.14,0.11,"Delete","Remove the current weapon from list.");
|
||||
Rep.ClientAddComponent(EditTraderID,3,0,true,false,0.1,0.66,0.14,0.11,"Add","Add a new weapon category to the list.");
|
||||
Rep.ClientAddComponent(EditTraderID,4,0,true,false,0.3,0.66,0.14,0.11,"Edit","Rename the current weapon category.");
|
||||
Rep.ClientAddComponent(EditTraderID,5,0,true,false,0.6,0.66,0.14,0.11,"Delete","Remove the current weapon category from list.");
|
||||
Rep.ClientAddComponent(EditTraderID,8,2,true,false,0.35,0.82,0.3,0.15,"Close","Close menu");
|
||||
|
||||
SendCategories();
|
||||
SendWeaponList();
|
||||
}
|
||||
function EndState()
|
||||
{
|
||||
if( bConfigDirty )
|
||||
MutatorOwner.SaveConfig();
|
||||
Rep.ClientCloseWindow(EditTraderID);
|
||||
Rep.ClientCloseWindow(AddWeaponID);
|
||||
Rep.ClientCloseWindow(EditWeaponID);
|
||||
Rep.ClientCloseWindow(AddCategoryID);
|
||||
Rep.ClientCloseWindow(EditCategoryID);
|
||||
}
|
||||
function WindowClosed( name ID )
|
||||
{
|
||||
if( ID==EditTraderID )
|
||||
GoToState('MainMenu');
|
||||
else Global.WindowClosed(ID);
|
||||
}
|
||||
|
||||
function Tick( float Delta )
|
||||
{
|
||||
if( bSendCat )
|
||||
{
|
||||
if( Len(PendingCategories)<=200 )
|
||||
{
|
||||
bSendCat = false;
|
||||
Rep.ClientAddComponent(EditTraderID,6,6,true,false,0.025,0.55,0.95,0.1,PendingCategories,"Category:");
|
||||
EditingCategory = 0;
|
||||
if( !bSendWep )
|
||||
UpdateCategoryIndex();
|
||||
}
|
||||
else
|
||||
{
|
||||
Rep.ClientPendingData(Left(PendingCategories,200));
|
||||
PendingCategories = Mid(PendingCategories,200);
|
||||
}
|
||||
}
|
||||
else if( bSendWep )
|
||||
{
|
||||
if( Len(PendingDataFeed)<=200 )
|
||||
{
|
||||
bSendWep = false;
|
||||
Rep.ClientAddComponent(EditTraderID,7,6,true,false,0.025,0.15,0.95,0.1,PendingDataFeed,"Weapon:");
|
||||
EditingIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Rep.ClientPendingData(Left(PendingDataFeed,200));
|
||||
PendingDataFeed = Mid(PendingDataFeed,200);
|
||||
}
|
||||
}
|
||||
Global.Tick(Delta);
|
||||
}
|
||||
final function SendCategories()
|
||||
{
|
||||
local int i;
|
||||
|
||||
bSendCat = true;
|
||||
PendingCategories = "0;";
|
||||
for( i=0; i<MutatorOwner.WeaponCategories.Length; ++i )
|
||||
{
|
||||
if( i==0 )
|
||||
PendingCategories $= Repl(MutatorOwner.WeaponCategories[i],":",";");
|
||||
else PendingCategories $= ":"$Repl(MutatorOwner.WeaponCategories[i],":",";");
|
||||
}
|
||||
if( i==0 )
|
||||
PendingCategories $= "None";
|
||||
}
|
||||
final function SendWeaponList()
|
||||
{
|
||||
local int i,j;
|
||||
local string S;
|
||||
|
||||
bSendWep = true;
|
||||
PendingDataFeed = "0;None";
|
||||
for( i=0; i<MutatorOwner.TraderInventory.Length; ++i )
|
||||
{
|
||||
S = MutatorOwner.TraderInventory[i];
|
||||
j = InStr(S,":");
|
||||
if( j>=0 )
|
||||
S = Mid(S,j+1);
|
||||
PendingDataFeed $= ":"$S;
|
||||
}
|
||||
}
|
||||
final function UpdateWeaponCat( int NewID )
|
||||
{
|
||||
local int j;
|
||||
local string S;
|
||||
|
||||
if( EditingIndex>0 && !bSendWep && EditingIndex<=MutatorOwner.TraderInventory.Length )
|
||||
{
|
||||
S = MutatorOwner.TraderInventory[EditingIndex-1];
|
||||
j = InStr(S,":");
|
||||
if( j>=0 )
|
||||
S = Mid(S,j+1);
|
||||
MutatorOwner.TraderInventory[EditingIndex-1] = string(NewID)$":"$S;
|
||||
bConfigDirty = true;
|
||||
}
|
||||
}
|
||||
final function UpdateCategoryIndex()
|
||||
{
|
||||
local int j;
|
||||
local string S;
|
||||
|
||||
if( EditingIndex>0 && !bSendWep && EditingIndex<=MutatorOwner.TraderInventory.Length )
|
||||
{
|
||||
S = MutatorOwner.TraderInventory[EditingIndex-1];
|
||||
j = InStr(S,":");
|
||||
if( j>=0 )
|
||||
EditingCategory = int(Left(S,j));
|
||||
else EditingCategory = 0;
|
||||
Rep.ClientSetCompValue(EditTraderID,6,string(EditingCategory));
|
||||
}
|
||||
}
|
||||
final function DeleteWeapon()
|
||||
{
|
||||
if( EditingIndex>0 && !bSendWep && EditingIndex<=MutatorOwner.TraderInventory.Length )
|
||||
{
|
||||
MutatorOwner.TraderInventory.Remove(EditingIndex-1,1);
|
||||
bConfigDirty = true;
|
||||
SendWeaponList();
|
||||
}
|
||||
}
|
||||
final function DeleteCategory()
|
||||
{
|
||||
local int i,j,n;
|
||||
local string S;
|
||||
|
||||
if( EditingCategory>=0 && !bSendCat && EditingCategory<MutatorOwner.WeaponCategories.Length )
|
||||
{
|
||||
for( i=0; i<MutatorOwner.TraderInventory.Length; ++i )
|
||||
{
|
||||
S = MutatorOwner.TraderInventory[i];
|
||||
j = InStr(S,":");
|
||||
if( j>=0 )
|
||||
{
|
||||
n = int(Left(S,j));
|
||||
S = Mid(S,j+1);
|
||||
}
|
||||
else n = 0;
|
||||
if( n>=EditingCategory )
|
||||
n = Max(j-1,0);
|
||||
MutatorOwner.TraderInventory[i] = string(n)$":"$S;
|
||||
}
|
||||
MutatorOwner.WeaponCategories.Remove(EditingCategory,1);
|
||||
bConfigDirty = true;
|
||||
SendCategories();
|
||||
SendWeaponList();
|
||||
}
|
||||
}
|
||||
final function EditBoxWindow( name ID, string Title, string Type, string A, string B, optional string C )
|
||||
{
|
||||
Rep.ClientOpenWindow(ID,0.7,0.2,Title);
|
||||
Rep.ClientAddComponent(ID,0,3,false,false,0.025,0.2,0.95,0.4,C,Type);
|
||||
Rep.ClientAddComponent(ID,1,1,true,false,0.1,0.6,0.3,0.2,A,A$" this weapon "$B$" in trader menu.");
|
||||
Rep.ClientAddComponent(ID,2,2,true,false,0.6,0.6,0.3,0.2,"Close","Close menu without doing anything");
|
||||
PendingString = C;
|
||||
}
|
||||
final function AddWeapon()
|
||||
{
|
||||
EditBoxWindow(AddWeaponID,"Add Weapon","Classname:","Add","class");
|
||||
}
|
||||
final function AddNewWeapon()
|
||||
{
|
||||
local int i;
|
||||
local class<KFWeaponPickup> WC;
|
||||
|
||||
WC = Class<KFWeaponPickup>(DynamicLoadObject(PendingString,Class'Class'));
|
||||
if( WC==None )
|
||||
{
|
||||
PlayerOwner.ClientMessage("Couldn't add weapon: Couldn't load class '"$PendingString$"'");
|
||||
return;
|
||||
}
|
||||
i = MutatorOwner.TraderInventory.Length;
|
||||
MutatorOwner.TraderInventory.Length = i+1;
|
||||
MutatorOwner.TraderInventory[i] = "0:"$string(WC);
|
||||
bConfigDirty = true;
|
||||
SendWeaponList();
|
||||
Rep.ClientCloseWindow(AddWeaponID);
|
||||
}
|
||||
final function EditWeapon()
|
||||
{
|
||||
local string S;
|
||||
local int i;
|
||||
|
||||
if( EditingIndex>0 && !bSendWep && EditingIndex<=MutatorOwner.TraderInventory.Length )
|
||||
{
|
||||
S = MutatorOwner.TraderInventory[EditingIndex-1];
|
||||
i = InStr(S,":");
|
||||
if( i>=0 )
|
||||
S = Mid(S,i+1);
|
||||
EditBoxWindow(EditWeaponID,"Edit Weapon","Classname:","Edit","class",S);
|
||||
}
|
||||
}
|
||||
final function EditCurrentWeapon()
|
||||
{
|
||||
local int i,n;
|
||||
local class<KFWeaponPickup> WC;
|
||||
local string S;
|
||||
|
||||
if( EditingIndex>0 && !bSendWep && EditingIndex<=MutatorOwner.TraderInventory.Length )
|
||||
{
|
||||
WC = Class<KFWeaponPickup>(DynamicLoadObject(PendingString,Class'Class'));
|
||||
if( WC==None )
|
||||
{
|
||||
PlayerOwner.ClientMessage("Couldn't edit weapon: Couldn't load class '"$PendingString$"'");
|
||||
return;
|
||||
}
|
||||
S = MutatorOwner.TraderInventory[EditingIndex-1];
|
||||
i = InStr(S,":");
|
||||
if( i>=0 )
|
||||
{
|
||||
n = int(Left(S,i));
|
||||
S = Mid(S,i+1);
|
||||
}
|
||||
else n = 0;
|
||||
MutatorOwner.TraderInventory[EditingIndex-1] = string(n)$":"$string(WC);
|
||||
bConfigDirty = true;
|
||||
SendWeaponList();
|
||||
Rep.ClientCloseWindow(EditWeaponID);
|
||||
}
|
||||
}
|
||||
final function AddCategory()
|
||||
{
|
||||
EditBoxWindow(AddCategoryID,"Add Category","Name:","Add","category");
|
||||
}
|
||||
final function AddNewCategory()
|
||||
{
|
||||
local int i;
|
||||
|
||||
i = MutatorOwner.WeaponCategories.Length;
|
||||
MutatorOwner.WeaponCategories.Length = i+1;
|
||||
MutatorOwner.WeaponCategories[i] = PendingString;
|
||||
bConfigDirty = true;
|
||||
SendCategories();
|
||||
Rep.ClientCloseWindow(AddCategoryID);
|
||||
}
|
||||
final function EditCategory()
|
||||
{
|
||||
if( EditingCategory>=0 && !bSendCat && EditingCategory<MutatorOwner.WeaponCategories.Length )
|
||||
EditBoxWindow(EditCategoryID,"Edit Category","Name:","Edit","category",MutatorOwner.WeaponCategories[EditingCategory]);
|
||||
}
|
||||
final function EditCurrentCategory()
|
||||
{
|
||||
if( EditingCategory>=0 && !bSendCat && EditingCategory<MutatorOwner.WeaponCategories.Length )
|
||||
{
|
||||
MutatorOwner.WeaponCategories[EditingCategory] = PendingString;
|
||||
bConfigDirty = true;
|
||||
SendCategories();
|
||||
Rep.ClientCloseWindow(EditCategoryID);
|
||||
}
|
||||
}
|
||||
function SubmittedValue( name ID, int CompID, string Value )
|
||||
{
|
||||
if( ID==EditTraderID )
|
||||
{
|
||||
switch( CompID )
|
||||
{
|
||||
case 0:
|
||||
AddWeapon();
|
||||
break;
|
||||
case 1:
|
||||
EditWeapon();
|
||||
break;
|
||||
case 2:
|
||||
DeleteWeapon();
|
||||
break;
|
||||
case 3:
|
||||
AddCategory();
|
||||
break;
|
||||
case 4:
|
||||
EditCategory();
|
||||
break;
|
||||
case 5:
|
||||
DeleteCategory();
|
||||
break;
|
||||
case 6:
|
||||
EditingCategory = int(Value);
|
||||
UpdateWeaponCat(EditingCategory);
|
||||
break;
|
||||
case 7:
|
||||
EditingIndex = int(Value);
|
||||
UpdateCategoryIndex();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( ID==AddWeaponID )
|
||||
{
|
||||
switch( CompID )
|
||||
{
|
||||
case 0:
|
||||
PendingString = Value;
|
||||
break;
|
||||
case 1:
|
||||
AddNewWeapon();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( ID==EditWeaponID )
|
||||
{
|
||||
switch( CompID )
|
||||
{
|
||||
case 0:
|
||||
PendingString = Value;
|
||||
break;
|
||||
case 1:
|
||||
EditCurrentWeapon();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( ID==AddCategoryID )
|
||||
{
|
||||
switch( CompID )
|
||||
{
|
||||
case 0:
|
||||
PendingString = Value;
|
||||
break;
|
||||
case 1:
|
||||
AddNewCategory();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( ID==EditCategoryID )
|
||||
{
|
||||
switch( CompID )
|
||||
{
|
||||
case 0:
|
||||
PendingString = Value;
|
||||
break;
|
||||
case 1:
|
||||
EditCurrentCategory();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state EditChars
|
||||
{
|
||||
function BeginState()
|
||||
{
|
||||
bConfigDirty = false;
|
||||
Rep.ClientOpenWindow(CharacterEditID,0.6,0.4,"Character Editor");
|
||||
Rep.ClientAddComponent(CharacterEditID,0,0,true,false,0.1,0.4,0.14,0.11,"Add","Add a new character to the list.");
|
||||
Rep.ClientAddComponent(CharacterEditID,1,0,true,false,0.3,0.4,0.14,0.11,"Edit","Edit the current character.");
|
||||
Rep.ClientAddComponent(CharacterEditID,2,0,true,false,0.6,0.4,0.14,0.11,"Delete","Remove the current character from list.");
|
||||
Rep.ClientAddComponent(CharacterEditID,3,2,true,false,0.35,0.82,0.3,0.15,"Close","Close menu");
|
||||
SendCharacters();
|
||||
}
|
||||
function EndState()
|
||||
{
|
||||
if( bConfigDirty )
|
||||
MutatorOwner.SaveConfig();
|
||||
Rep.ClientCloseWindow(CharacterEditID);
|
||||
}
|
||||
function WindowClosed( name ID )
|
||||
{
|
||||
if( ID==CharacterEditID )
|
||||
GoToState('MainMenu');
|
||||
else Global.WindowClosed(ID);
|
||||
}
|
||||
|
||||
function Tick( float Delta )
|
||||
{
|
||||
if( bSendCat )
|
||||
{
|
||||
if( Len(PendingCategories)<=200 )
|
||||
{
|
||||
bSendCat = false;
|
||||
Rep.ClientAddComponent(CharacterEditID,4,6,true,false,0.025,0.2,0.95,0.15,PendingCategories,"Character:");
|
||||
EditingCategory = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Rep.ClientPendingData(Left(PendingCategories,200));
|
||||
PendingCategories = Mid(PendingCategories,200);
|
||||
}
|
||||
}
|
||||
Global.Tick(Delta);
|
||||
}
|
||||
final function SendCharacters()
|
||||
{
|
||||
local int i,j;
|
||||
local string S;
|
||||
|
||||
bSendCat = true;
|
||||
PendingCategories = "0;";
|
||||
for( i=0; i<MutatorOwner.CustomCharacters.Length; ++i )
|
||||
{
|
||||
S = MutatorOwner.CustomCharacters[i];
|
||||
j = InStr(S,":");
|
||||
if( j>=0 )
|
||||
S = Mid(S,j+1)$" ["$Left(S,j)$"]";
|
||||
if( i==0 )
|
||||
PendingCategories $= S;
|
||||
else PendingCategories $= ":"$S;
|
||||
}
|
||||
if( i==0 )
|
||||
PendingCategories $= "None";
|
||||
}
|
||||
|
||||
final function DeleteCharacter()
|
||||
{
|
||||
if( EditingCategory>=0 && !bSendCat && EditingCategory<MutatorOwner.CustomCharacters.Length )
|
||||
{
|
||||
MutatorOwner.CustomCharacters.Remove(EditingCategory,1);
|
||||
bConfigDirty = true;
|
||||
SendCharacters();
|
||||
}
|
||||
}
|
||||
final function EditBoxWindow( name ID, string Title, string A, optional string C, optional string Cat )
|
||||
{
|
||||
Rep.ClientOpenWindow(ID,0.7,0.2,Title);
|
||||
Rep.ClientAddComponent(ID,0,3,false,false,0.025,0.2,0.95,0.4,C,"Character:");
|
||||
Rep.ClientAddComponent(ID,1,3,false,false,0.025,0.4,0.95,0.4,Cat,"Category:");
|
||||
Rep.ClientAddComponent(ID,2,1,true,false,0.1,0.6,0.3,0.2,A,A$" this character.");
|
||||
Rep.ClientAddComponent(ID,3,2,true,false,0.6,0.6,0.3,0.2,"Close","Close menu without doing anything");
|
||||
PendingString = C;
|
||||
PendingDataFeed = Cat;
|
||||
}
|
||||
final function AddCharacter()
|
||||
{
|
||||
EditBoxWindow(AddCategoryID,"Add Character","Add");
|
||||
}
|
||||
final function AddNewCharacter()
|
||||
{
|
||||
local int i;
|
||||
local string S;
|
||||
|
||||
if( class<PlayerRecordClass>(DynamicLoadObject(PendingString$"Mod."$PendingString,class'Class',true))==None )
|
||||
PlayerOwner.ClientMessage("Couldn't load any PlayerRecordClass for '"$PendingString$"Mod."$PendingString$"', are sure this is desired?");
|
||||
if( PendingDataFeed!="" )
|
||||
S = PendingDataFeed$":"$PendingString;
|
||||
else S = PendingString;
|
||||
i = MutatorOwner.CustomCharacters.Length;
|
||||
MutatorOwner.CustomCharacters.Length = i+1;
|
||||
MutatorOwner.CustomCharacters[i] = S;
|
||||
bConfigDirty = true;
|
||||
SendCharacters();
|
||||
Rep.ClientCloseWindow(AddCategoryID);
|
||||
}
|
||||
final function EditCharacter()
|
||||
{
|
||||
local int i;
|
||||
local string S;
|
||||
|
||||
if( EditingCategory>=0 && !bSendCat && EditingCategory<MutatorOwner.CustomCharacters.Length )
|
||||
{
|
||||
S = MutatorOwner.CustomCharacters[EditingCategory];
|
||||
i = InStr(S,":");
|
||||
if( i==-1 )
|
||||
EditBoxWindow(EditCategoryID,"Edit Character","Edit",S);
|
||||
else EditBoxWindow(EditCategoryID,"Edit Character","Edit",Mid(S,i+1),Left(S,i));
|
||||
}
|
||||
}
|
||||
final function EditCurrentCharacter()
|
||||
{
|
||||
local string S;
|
||||
|
||||
if( EditingCategory>=0 && !bSendCat && EditingCategory<MutatorOwner.CustomCharacters.Length )
|
||||
{
|
||||
if( class<PlayerRecordClass>(DynamicLoadObject(PendingString$"Mod."$PendingString,class'Class',true))==None )
|
||||
PlayerOwner.ClientMessage("Couldn't load any PlayerRecordClass for '"$PendingString$"Mod."$PendingString$"', are sure this is desired?");
|
||||
if( PendingDataFeed!="" )
|
||||
S = PendingDataFeed$":"$PendingString;
|
||||
else S = PendingString;
|
||||
MutatorOwner.CustomCharacters[EditingCategory] = S;
|
||||
bConfigDirty = true;
|
||||
SendCharacters();
|
||||
Rep.ClientCloseWindow(EditCategoryID);
|
||||
}
|
||||
}
|
||||
function SubmittedValue( name ID, int CompID, string Value )
|
||||
{
|
||||
if( ID==CharacterEditID )
|
||||
{
|
||||
switch( CompID )
|
||||
{
|
||||
case 0:
|
||||
AddCharacter();
|
||||
break;
|
||||
case 1:
|
||||
EditCharacter();
|
||||
break;
|
||||
case 2:
|
||||
DeleteCharacter();
|
||||
break;
|
||||
case 4:
|
||||
EditingCategory = int(Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( ID==AddCategoryID )
|
||||
{
|
||||
switch( CompID )
|
||||
{
|
||||
case 0:
|
||||
PendingString = Value;
|
||||
break;
|
||||
case 1:
|
||||
PendingDataFeed = Value;
|
||||
break;
|
||||
case 2:
|
||||
AddNewCharacter();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( ID==EditCategoryID )
|
||||
{
|
||||
switch( CompID )
|
||||
{
|
||||
case 0:
|
||||
PendingString = Value;
|
||||
break;
|
||||
case 1:
|
||||
PendingDataFeed = Value;
|
||||
break;
|
||||
case 2:
|
||||
EditCurrentCharacter();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state EditStatsM
|
||||
{
|
||||
function BeginState()
|
||||
{
|
||||
Rep.ClientOpenWindow(EditStatMenuID,0.4,0.3,"Stats Editor");
|
||||
Rep.ClientAddComponent(EditStatMenuID,0,0,true,false,0.1,0.6,0.3,0.2,"Refresh","Refresh players list");
|
||||
Rep.ClientAddComponent(EditStatMenuID,1,1,true,true,0.6,0.6,0.3,0.2,"Edit","Edit stats of selected player");
|
||||
Rep.ClientAddComponent(EditStatMenuID,3,2,true,false,0.35,0.82,0.3,0.15,"Close","Close menu");
|
||||
SetPlayerList();
|
||||
}
|
||||
function EndState()
|
||||
{
|
||||
Rep.ClientCloseWindow(EditStatMenuID);
|
||||
}
|
||||
final function SetPlayerList()
|
||||
{
|
||||
local Controller C;
|
||||
local string S;
|
||||
|
||||
PlayerList.Length = 0;
|
||||
EditingIndex = 0;
|
||||
S = "0;None";
|
||||
for( C=Level.ControllerList; C!=None; C=C.nextController )
|
||||
{
|
||||
if( C.bIsPlayer && xPlayer(C)!=None && ServerStStats(xPlayer(C).SteamStatsAndAchievements)!=none )
|
||||
{
|
||||
PlayerList[PlayerList.Length] = C.PlayerReplicationInfo.PlayerID;
|
||||
S $= ":"$C.PlayerReplicationInfo.PlayerID$" - "$Repl(Left(C.PlayerReplicationInfo.PlayerName,16),":",".");
|
||||
if( Len(S)>150 )
|
||||
{
|
||||
Rep.ClientPendingData(S);
|
||||
S = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
Rep.ClientAddComponent(EditStatMenuID,2,6,true,false,0.1,0.1,0.8,0.2,S,"Select player:");
|
||||
Rep.ClientSetCompLock(EditStatMenuID,1,true);
|
||||
}
|
||||
final function EditPlayerEntry()
|
||||
{
|
||||
local Controller C;
|
||||
local int i;
|
||||
|
||||
if( EditingIndex==0 || (EditingIndex-1)>=PlayerList.Length )
|
||||
{
|
||||
PlayerOwner.ClientMessage("You selected an invalid player to edit.");
|
||||
return;
|
||||
}
|
||||
i = PlayerList[EditingIndex-1];
|
||||
for( C=Level.ControllerList; C!=None; C=C.nextController )
|
||||
{
|
||||
if( C.bIsPlayer && xPlayer(C)!=None && C.PlayerReplicationInfo.PlayerID==i && ServerStStats(xPlayer(C).SteamStatsAndAchievements)!=none )
|
||||
{
|
||||
EditingStats = ServerStStats(xPlayer(C).SteamStatsAndAchievements);
|
||||
if( !EditingStats.bStatsReadyNow || EditingStats.MyStatsObject==None )
|
||||
PlayerOwner.ClientMessage("Your selected players stats aren't ready to be edited yet.");
|
||||
else GoToState('EditStats');
|
||||
return;
|
||||
}
|
||||
}
|
||||
PlayerOwner.ClientMessage("Your selected player isn't available on server anymore, please refresh.");
|
||||
}
|
||||
function SubmittedValue( name ID, int CompID, string Value )
|
||||
{
|
||||
if( ID==EditStatMenuID )
|
||||
{
|
||||
switch( CompID )
|
||||
{
|
||||
case 0:
|
||||
SetPlayerList();
|
||||
break;
|
||||
case 1:
|
||||
EditPlayerEntry();
|
||||
break;
|
||||
case 2:
|
||||
EditingIndex = int(Value);
|
||||
Rep.ClientSetCompLock(EditStatMenuID,1,(EditingIndex==0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
function WindowClosed( name ID )
|
||||
{
|
||||
if( ID==EditStatMenuID )
|
||||
GoToState('MainMenu');
|
||||
else Global.WindowClosed(ID);
|
||||
}
|
||||
}
|
||||
state EditStats
|
||||
{
|
||||
function BeginState()
|
||||
{
|
||||
Rep.ClientOpenWindow(StatEditID,0.9,0.9,"Stats of "$EditingStats.PlayerOwner.PlayerReplicationInfo.PlayerName);
|
||||
Rep.ClientAddComponent(StatEditID,0,1,true,false,0.1,0.9,0.15,0.05,"Save","Save changes of this player stats");
|
||||
Rep.ClientAddComponent(StatEditID,1,0,true,false,0.47,0.9,0.15,0.05,"Update","Update stats to match client current stats");
|
||||
Rep.ClientAddComponent(StatEditID,2,2,true,false,0.8,0.9,0.15,0.05,"Close","Close window without saving changes");
|
||||
ReadStats();
|
||||
}
|
||||
function EndState()
|
||||
{
|
||||
Rep.ClientCloseWindow(StatEditID);
|
||||
}
|
||||
function Tick( float Delta )
|
||||
{
|
||||
if( EditingStats==None )
|
||||
{
|
||||
PlayerOwner.ClientMessage("Desired player disconnected.");
|
||||
GoToState('EditStatsM');
|
||||
}
|
||||
Global.Tick(Delta);
|
||||
}
|
||||
function WindowClosed( name ID )
|
||||
{
|
||||
if( ID==StatEditID )
|
||||
GoToState('EditStatsM');
|
||||
else Global.WindowClosed(ID);
|
||||
}
|
||||
final function AddStat( out int ID, int CurValue, out float X, out float Y, string Info )
|
||||
{
|
||||
Rep.ClientAddComponent(StatEditID,ID++,5,true,false,X,Y,0.28,0.04,"0:1073741823:1:"$CurValue,Left(Info,13));
|
||||
Y+=0.04;
|
||||
if( Y>=0.85 )
|
||||
{
|
||||
X += 0.3;
|
||||
Y = 0.025;
|
||||
}
|
||||
}
|
||||
final function AddStatStr( out int ID, string CurValue, out float X, out float Y, string Info )
|
||||
{
|
||||
Rep.ClientAddComponent(StatEditID,ID++,3,true,false,X,Y,0.28,0.04,CurValue,Left(Info,13));
|
||||
Y+=0.04;
|
||||
if( Y>=0.85 )
|
||||
{
|
||||
X += 0.3;
|
||||
Y = 0.025;
|
||||
}
|
||||
}
|
||||
final function ReadStats()
|
||||
{
|
||||
local int i,j;
|
||||
local float X,Y;
|
||||
local StatsObject S;
|
||||
local string Res;
|
||||
|
||||
i = 3;
|
||||
S = EditingStats.MyStatsObject;
|
||||
X = 0.015;
|
||||
Y = 0.025;
|
||||
|
||||
NewStatValues.Length = 0;
|
||||
for( j=0; j<StatNames.Length; ++j )
|
||||
{
|
||||
Res = "";
|
||||
Res = S.GetPropertyText(StatNames[j]);
|
||||
AddStat(i,int(Res),X,Y,StatNames[j]);
|
||||
}
|
||||
for( j=0; j<S.CC.Length; ++j )
|
||||
AddStatStr(i,S.CC[j].V,X,Y,string(S.CC[j].N));
|
||||
}
|
||||
final function SaveStats()
|
||||
{
|
||||
local int i;
|
||||
local StatsObject S;
|
||||
|
||||
Log(PlayerOwner.PlayerReplicationInfo.PlayerName$" edited stats of "$EditingStats.PlayerOwner.PlayerReplicationInfo.PlayerName,Class.Outer.Name);
|
||||
S = EditingStats.MyStatsObject;
|
||||
for( i=0; i<NewStatValues.Length; ++i )
|
||||
if( NewStatValues[i]!="" )
|
||||
{
|
||||
if( i<StatNames.Length )
|
||||
S.SetPropertyText(StatNames[i],NewStatValues[i]);
|
||||
else S.CC[i-StatNames.Length].V = NewStatValues[i];
|
||||
}
|
||||
EditingStats.RepCopyStats();
|
||||
EditingStats.NotifyStatChanged();
|
||||
}
|
||||
|
||||
function SubmittedValue( name ID, int CompID, string Value )
|
||||
{
|
||||
if( ID==StatEditID )
|
||||
{
|
||||
switch( CompID )
|
||||
{
|
||||
case 0:
|
||||
SaveStats();
|
||||
break;
|
||||
case 1:
|
||||
ReadStats();
|
||||
break;
|
||||
case 2:
|
||||
GoToState('EditStatsM');
|
||||
break;
|
||||
default:
|
||||
if( CompID>=3 )
|
||||
{
|
||||
CompID-=3;
|
||||
if( CompID>=NewStatValues.Length )
|
||||
NewStatValues.Length = CompID+1;
|
||||
NewStatValues[CompID] = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
MainMenuID="i"
|
||||
EditStatMenuID="Core"
|
||||
StatEditID="j"
|
||||
EditTraderID="Rand"
|
||||
AddWeaponID="Warn"
|
||||
EditWeaponID="Dot"
|
||||
AddCategoryID="Lerp"
|
||||
EditCategoryID="Eval"
|
||||
ErrorID="Error"
|
||||
CharacterEditID="Log"
|
||||
EditSettingsID="S"
|
||||
StatNames(0)="DamageHealedStat"
|
||||
StatNames(1)="WeldingPointsStat"
|
||||
StatNames(2)="ShotgunDamageStat"
|
||||
StatNames(3)="HeadshotKillsStat"
|
||||
StatNames(4)="StalkerKillsStat"
|
||||
StatNames(5)="BullpupDamageStat"
|
||||
StatNames(6)="MeleeDamageStat"
|
||||
StatNames(7)="FlameThrowerDamageStat"
|
||||
StatNames(8)="SelfHealsStat"
|
||||
StatNames(9)="SoleSurvivorWavesStat"
|
||||
StatNames(10)="CashDonatedStat"
|
||||
StatNames(11)="FeedingKillsStat"
|
||||
StatNames(12)="BurningCrossbowKillsStat"
|
||||
StatNames(13)="GibbedFleshpoundsStat"
|
||||
StatNames(14)="StalkersKilledWithExplosivesStat"
|
||||
StatNames(15)="GibbedEnemiesStat"
|
||||
StatNames(16)="BloatKillsStat"
|
||||
StatNames(17)="SirenKillsStat"
|
||||
StatNames(18)="KillsStat"
|
||||
StatNames(19)="ExplosivesDamageStat"
|
||||
StatNames(20)="TotalPlayTime"
|
||||
StatNames(21)="WinsCount"
|
||||
StatNames(22)="LostsCount"
|
||||
StatNames(23)="TotalZedTimeStat"
|
||||
SettingLines(0)=(Type=5,ExtraValue="-1:250:1:",Name="Min Perk Level",PropName="MinPerksLevel")
|
||||
SettingLines(1)=(Type=5,ExtraValue="0:250:1:",Name="Max Perk Level",PropName="MaxPerksLevel")
|
||||
SettingLines(2)=(Type=4,ExtraValue="0.0001:100:0.05:",Name="Requirement Scale",PropName="RequirementScaling")
|
||||
SettingLines(3)=(Type=5,ExtraValue="0:10:1:",Name="Mid-Game save waves",PropName="MidGameSaveWaves")
|
||||
SettingLines(4)=(Type=7,Name="Force perks for all",PropName="bForceGivePerk")
|
||||
SettingLines(5)=(Type=7,Name="No perk saving",PropName="bNoSavingProgress")
|
||||
SettingLines(6)=(Type=7,Name="Use PlayerName as ID",PropName="bUsePlayerNameAsID")
|
||||
SettingLines(7)=(Type=7,Name="Message everyones levelup",PropName="bMessageAnyPlayerLevelUp")
|
||||
SettingLines(8)=(Type=7,Name="Use lowest requirements",PropName="bUseLowestRequirements")
|
||||
SettingLines(9)=(Type=7,Name="Black and white ZED-time",PropName="bBWZEDTime")
|
||||
SettingLines(10)=(Type=7,Name="Use enhanced scoreboard",PropName="bUseEnhancedScoreboard")
|
||||
SettingLines(11)=(Type=7,Name="Remove unused custom stats",PropName="bOverrideUnusedCustomStats")
|
||||
SettingLines(12)=(Type=7,Name="Always allow perk changes",PropName="bAllowAlwaysPerkChanges")
|
||||
SettingLines(13)=(Type=7,Name="Force everyone use custom char",PropName="bForceCustomChars")
|
||||
SettingLines(14)=(Type=7,Name="Enable chat emoticons",PropName="bEnableChatIcons")
|
||||
SettingLines(15)=(Type=7,Name="Over shoulder view",PropName="bEnhancedShoulderView")
|
||||
SettingLines(16)=(Type=7,Name="Fix grenade exploit",PropName="bFixGrenadeExploit")
|
||||
SettingLines(17)=(Type=7,Name="Use remote database",PropName="bUseRemoteDatabase")
|
||||
SettingLines(18)=(Type=7,Name="Use FTP as database",PropName="bUseFTPLink")
|
||||
SettingLines(19)=(Type=3,Name="Newspage URL",PropName="ServerNewsURL")
|
||||
SettingLines(20)=(Type=3,Name="Remove DB URL",PropName="RemoteDatabaseURL")
|
||||
SettingLines(21)=(Type=3,Name="Remove DB Password",PropName="RemotePassword")
|
||||
SettingLines(22)=(Type=3,Name="Remove DB User",PropName="RemoteFTPUser")
|
||||
SettingLines(23)=(Type=3,Name="Remote DB Dir",PropName="RemoteFTPDir")
|
||||
SettingLines(24)=(Type=7,Name="No perk changes",PropName="bNoPerkChanges")
|
||||
}
|
||||
216
kf_sources/ServerPerksMut/Classes/DatabaseUdpLink.uc
Normal file
216
kf_sources/ServerPerksMut/Classes/DatabaseUdpLink.uc
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
Class DatabaseUdpLink extends UdpLink;
|
||||
|
||||
var string PendingLine;
|
||||
var IpAddr A;
|
||||
var ServerPerksMut Mut;
|
||||
var array<StatsObject> ToSave;
|
||||
var array<ServerStStats> PendingData;
|
||||
var transient float NextReqTimer;
|
||||
var bool bConnectionReady,bHasPendingLine;
|
||||
var byte LoopCounter;
|
||||
|
||||
enum ENetID
|
||||
{
|
||||
ID_None,
|
||||
ID_Open,
|
||||
ID_RequestPassword,
|
||||
ID_HeresPassword,
|
||||
ID_ConnectionClosed,
|
||||
ID_PasswordCorrect,
|
||||
ID_NewPlayer,
|
||||
ID_BadNewPlayer,
|
||||
ID_SendPlayerData,
|
||||
ID_UpdatePlayer,
|
||||
ID_KeepAlive,
|
||||
};
|
||||
|
||||
function PostBeginPlay()
|
||||
{
|
||||
Disable('Tick');
|
||||
}
|
||||
function BeginEvent()
|
||||
{
|
||||
Mut.SaveAllStats = SaveAllStats;
|
||||
Mut.RequestStats = RequestStats;
|
||||
|
||||
ReceiveMode = RMODE_Event;
|
||||
if( BindPort(Rand(8000)+8000,true)>0 )
|
||||
Resolve(Mut.RemoteDatabaseURL);
|
||||
}
|
||||
event Resolved( IpAddr Addr )
|
||||
{
|
||||
A = Addr;
|
||||
A.Port = Mut.RemotePort;
|
||||
SendText(A,Chr(ENetID.ID_Open));
|
||||
Enable('Tick');
|
||||
NextReqTimer = Level.TimeSeconds+5.f;
|
||||
}
|
||||
function Tick( float Delta ) // Every 5 seconds, try to open connection again.
|
||||
{
|
||||
if( !bConnectionReady && NextReqTimer<Level.TimeSeconds )
|
||||
{
|
||||
NextReqTimer = Level.TimeSeconds+5.f;
|
||||
SendText(A,Chr(ENetID.ID_Open));
|
||||
}
|
||||
}
|
||||
event ReceivedText( IpAddr Addr, string Text )
|
||||
{
|
||||
local byte First;
|
||||
|
||||
if( bHasPendingLine )
|
||||
{
|
||||
if( Asc(Right(Text,1))!=10 )
|
||||
PendingLine = PendingLine$Text;
|
||||
else
|
||||
{
|
||||
ReceivedPlayerData(PendingLine$Left(Text,Len(Text)-1));
|
||||
PendingLine = "";
|
||||
bHasPendingLine = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
First = Asc(Left(Text,1));
|
||||
Text = Mid(Text,1);
|
||||
if( Mut.bDebugDatabase )
|
||||
Level.Game.Broadcast(Self,"Receive "$GetEnum(enum'ENetID',First)$": "$Text);
|
||||
switch( First )
|
||||
{
|
||||
case ENetID.ID_PasswordCorrect:
|
||||
bConnectionReady = true;
|
||||
break;
|
||||
case ENetID.ID_RequestPassword:
|
||||
bConnectionReady = false;
|
||||
SendText(A,Chr(ENetID.ID_HeresPassword)$Mut.RemotePassword);
|
||||
break;
|
||||
case ENetID.ID_ConnectionClosed:
|
||||
bConnectionReady = false;
|
||||
SendText(A,Chr(ENetID.ID_Open));
|
||||
break;
|
||||
case ENetID.ID_KeepAlive:
|
||||
SendText(A,Chr(ENetID.ID_KeepAlive));
|
||||
break;
|
||||
case ENetID.ID_NewPlayer:
|
||||
ReceivedPlayerID(Text);
|
||||
break;
|
||||
case ENetID.ID_SendPlayerData:
|
||||
if( Asc(Right(Text,1))!=10 )
|
||||
{
|
||||
PendingLine = Text;
|
||||
bHasPendingLine = true;
|
||||
break;
|
||||
}
|
||||
ReceivedPlayerData(Left(Text,Len(Text)-1));
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
function SaveAllStats()
|
||||
{
|
||||
local int i;
|
||||
|
||||
ToSave = Mut.ActiveStats;
|
||||
for( i=0; i<ToSave.Length; ++i )
|
||||
{
|
||||
if( !ToSave[i].bStatsChanged )
|
||||
ToSave.Remove(i--,1);
|
||||
}
|
||||
if( ToSave.Length>0 )
|
||||
GoToState('SaveAll');
|
||||
}
|
||||
function RequestStats( ServerStStats Other )
|
||||
{
|
||||
local int i;
|
||||
|
||||
if( !bConnectionReady )
|
||||
return;
|
||||
SendText(A,Chr(ENetID.ID_NewPlayer)$Other.MyStatsObject.Name$"*"$Mut.GetSafeName(Other.PlayerOwner.PlayerReplicationInfo.PlayerName));
|
||||
for( i=0; i<PendingData.Length; ++i )
|
||||
if( PendingData[i]==Other )
|
||||
return;
|
||||
PendingData[PendingData.Length] = Other;
|
||||
}
|
||||
final function ReceivedPlayerID( string S )
|
||||
{
|
||||
local int i,RID;
|
||||
|
||||
i = InStr(S,"|");
|
||||
RID = int(Left(S,i));
|
||||
S = Mid(S,i+1);
|
||||
|
||||
for( i=0; i<PendingData.Length; ++i )
|
||||
{
|
||||
if( PendingData[i]==None )
|
||||
PendingData.Remove(i--,1);
|
||||
else if( S~=string(PendingData[i].MyStatsObject.Name) )
|
||||
{
|
||||
PendingData[i].SetID(RID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
final function ReceivedPlayerData( string S )
|
||||
{
|
||||
local int i,RID;
|
||||
|
||||
i = InStr(S,"|");
|
||||
RID = int(Left(S,i));
|
||||
S = Mid(S,i+1);
|
||||
|
||||
for( i=0; i<PendingData.Length; ++i )
|
||||
{
|
||||
if( PendingData[i]==None )
|
||||
PendingData.Remove(i--,1);
|
||||
else if( RID==PendingData[i].GetID() )
|
||||
{
|
||||
PendingData[i].GetData(S);
|
||||
PendingData.Remove(i,1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
State SaveAll
|
||||
{
|
||||
function BeginState()
|
||||
{
|
||||
SetTimer(0.05,true);
|
||||
}
|
||||
function EndState()
|
||||
{
|
||||
SetTimer(0,false);
|
||||
}
|
||||
function Timer()
|
||||
{
|
||||
local StatsObject S;
|
||||
local string Line;
|
||||
|
||||
if( !bConnectionReady )
|
||||
return;
|
||||
S = ToSave[0];
|
||||
if( Mut.bDebugDatabase )
|
||||
Level.Game.Broadcast(Self,"Send Player stats: "$S.Name$" ("$(ToSave.Length-1)$" remain)");
|
||||
S.bStatsChanged = false;
|
||||
Line = Chr(ENetID.ID_UpdatePlayer)$S.ID$"|"$S.GetSaveData()$Chr(10);
|
||||
while( Len(Line)>512 )
|
||||
{
|
||||
SendText(A,Left(Line,512));
|
||||
Line = Mid(Line,512);
|
||||
}
|
||||
SendText(A,Line);
|
||||
ToSave.Remove(0,1);
|
||||
if( ToSave.Length==0 )
|
||||
GoToState('');
|
||||
}
|
||||
Begin:
|
||||
while( ++LoopCounter<150 )
|
||||
{
|
||||
if( Level.bLevelChange ) // Delay mapchange until all stats are uploaded.
|
||||
Level.NextSwitchCountdown = FMax(Level.NextSwitchCountdown,1.f);
|
||||
Sleep(0.5);
|
||||
}
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
}
|
||||
58
kf_sources/ServerPerksMut/Classes/FTPDataConnection.uc
Normal file
58
kf_sources/ServerPerksMut/Classes/FTPDataConnection.uc
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
Class FTPDataConnection extends TcpLink;
|
||||
|
||||
var bool bUpload,bWasOpened;
|
||||
var string Data;
|
||||
|
||||
delegate OnCompleted();
|
||||
delegate OnProgress();
|
||||
|
||||
function PostBeginPlay()
|
||||
{
|
||||
LinkMode = MODE_Text;
|
||||
}
|
||||
event Opened()
|
||||
{
|
||||
BeginUpload();
|
||||
}
|
||||
event Closed()
|
||||
{
|
||||
OnCompleted();
|
||||
Destroy();
|
||||
}
|
||||
event ReceivedText( string Text )
|
||||
{
|
||||
if( bUpload )
|
||||
Log(Text,'FTPD');
|
||||
else
|
||||
{
|
||||
Data $= Text;
|
||||
OnProgress();
|
||||
}
|
||||
}
|
||||
function BeginUpload()
|
||||
{
|
||||
if( bWasOpened )
|
||||
GoToState('Uploading');
|
||||
else bWasOpened = true;
|
||||
}
|
||||
|
||||
state Uploading
|
||||
{
|
||||
function BeginState()
|
||||
{
|
||||
Tick(0.f);
|
||||
}
|
||||
function Tick( float Delta )
|
||||
{
|
||||
if( Data!="" )
|
||||
{
|
||||
SendText(Left(Data,250));
|
||||
Data = Mid(Data,250);
|
||||
}
|
||||
else Close();
|
||||
}
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
}
|
||||
684
kf_sources/ServerPerksMut/Classes/FTPTcpLink.uc
Normal file
684
kf_sources/ServerPerksMut/Classes/FTPTcpLink.uc
Normal file
|
|
@ -0,0 +1,684 @@
|
|||
Class FTPTcpLink extends TcpLink;
|
||||
|
||||
var string TempFileName;
|
||||
var array<ServerStStats> PendingLoaders;
|
||||
var array<StatsObject> ToSave;
|
||||
var ServerPerksMut Mut;
|
||||
var IpAddr SiteAddress;
|
||||
var FTPDataConnection DataConnection;
|
||||
var transient float WelcomeTimer;
|
||||
var array<string> TotalList;
|
||||
var PlayerController WebAdminController;
|
||||
var int IgnoreDateNum;
|
||||
var byte RetryCounter;
|
||||
var bool bConnectionBroken,bFullVerbose,bUploadAllStats,bTotalUpload,bFileInProgress,bLogAllCommands,bCheckedWeb,bPostUploadCheck,bIsAsciiMode,bObtainDir;
|
||||
|
||||
function BeginEvent()
|
||||
{
|
||||
Mut.SaveAllStats = SaveAllStats;
|
||||
Mut.RequestStats = RequestStats;
|
||||
if( Mut.bDebugDatabase )
|
||||
{
|
||||
bLogAllCommands = true;
|
||||
bFullVerbose = true;
|
||||
}
|
||||
|
||||
LinkMode = MODE_Line;
|
||||
ReceiveMode = RMODE_Event;
|
||||
Resolve(Mut.RemoteDatabaseURL);
|
||||
}
|
||||
final function ReportError( int Code, string InEr )
|
||||
{
|
||||
if( !bConnectionBroken )
|
||||
{
|
||||
Level.Game.Broadcast(Self,Code$" FTP Error: "$InEr);
|
||||
Log(Code$" FTP Error: "$InEr,Class.Name);
|
||||
}
|
||||
bConnectionBroken = true;
|
||||
GoToState('ErrorState');
|
||||
}
|
||||
event Resolved( IpAddr Addr )
|
||||
{
|
||||
SiteAddress = Addr;
|
||||
SiteAddress.Port = Mut.RemotePort;
|
||||
GoToState('Idle');
|
||||
}
|
||||
event ResolveFailed()
|
||||
{
|
||||
ReportError(0,"Couldn't resolve address, aborting...");
|
||||
}
|
||||
event Closed()
|
||||
{
|
||||
ReportError(1,"Connection was closed by FTP server!");
|
||||
}
|
||||
final function DebugLog( string Str )
|
||||
{
|
||||
if( !bCheckedWeb )
|
||||
{
|
||||
bCheckedWeb = true;
|
||||
foreach DynamicActors(class'PlayerController',WebAdminController)
|
||||
if( WebAdminController.IsA('MessagingSpectator') )
|
||||
break;
|
||||
//if( Level.NetMode==NM_StandAlone )
|
||||
// WebAdminController = Level.GetLocalPlayerController();
|
||||
}
|
||||
if( WebAdminController!=None )
|
||||
WebAdminController.ClientMessage(Str,'FTP');
|
||||
Log(Str,'FTP');
|
||||
}
|
||||
event ReceivedLine( string Text )
|
||||
{
|
||||
if( bLogAllCommands )
|
||||
DebugLog("ReceiveFTP "$GetStateName()$":"@Text);
|
||||
ProcessResponse(int(Left(Text,3)),Mid(Text,4));
|
||||
}
|
||||
final function SendFTPLine( string Text )
|
||||
{
|
||||
if( bLogAllCommands )
|
||||
DebugLog("SendFTP "$GetStateName()$":"@Text);
|
||||
SendText(Text);
|
||||
}
|
||||
|
||||
function SaveAllStats()
|
||||
{
|
||||
local int i;
|
||||
|
||||
if( bTotalUpload )
|
||||
return;
|
||||
ToSave = Mut.ActiveStats;
|
||||
for( i=0; i<ToSave.Length; ++i )
|
||||
{
|
||||
if( !ToSave[i].bStatsChanged )
|
||||
ToSave.Remove(i--,1);
|
||||
}
|
||||
if( ToSave.Length>0 )
|
||||
bUploadAllStats = true;
|
||||
}
|
||||
function RequestStats( ServerStStats Other )
|
||||
{
|
||||
local int i;
|
||||
|
||||
if( bTotalUpload )
|
||||
return;
|
||||
for( i=0; i<PendingLoaders.Length; ++i )
|
||||
{
|
||||
if( PendingLoaders[i]==None )
|
||||
PendingLoaders.Remove(i--,1);
|
||||
else if( PendingLoaders[i]==Other )
|
||||
return;
|
||||
}
|
||||
PendingLoaders[PendingLoaders.Length] = Other;
|
||||
}
|
||||
final function FullUpload()
|
||||
{
|
||||
if( Class'ServerPerksMut'.Default.FTPUploadAllIgnoreDate!="" )
|
||||
{
|
||||
bObtainDir = true;
|
||||
IgnoreDateNum = GetDateInt(int(Mid(Class'ServerPerksMut'.Default.FTPUploadAllIgnoreDate,6,2)),int(Mid(Class'ServerPerksMut'.Default.FTPUploadAllIgnoreDate,4,2)),int(Mid(Class'ServerPerksMut'.Default.FTPUploadAllIgnoreDate,0,4)));
|
||||
}
|
||||
|
||||
TotalList = GetPerObjectNames("ServerPerksStat","StatsObject",9999999);
|
||||
bTotalUpload = true;
|
||||
bUploadAllStats = true;
|
||||
bFullVerbose = true;
|
||||
HasMoreStats();
|
||||
SaveAllStats();
|
||||
}
|
||||
final function bool HasMoreStats()
|
||||
{
|
||||
local byte i;
|
||||
local int j;
|
||||
|
||||
if( TotalList.Length==0 )
|
||||
return false;
|
||||
j = ToSave.Length;
|
||||
for( i=0; i<Min(20,TotalList.Length); ++i )
|
||||
{
|
||||
ToSave.Length = j+1;
|
||||
ToSave[j] = new(None,TotalList[i]) Class'StatsObject';
|
||||
++j;
|
||||
}
|
||||
TotalList.Remove(0,20);
|
||||
return true;
|
||||
}
|
||||
final function CheckNextCommand()
|
||||
{
|
||||
if( bObtainDir )
|
||||
{
|
||||
GoToState('GetDir');
|
||||
return;
|
||||
}
|
||||
while( PendingLoaders.Length>0 && PendingLoaders[0]==None )
|
||||
PendingLoaders.Remove(0,1);
|
||||
|
||||
if( bUploadAllStats || (bTotalUpload && HasMoreStats()) )
|
||||
GoToState('UploadStats','Begin');
|
||||
else if( PendingLoaders.Length>0 )
|
||||
GoToState('DownloadStats','Begin');
|
||||
else
|
||||
{
|
||||
if( bFullVerbose )
|
||||
Level.Game.Broadcast(Self,"FTP: All done!");
|
||||
if( Mut.FTPKeepAliveSec>0 && !Level.Game.bGameEnded )
|
||||
GoToState('KeepAlive');
|
||||
else GoToState('EndConnection');
|
||||
}
|
||||
}
|
||||
function ProcessResponse( int Code, string Line )
|
||||
{
|
||||
switch( Code )
|
||||
{
|
||||
case 220: // Welcome
|
||||
if( WelcomeTimer<Level.TimeSeconds )
|
||||
{
|
||||
SendFTPLine("USER "$Mut.RemoteFTPUser);
|
||||
WelcomeTimer = Level.TimeSeconds+0.2;
|
||||
}
|
||||
break;
|
||||
case 331: // Password required
|
||||
SendFTPLine("PASS "$Mut.RemotePassword);
|
||||
break;
|
||||
case 230: // User logged in.
|
||||
if( Mut.RemoteFTPDir!="" )
|
||||
SendFTPLine("CWD "$Mut.RemoteFTPDir);
|
||||
else
|
||||
{
|
||||
SendFTPLine("TYPE A");
|
||||
bIsAsciiMode = true;
|
||||
}
|
||||
break;
|
||||
case 250: // CWD command successful.
|
||||
SendFTPLine("TYPE A");
|
||||
bIsAsciiMode = true;
|
||||
break;
|
||||
case 200: // Type set to A
|
||||
CheckNextCommand();
|
||||
break;
|
||||
case 226: // File successfully transferred
|
||||
case 150: // Opening ASCII mode data connection
|
||||
case 221: // Good-bye
|
||||
break;
|
||||
case 421: // No transfer timeout: closing control connection
|
||||
if( bFullVerbose )
|
||||
Level.Game.Broadcast(Self,"FTP: Connection timed out, reconnecting!");
|
||||
GoToState('EndConnection');
|
||||
break;
|
||||
case 221: // Good-bye
|
||||
Close();
|
||||
break;
|
||||
default:
|
||||
if( bFullVerbose )
|
||||
Level.Game.Broadcast(Self,"FTP: Unknown FTP code '"$Code$"': "$Line);
|
||||
Log("Unknown FTP code '"$Code$"': "$Line,Class.Name);
|
||||
}
|
||||
}
|
||||
function DataReceived();
|
||||
|
||||
function DataProgress()
|
||||
{
|
||||
SetTimer(60,false);
|
||||
}
|
||||
|
||||
final function bool OpenDataConnection( string S, bool bUpload )
|
||||
{
|
||||
local int i,j;
|
||||
local IpAddr A;
|
||||
|
||||
A = SiteAddress;
|
||||
|
||||
// Get destination port
|
||||
S = Mid(S,InStr(S,"(")+1);
|
||||
for( i=0; i<4; ++i ) // Skip IP address
|
||||
S = Mid(S,InStr(S,",")+1);
|
||||
i = InStr(S,",");
|
||||
A.Port = int(Left(S,i))*256 + int(Mid(S,i+1));
|
||||
|
||||
// Now attempt to bind port and open connection.
|
||||
for( j=0; j<20; ++j )
|
||||
{
|
||||
if( DataConnection!=None )
|
||||
DataConnection.Destroy();
|
||||
DataConnection = Spawn(Class'FTPDataConnection',Self);
|
||||
DataConnection.bUpload = bUpload;
|
||||
DataConnection.BindPort();
|
||||
if( DataConnection.Open(A) )
|
||||
{
|
||||
DataConnection.OnCompleted = DataReceived;
|
||||
DataConnection.OnProgress = DataProgress;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
DataConnection.Destroy();
|
||||
DataConnection = None;
|
||||
ReportError(2,"Couldn't bind port for upload data connection!");
|
||||
return false;
|
||||
}
|
||||
|
||||
function Timer()
|
||||
{
|
||||
ReportError(3,"FTP connection timed out!");
|
||||
}
|
||||
|
||||
state Idle
|
||||
{
|
||||
Ignores Timer;
|
||||
|
||||
final function StartConnection()
|
||||
{
|
||||
local int i;
|
||||
|
||||
for( i=0; i<40; ++i )
|
||||
{
|
||||
BindPort();
|
||||
if( Open(SiteAddress) )
|
||||
{
|
||||
GoToState('InitConnection');
|
||||
return;
|
||||
}
|
||||
}
|
||||
ReportError(4,"Port couldn't be bound or connection failed to open!");
|
||||
}
|
||||
function SaveAllStats()
|
||||
{
|
||||
Global.SaveAllStats();
|
||||
if( bUploadAllStats )
|
||||
StartConnection();
|
||||
}
|
||||
function RequestStats( ServerStStats Other )
|
||||
{
|
||||
Global.RequestStats(Other);
|
||||
StartConnection();
|
||||
}
|
||||
Begin:
|
||||
Sleep(0.1f);
|
||||
if( bUploadAllStats || PendingLoaders.Length>0 )
|
||||
StartConnection();
|
||||
}
|
||||
state InitConnection
|
||||
{
|
||||
function BeginState()
|
||||
{
|
||||
SetTimer(10,false);
|
||||
}
|
||||
event Closed()
|
||||
{
|
||||
ReportError(5,"Connection was closed by FTP server!");
|
||||
}
|
||||
Begin:
|
||||
Sleep(5.f);
|
||||
SendFTPLine("USER "$Mut.RemoteFTPUser);
|
||||
}
|
||||
state ConnectionBase
|
||||
{
|
||||
event Closed()
|
||||
{
|
||||
GoToState('Idle');
|
||||
}
|
||||
Begin:
|
||||
while( true )
|
||||
{
|
||||
if( bUploadAllStats && Level.bLevelChange ) // Delay mapchange until all stats are uploaded.
|
||||
Level.NextSwitchCountdown = FMax(Level.NextSwitchCountdown,1.f);
|
||||
Sleep(0.5);
|
||||
}
|
||||
}
|
||||
state EndConnection extends ConnectionBase
|
||||
{
|
||||
function BeginState()
|
||||
{
|
||||
SendFTPLine("QUIT");
|
||||
SetTimer(4,false);
|
||||
}
|
||||
}
|
||||
state KeepAlive extends ConnectionBase
|
||||
{
|
||||
Ignores Timer;
|
||||
|
||||
function SaveAllStats()
|
||||
{
|
||||
Global.SaveAllStats();
|
||||
if( bUploadAllStats )
|
||||
StartConnection();
|
||||
}
|
||||
function RequestStats( ServerStStats Other )
|
||||
{
|
||||
Global.RequestStats(Other);
|
||||
StartConnection();
|
||||
}
|
||||
final function StartConnection()
|
||||
{
|
||||
CheckNextCommand();
|
||||
}
|
||||
Begin:
|
||||
while( true )
|
||||
{
|
||||
if( bUploadAllStats || PendingLoaders.Length>0 )
|
||||
StartConnection();
|
||||
Sleep(Mut.FTPKeepAliveSec);
|
||||
SendFTPLine("NOOP");
|
||||
}
|
||||
}
|
||||
state UploadStats extends ConnectionBase
|
||||
{
|
||||
function BeginState()
|
||||
{
|
||||
bUploadAllStats = false;
|
||||
SetTimer(10,false);
|
||||
}
|
||||
function SaveAllStats();
|
||||
|
||||
final function InitDataConnection( string S )
|
||||
{
|
||||
if( bFullVerbose )
|
||||
Level.Game.Broadcast(Self,"FTP: Upload stats for "$ToSave[0].PlayerName$" ("$(ToSave.Length-1+TotalList.Length)$" remains)");
|
||||
if( OpenDataConnection(S,true) )
|
||||
{
|
||||
DataConnection.Data = ToSave[0].GetSaveData();
|
||||
TempFileName = ToSave[0].Name$".txt.tmp";
|
||||
SendFTPLine("STOR "$TempFileName);
|
||||
bFileInProgress = true;
|
||||
}
|
||||
}
|
||||
final function NextPackage()
|
||||
{
|
||||
RetryCounter = 0;
|
||||
ToSave[0].bStatsChanged = false;
|
||||
ToSave.Remove(0,1);
|
||||
if( ToSave.Length==0 )
|
||||
CheckNextCommand();
|
||||
else if( !bIsAsciiMode )
|
||||
{
|
||||
bIsAsciiMode = true;
|
||||
SendFTPLine("TYPE A");
|
||||
}
|
||||
else SendFTPLine("PASV");
|
||||
}
|
||||
function ProcessResponse( int Code, string Line )
|
||||
{
|
||||
switch( Code )
|
||||
{
|
||||
case 200: // Type set to A/I
|
||||
if( bPostUploadCheck )
|
||||
{
|
||||
SetTimer(5,false);
|
||||
SendFTPLine("SIZE "$TempFileName);
|
||||
}
|
||||
else SendFTPLine("PASV");
|
||||
break;
|
||||
case 227: // Entering passive mode
|
||||
if( !bFileInProgress )
|
||||
InitDataConnection(Line);
|
||||
break;
|
||||
case 150: // Opening ASCII mode data connection for file
|
||||
SetTimer(60,false);
|
||||
if( DataConnection!=None )
|
||||
DataConnection.BeginUpload();
|
||||
break;
|
||||
case 226: // File transfer completed.
|
||||
if( bFileInProgress )
|
||||
{
|
||||
SetTimer(5,false);
|
||||
bFileInProgress = false;
|
||||
bPostUploadCheck = true;
|
||||
SendFTPLine("TYPE I");
|
||||
bIsAsciiMode = false;
|
||||
}
|
||||
break;
|
||||
case 213: // File size response.
|
||||
if( bPostUploadCheck )
|
||||
{
|
||||
SetTimer(5,false);
|
||||
if( int(Line)<=5 )
|
||||
{
|
||||
bPostUploadCheck = false;
|
||||
if( ++RetryCounter>=5 )
|
||||
NextPackage();
|
||||
else
|
||||
{
|
||||
if( bFullVerbose )
|
||||
Level.Game.Broadcast(Self,"213 FTP Error: Stats upload failed for "$ToSave[0].PlayerName$" retrying...");
|
||||
SendFTPLine("PASV");
|
||||
}
|
||||
}
|
||||
else SendFTPLine("RNFR "$TempFileName);
|
||||
}
|
||||
break;
|
||||
case 350: // Rename accepted.
|
||||
if( bPostUploadCheck )
|
||||
{
|
||||
SetTimer(5,false);
|
||||
SendFTPLine("RNTO "$Left(TempFileName,Len(TempFileName)-4));
|
||||
}
|
||||
break;
|
||||
case 250: // File successfully renamed or moved
|
||||
NextPackage();
|
||||
break;
|
||||
case 550: // Sorry, but that file doesn't exist
|
||||
if( bPostUploadCheck )
|
||||
{
|
||||
SetTimer(5,false);
|
||||
bPostUploadCheck = false;
|
||||
if( ++RetryCounter>=5 )
|
||||
NextPackage();
|
||||
else
|
||||
{
|
||||
if( bFullVerbose )
|
||||
Level.Game.Broadcast(Self,"550 FTP Error: Stats upload failed for "$ToSave[0].PlayerName$" retrying...");
|
||||
SendFTPLine("PASV");
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Global.ProcessResponse(Code,Line);
|
||||
}
|
||||
}
|
||||
Begin:
|
||||
if( !bIsAsciiMode )
|
||||
{
|
||||
SendFTPLine("TYPE A");
|
||||
bIsAsciiMode = true;
|
||||
}
|
||||
else SendFTPLine("PASV");
|
||||
while( true )
|
||||
{
|
||||
if( Level.bLevelChange ) // Delay mapchange until all stats are uploaded.
|
||||
{
|
||||
bFullVerbose = true;
|
||||
Level.NextSwitchCountdown = FMax(Level.NextSwitchCountdown,1.f);
|
||||
}
|
||||
Sleep(0.5);
|
||||
}
|
||||
}
|
||||
state DownloadStats extends ConnectionBase
|
||||
{
|
||||
function BeginState()
|
||||
{
|
||||
SetTimer(10,false);
|
||||
}
|
||||
final function InitDataConnection( string S )
|
||||
{
|
||||
while( PendingLoaders.Length>0 && PendingLoaders[0]==None )
|
||||
PendingLoaders.Remove(0,1);
|
||||
if( PendingLoaders.Length==0 )
|
||||
{
|
||||
CheckNextCommand();
|
||||
return;
|
||||
}
|
||||
|
||||
if( bFullVerbose )
|
||||
Level.Game.Broadcast(Self,"FTP: Download stats for "$PendingLoaders[0].MyStatsObject.PlayerName$" ("$(PendingLoaders.Length-1)$" remains)");
|
||||
|
||||
if( OpenDataConnection(S,false) )
|
||||
{
|
||||
SendFTPLine("RETR "$PendingLoaders[0].MyStatsObject.Name$".txt");
|
||||
bFileInProgress = true;
|
||||
}
|
||||
}
|
||||
function DataReceived()
|
||||
{
|
||||
bFileInProgress = false;
|
||||
if( PendingLoaders[0]!=None )
|
||||
{
|
||||
if( DataConnection!=None )
|
||||
PendingLoaders[0].GetData(DataConnection.Data);
|
||||
else PendingLoaders[0].GetData("");
|
||||
}
|
||||
PendingLoaders.Remove(0,1);
|
||||
while( PendingLoaders.Length>0 && PendingLoaders[0]==None )
|
||||
PendingLoaders.Remove(0,1);
|
||||
|
||||
if( bUploadAllStats ) // Saving has higher priority.
|
||||
GoToState('UploadStats');
|
||||
else if( PendingLoaders.Length>0 )
|
||||
SendFTPLine("PASV");
|
||||
else CheckNextCommand();
|
||||
}
|
||||
function ProcessResponse( int Code, string Line )
|
||||
{
|
||||
switch( Code )
|
||||
{
|
||||
case 200: // Type set to A
|
||||
SendFTPLine("PASV");
|
||||
break;
|
||||
case 227: // Entering passive mode
|
||||
if( !bFileInProgress )
|
||||
InitDataConnection(Line);
|
||||
break;
|
||||
case 150: // Opening ASCII mode data connection for file
|
||||
SetTimer(60,false);
|
||||
break;
|
||||
case 550: // No such file or directory
|
||||
SetTimer(10,false);
|
||||
if( bFileInProgress )
|
||||
{
|
||||
if( DataConnection!=None )
|
||||
DataConnection.Destroy();
|
||||
DataReceived();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Global.ProcessResponse(Code,Line);
|
||||
}
|
||||
}
|
||||
Begin:
|
||||
if( !bIsAsciiMode )
|
||||
{
|
||||
bIsAsciiMode = true;
|
||||
SendFTPLine("TYPE A");
|
||||
}
|
||||
else SendFTPLine("PASV");
|
||||
while( true )
|
||||
{
|
||||
if( bUploadAllStats && Level.bLevelChange ) // Delay mapchange until all stats are uploaded.
|
||||
{
|
||||
bFullVerbose = true;
|
||||
Level.NextSwitchCountdown = FMax(Level.NextSwitchCountdown,1.f);
|
||||
}
|
||||
Sleep(0.5);
|
||||
}
|
||||
}
|
||||
state ErrorState
|
||||
{
|
||||
Ignores SaveAllStats,RequestStats;
|
||||
Begin:
|
||||
Sleep(1.f);
|
||||
Mut.RespawnNetworkLink();
|
||||
}
|
||||
|
||||
static final function int GetDateInt( int Day, int Month, int Year )
|
||||
{
|
||||
return Day + (Month*31) + (Year*366);
|
||||
}
|
||||
state GetDir
|
||||
{
|
||||
function BeginState()
|
||||
{
|
||||
SendFTPLine("TYPE I");
|
||||
bObtainDir = false;
|
||||
}
|
||||
final function BeginPassiveCon( string S )
|
||||
{
|
||||
if( bFullVerbose )
|
||||
Level.Game.Broadcast(Self,"FTP: Get directory");
|
||||
|
||||
if( OpenDataConnection(S,false) )
|
||||
SendFTPLine("MLSD");
|
||||
}
|
||||
function DataReceived()
|
||||
{
|
||||
local array<string> SA;
|
||||
local string S;
|
||||
local int i,j,Da,Mo,Ye,ol;
|
||||
|
||||
if( DataConnection!=None )
|
||||
{
|
||||
Split(DataConnection.Data,Chr(13)$Chr(10),SA);
|
||||
ol = TotalList.Length;
|
||||
for( i=0; i<SA.Length; ++i )
|
||||
{
|
||||
S = SA[i];
|
||||
j = InStr(S,"modify=");
|
||||
if( j==-1 )
|
||||
continue;
|
||||
S = Mid(S,j+7);
|
||||
j = InStr(S,";");
|
||||
if( j==-1 )
|
||||
continue;
|
||||
Ye = int(Mid(S,0,4));
|
||||
Mo = int(Mid(S,4,2));
|
||||
Da = int(Mid(S,6,2));
|
||||
j = InStr(S," ");
|
||||
if( j==-1 )
|
||||
continue;
|
||||
S = Mid(S,j+1);
|
||||
if( Right(S,4)!=".txt" )
|
||||
continue;
|
||||
if( IgnoreDateNum<=GetDateInt(Da,Mo,Ye) )
|
||||
Log(S@"is newer: "$Da$"."$Mo$"."$Ye);
|
||||
else
|
||||
{
|
||||
S = Left(S,Len(S)-4);
|
||||
for( j=0; j<TotalList.Length; ++j )
|
||||
if( TotalList[j]==S )
|
||||
{
|
||||
TotalList.Remove(j,1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Level.Game.Broadcast(Self,"Reduced list size: "$ol$" -> "$TotalList.Length);
|
||||
}
|
||||
CheckNextCommand();
|
||||
}
|
||||
function ProcessResponse( int Code, string Line )
|
||||
{
|
||||
switch( Code )
|
||||
{
|
||||
case 200: // Type set to I
|
||||
bIsAsciiMode = false;
|
||||
SendFTPLine("PASV");
|
||||
break;
|
||||
case 227: // Entering passive mode
|
||||
BeginPassiveCon(Line);
|
||||
break;
|
||||
case 150: // Opening ASCII mode data connection for file
|
||||
SetTimer(120,false);
|
||||
break;
|
||||
case 550: // No such file or directory
|
||||
SetTimer(10,false);
|
||||
if( bFileInProgress )
|
||||
{
|
||||
if( DataConnection!=None )
|
||||
DataConnection.Destroy();
|
||||
DataReceived();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Global.ProcessResponse(Code,Line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
}
|
||||
18
kf_sources/ServerPerksMut/Classes/FragFireFix.uc
Normal file
18
kf_sources/ServerPerksMut/Classes/FragFireFix.uc
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
class FragFireFix extends FragFire;
|
||||
|
||||
var float PrevAmmo;
|
||||
|
||||
function DoFireEffect()
|
||||
{
|
||||
local float MaxAmmo,CurAmmo;
|
||||
|
||||
Weapon.GetAmmoCount(MaxAmmo,CurAmmo);
|
||||
if (CurAmmo==0 && PrevAmmo==0)
|
||||
return;
|
||||
PrevAmmo=CurAmmo;
|
||||
Super.DoFireEffect();
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
}
|
||||
57
kf_sources/ServerPerksMut/Classes/SRGameRules.uc
Normal file
57
kf_sources/ServerPerksMut/Classes/SRGameRules.uc
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
//=============================================================================
|
||||
// SRGameRules
|
||||
//=============================================================================
|
||||
class SRGameRules extends GameRules;
|
||||
|
||||
function PostBeginPlay()
|
||||
{
|
||||
if( Level.Game.GameRulesModifiers==None )
|
||||
Level.Game.GameRulesModifiers = Self;
|
||||
else Level.Game.GameRulesModifiers.AddGameRules(Self);
|
||||
}
|
||||
|
||||
function AddGameRules(GameRules GR)
|
||||
{
|
||||
if ( GR!=Self )
|
||||
Super.AddGameRules(GR);
|
||||
}
|
||||
|
||||
function bool PreventDeath(Pawn Killed, Controller Killer, class<DamageType> damageType, vector HitLocation)
|
||||
{
|
||||
local ClientPerkRepLink R;
|
||||
local SRCustomProgress S;
|
||||
|
||||
if ( (NextGameRules != None) && NextGameRules.PreventDeath(Killed,Killer, damageType,HitLocation) )
|
||||
return true;
|
||||
|
||||
if( xPlayer(Killer)!=None && Killed.Controller!=None && Killed.Controller!=Killer )
|
||||
{
|
||||
R = FindStatsFor(Killer);
|
||||
if( R!=None )
|
||||
for( S=R.CustomLink; S!=None; S=S.NextLink )
|
||||
S.NotifyPlayerKill(Killed,damageType);
|
||||
}
|
||||
if( xPlayer(Killed.Controller)!=None && Killer!=None && Killer.Pawn!=None )
|
||||
{
|
||||
R = FindStatsFor(Killed.Controller);
|
||||
if( R!=None )
|
||||
for( S=R.CustomLink; S!=None; S=S.NextLink )
|
||||
S.NotifyPlayerKilled(Killer.Pawn,damageType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
static final function ClientPerkRepLink FindStatsFor( Controller C )
|
||||
{
|
||||
local LinkedReplicationInfo L;
|
||||
|
||||
if( C.PlayerReplicationInfo==None )
|
||||
return None;
|
||||
for( L=C.PlayerReplicationInfo.CustomReplicationInfo; L!=None; L=L.NextReplicationInfo )
|
||||
if( ClientPerkRepLink(L)!=None )
|
||||
return ClientPerkRepLink(L);
|
||||
return None;
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
}
|
||||
279
kf_sources/ServerPerksMut/Classes/ServerPerkWebAdmin.uc
Normal file
279
kf_sources/ServerPerksMut/Classes/ServerPerkWebAdmin.uc
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
ServerPerks webadmin interface
|
||||
*/
|
||||
class ServerPerkWebAdmin extends xWebQueryHandler;
|
||||
|
||||
var ServerPerksMut Mut;
|
||||
var string HomeURL,PerksURL,TraderCatURL,TraderInvURL;
|
||||
|
||||
function bool Init()
|
||||
{
|
||||
foreach Level.AllActors( class'ServerPerksMut', Mut )
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
function Cleanup()
|
||||
{
|
||||
Mut = None;
|
||||
}
|
||||
|
||||
function bool Query(WebRequest Request, WebResponse Response)
|
||||
{
|
||||
switch (Mid(Request.URI, 1))
|
||||
{
|
||||
case DefaultPage:
|
||||
RequestFrame(Request, Response);
|
||||
return true;
|
||||
case HomeURL:
|
||||
RequestMain(Request, Response);
|
||||
return true;
|
||||
case PerksURL:
|
||||
RequestPerks(Request, Response);
|
||||
return true;
|
||||
case TraderCatURL:
|
||||
TradetCat(Request, Response);
|
||||
return true;
|
||||
case TraderInvURL:
|
||||
RequestInventory(Request, Response);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function RequestFrame(WebRequest Request, WebResponse Response)
|
||||
{
|
||||
Response.SendText("<html><head><title>SP</title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\"></head>");
|
||||
Response.SendText("<frameset cols=\"*\" rows=\"*\" border=\"0\" scrolling=\"No\" frameborder=\"no\" noresize framespacing=\"0\" marginheight=\"0\">");
|
||||
Response.SendText("<frame src=\""$HomeURL$"\" name=\"main\" border=\"0\" frameborder=\"no\" noresize framespacing=\"0\" marginheight=\"0\"></frameset>");
|
||||
Response.SendText("<noframes><body bgcolor=\"#FFFFFF\"></body></noframes></html>");
|
||||
}
|
||||
|
||||
final function SendHeader( WebResponse Response, optional bool bNoSettings )
|
||||
{
|
||||
Response.SendText("<html><head><title>SP</title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\"><link rel=\"stylesheet\" type=\"text/css\" href=\""$SiteCSSFile$"\"></head><body bgcolor=\""$SiteBG$"\" topmargin=\"0\" leftmargin=\"0\" marginheight=\"0\" marginwidth=\"0\"><body><div align=\"center\"><table cellpadding=\"1\" cellspacing=\"2\" style=\"width:600px\">");
|
||||
if( !bNoSettings )
|
||||
Response.SendText("<form method=\"post\">");
|
||||
}
|
||||
final function SendSubmitButton( WebResponse Response )
|
||||
{
|
||||
Response.SendText("<tr><td colspan=\"2\"><input type=\"submit\" name=\"submit\" value=\"Submit\" class=\"button\"></td></tr></form>");
|
||||
}
|
||||
final function SendFooter( WebResponse Response )
|
||||
{
|
||||
Response.SendText("</table></div></body></html>");
|
||||
}
|
||||
final function SendHeaderLine( WebResponse Response, string S )
|
||||
{
|
||||
Response.SendText("<tr><th colspan=\"2\">"$S$"</th></tr>");
|
||||
}
|
||||
final function SendURLLine( WebResponse Response, string URL, string DisplayStr )
|
||||
{
|
||||
Response.SendText("<tr><td colspan=\"2\"><a href=\""$URL$"\">"$DisplayStr$"</a></td></tr>");
|
||||
}
|
||||
final function SendTableLine( WebResponse Response, string S )
|
||||
{
|
||||
Response.SendText("<tr>"$S$"</tr>");
|
||||
}
|
||||
|
||||
function RequestMain(WebRequest Request, WebResponse Response)
|
||||
{
|
||||
SendHeader(Response,true);
|
||||
SendHeaderLine(Response,"ServerPerks settings");
|
||||
SendURLLine(Response,PerksURL,"Edit perk classes");
|
||||
SendURLLine(Response,TraderCatURL,"Edit trader categories");
|
||||
SendURLLine(Response,TraderInvURL,"Edit trader inventory");
|
||||
SendFooter(Response);
|
||||
}
|
||||
function RequestPerks(WebRequest Request, WebResponse Response)
|
||||
{
|
||||
local string S,Er;
|
||||
local array<string> PA;
|
||||
local int i,j;
|
||||
local class<SRVeterancyTypes> VC;
|
||||
|
||||
// Process response.
|
||||
if( Request.GetVariable("submit") == "Submit" )
|
||||
{
|
||||
S = Request.GetVariable("Perks", "");
|
||||
if( S!="" )
|
||||
{
|
||||
Split(S,Chr(13)$Chr(10),PA);
|
||||
if( PA.Length<=1 )
|
||||
{
|
||||
PA.Length = 0;
|
||||
Split(S,Chr(10),PA);
|
||||
}
|
||||
Class'ServerPerksMut'.Default.Perks.Length = 0;
|
||||
for( i=0; i<PA.Length; ++i )
|
||||
{
|
||||
VC = class<SRVeterancyTypes>(DynamicLoadObject(PA[i],Class'Class'));
|
||||
if( VC!=None )
|
||||
{
|
||||
Class'ServerPerksMut'.Default.Perks.Length = j+1;
|
||||
Class'ServerPerksMut'.Default.Perks[j++] = string(VC);
|
||||
}
|
||||
else if( Er=="" )
|
||||
Er = PA[i];
|
||||
else Er $= ", "$PA[i];
|
||||
}
|
||||
Class'ServerPerksMut'.Static.StaticSaveConfig();
|
||||
}
|
||||
}
|
||||
|
||||
SendHeader(Response);
|
||||
SendHeaderLine(Response,"Perk classes:");
|
||||
if( Er!="" )
|
||||
SendHeaderLine(Response,"<font color=\"red\">[Warning] Perk classes failed to load:<BR>"$Er$"</font>");
|
||||
|
||||
// Send perk list
|
||||
for( i=0; i<Class'ServerPerksMut'.Default.Perks.Length; ++i )
|
||||
{
|
||||
if( i==0 )
|
||||
S = Class'ServerPerksMut'.Default.Perks[0];
|
||||
else S = S$Chr(10)$Class'ServerPerksMut'.Default.Perks[i];
|
||||
}
|
||||
SendTableLine(Response,"<td colspan=\"3\"><textarea name=\"Perks\" rows=\"25\" cols=\"80\">"$S$"</textarea></td>");
|
||||
|
||||
SendSubmitButton(Response);
|
||||
SendURLLine(Response,HomeURL,"Return to home");
|
||||
SendFooter(Response);
|
||||
}
|
||||
function TradetCat(WebRequest Request, WebResponse Response)
|
||||
{
|
||||
local string S,D,A,B;
|
||||
local int i,j;
|
||||
|
||||
// Process response.
|
||||
if( Request.GetVariable("submit") == "Submit" )
|
||||
{
|
||||
for( i=Class'ServerPerksMut'.Default.WeaponCategories.Length; i>=0; --i )
|
||||
{
|
||||
j = int(Request.GetVariable("WI"$i, "-2"));
|
||||
if( j==-2 )
|
||||
continue;
|
||||
S = Request.GetVariable("WC"$i, "");
|
||||
|
||||
if( S=="" || S=="NEW" )
|
||||
{
|
||||
if( i<Class'ServerPerksMut'.Default.WeaponCategories.Length )
|
||||
Class'ServerPerksMut'.Default.WeaponCategories.Remove(i,1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( j>=0 )
|
||||
S = string(j)$":"$S;
|
||||
if( i>=Class'ServerPerksMut'.Default.WeaponCategories.Length )
|
||||
Class'ServerPerksMut'.Default.WeaponCategories.Length = i+1;
|
||||
Class'ServerPerksMut'.Default.WeaponCategories[i] = S;
|
||||
}
|
||||
}
|
||||
Class'ServerPerksMut'.Static.StaticSaveConfig();
|
||||
}
|
||||
|
||||
SendHeader(Response);
|
||||
SendHeaderLine(Response,"Trader categories:");
|
||||
|
||||
// gather perks
|
||||
D = " ><option value=\"-1\">None</option>";
|
||||
for( i=0; i<Class'ServerPerksMut'.Default.Perks.Length; ++i )
|
||||
D = D$"<option value=\""$i$"\">"$Class'ServerPerksMut'.Default.Perks[i]$"</option>";
|
||||
D $= "<option value=\""$i$"\">Unperked</option></select>";
|
||||
|
||||
// categories
|
||||
Response.SendText("<tr>"$S$"</tr>");
|
||||
for( i=0; i<=Class'ServerPerksMut'.Default.WeaponCategories.Length; ++i )
|
||||
{
|
||||
S = "<tr><td><select class=\"mini\" name=\"WI"$i$"\""$D;
|
||||
if( i==Class'ServerPerksMut'.Default.WeaponCategories.Length )
|
||||
B = "NEW";
|
||||
else
|
||||
{
|
||||
if( Divide(Class'ServerPerksMut'.Default.WeaponCategories[i],":",A,B) )
|
||||
{
|
||||
j = int(A);
|
||||
if( j<Class'ServerPerksMut'.Default.Perks.Length )
|
||||
A = ">"$Class'ServerPerksMut'.Default.Perks[j]$"<";
|
||||
else A = ">Unperked<";
|
||||
S = Repl(S,A," selected=\"selected\""$A); // Shitty hack.
|
||||
}
|
||||
else B = Class'ServerPerksMut'.Default.WeaponCategories[i];
|
||||
}
|
||||
S $= "</td><td><input class=\"textbox\" type=\"text\" name=\"WC"$i$"\" value=\""$B$"\" size=\"16\" maxlength=\"32\">";
|
||||
Response.SendText(S$"</td></tr>");
|
||||
}
|
||||
|
||||
SendSubmitButton(Response);
|
||||
SendURLLine(Response,HomeURL,"Return to home");
|
||||
SendFooter(Response);
|
||||
}
|
||||
function RequestInventory(WebRequest Request, WebResponse Response)
|
||||
{
|
||||
local string S,Er,A,B;
|
||||
local array<string> PA;
|
||||
local int i,j;
|
||||
local class<Pickup> PC;
|
||||
|
||||
// Process response.
|
||||
if( Request.GetVariable("submit") == "Submit" )
|
||||
{
|
||||
S = Request.GetVariable("Inv", "");
|
||||
if( S!="" )
|
||||
{
|
||||
Split(S,Chr(13)$Chr(10),PA);
|
||||
if( PA.Length<=1 )
|
||||
{
|
||||
PA.Length = 0;
|
||||
Split(S,Chr(10),PA);
|
||||
}
|
||||
Class'ServerPerksMut'.Default.TraderInventory.Length = 0;
|
||||
for( i=0; i<PA.Length; ++i )
|
||||
{
|
||||
if( !Divide(PA[i],":",A,B) )
|
||||
{
|
||||
A = "";
|
||||
B = PA[i];
|
||||
}
|
||||
else A $= ":";
|
||||
|
||||
PC = class<Pickup>(DynamicLoadObject(B,Class'Class'));
|
||||
if( PC!=None )
|
||||
{
|
||||
Class'ServerPerksMut'.Default.TraderInventory.Length = j+1;
|
||||
Class'ServerPerksMut'.Default.TraderInventory[j++] = A$string(PC);
|
||||
}
|
||||
else if( Er=="" )
|
||||
Er = PA[i];
|
||||
else Er $= ", "$PA[i];
|
||||
}
|
||||
Class'ServerPerksMut'.Static.StaticSaveConfig();
|
||||
}
|
||||
}
|
||||
|
||||
SendHeader(Response);
|
||||
SendHeaderLine(Response,"Inventory classes:");
|
||||
if( Er!="" )
|
||||
SendHeaderLine(Response,"<font color=\"red\">[Warning] Pickup classes failed to load:<BR>"$Er$"</font>");
|
||||
|
||||
// Send perk list
|
||||
for( i=0; i<Class'ServerPerksMut'.Default.TraderInventory.Length; ++i )
|
||||
{
|
||||
if( i==0 )
|
||||
S = Class'ServerPerksMut'.Default.TraderInventory[0];
|
||||
else S = S$Chr(10)$Class'ServerPerksMut'.Default.TraderInventory[i];
|
||||
}
|
||||
SendTableLine(Response,"<td colspan=\"3\"><textarea name=\"Inv\" rows=\"25\" cols=\"80\">"$S$"</textarea></td>");
|
||||
|
||||
SendSubmitButton(Response);
|
||||
SendURLLine(Response,HomeURL,"Return to home");
|
||||
SendFooter(Response);
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
HomeURL="ServerPerkMain"
|
||||
PerksURL="ServerPerksPerks"
|
||||
TraderCatURL="ServerPerksTraderCat"
|
||||
TraderInvURL="ServerPerksTraderInv"
|
||||
DefaultPage="ServerPerkWebAdmin"
|
||||
Title="Server Perks"
|
||||
}
|
||||
829
kf_sources/ServerPerksMut/Classes/ServerPerksMut.uc
Normal file
829
kf_sources/ServerPerksMut/Classes/ServerPerksMut.uc
Normal file
|
|
@ -0,0 +1,829 @@
|
|||
// Written by .:..: (2009)
|
||||
Class ServerPerksMut extends Mutator
|
||||
Config(ServerPerks);
|
||||
|
||||
struct ChatIconType
|
||||
{
|
||||
var() config string IconTexture,IconTag;
|
||||
var() config bool bCaseInsensitive;
|
||||
};
|
||||
var() globalconfig array<string> Perks,TraderInventory,WeaponCategories,CustomCharacters;
|
||||
var() globalconfig int MinPerksLevel,MaxPerksLevel,RemotePort,MidGameSaveWaves,FTPKeepAliveSec;
|
||||
var() globalconfig float RequirementScaling;
|
||||
var() globalconfig string RemoteDatabaseURL,RemotePassword,RemoteFTPUser,RemoteFTPDir,ServerNewsURL,FTPUploadAllIgnoreDate;
|
||||
var() globalconfig array<ChatIconType> SmileyTags;
|
||||
|
||||
var array<ClientPerkRepLink.FShopCategoryIndex> LoadedCategories;
|
||||
var array<byte> LoadInvCategory;
|
||||
var array< class<SRVeterancyTypes> > LoadPerks;
|
||||
var array< class<Pickup> > LoadInventory;
|
||||
var const int VersionNumber;
|
||||
var array<PlayerController> PendingPlayers;
|
||||
var array<StatsObject> ActiveStats;
|
||||
var localized string ServerPerksGroup;
|
||||
var transient InternetLink Link;
|
||||
var KFGameType KFGT;
|
||||
var int LastSavedWave,WaveCounter;
|
||||
var SRGameRules RulesMod;
|
||||
var transient array<name> AddedServerPackages;
|
||||
var transient float NextCheckTimer;
|
||||
var array<SRHUDKillingFloor.SmileyMessageType> SmileyMsgs;
|
||||
var class<Object> SRScoreboardType,SRHudType,SRMenuType;
|
||||
var class<PlayerController> SRControllerType;
|
||||
|
||||
var() globalconfig bool bUploadAllStats,bForceGivePerk,bNoSavingProgress,bUseRemoteDatabase,bUsePlayerNameAsID,bMessageAnyPlayerLevelUp,bNoPerkChanges
|
||||
,bUseLowestRequirements,bBWZEDTime,bUseEnhancedScoreboard,bOverrideUnusedCustomStats,bAllowAlwaysPerkChanges,bEnableWebAdmin
|
||||
,bForceCustomChars,bEnableChatIcons,bEnhancedShoulderView,bFixGrenadeExploit,bAdminEditStats,bUseFTPLink,bDebugDatabase;
|
||||
var bool bEnabledEmoIcons;
|
||||
|
||||
function PostBeginPlay()
|
||||
{
|
||||
local int i,j;
|
||||
local class<SRVeterancyTypes> V;
|
||||
local class<Pickup> P;
|
||||
local string S;
|
||||
local byte Cat;
|
||||
local class<PlayerRecordClass> PR;
|
||||
local Texture T;
|
||||
local KFLevelRules R;
|
||||
|
||||
if( RulesMod==None )
|
||||
RulesMod = Spawn(Class'SRGameRules');
|
||||
|
||||
KFGT = KFGameType(Level.Game);
|
||||
if( Level.Game.HUDType~=Class'KFGameType'.Default.HUDType || Level.Game.HUDType~=Class'KFStoryGameInfo'.Default.HUDType )
|
||||
{
|
||||
bEnabledEmoIcons = bEnableChatIcons;
|
||||
Level.Game.HUDType = string(SRHudType);
|
||||
}
|
||||
|
||||
if( bUseEnhancedScoreboard && (Level.Game.ScoreBoardType~=Class'KFGameType'.Default.ScoreBoardType || Level.Game.ScoreBoardType~=Class'KFStoryGameInfo'.Default.ScoreBoardType) )
|
||||
Level.Game.ScoreBoardType = string(SRScoreboardType);
|
||||
|
||||
// Use own playercontroller class for security reasons.
|
||||
if( Level.Game.PlayerControllerClass==Class'KFPlayerController' || Level.Game.PlayerControllerClass==Class'KFPlayerController_Story' )
|
||||
{
|
||||
Level.Game.PlayerControllerClass = SRControllerType;
|
||||
Level.Game.PlayerControllerClassName = string(SRControllerType);
|
||||
}
|
||||
DeathMatch(Level.Game).LoginMenuClass = string(SRMenuType);
|
||||
|
||||
// Load perks.
|
||||
for( i=0; i<Perks.Length; i++ )
|
||||
{
|
||||
V = class<SRVeterancyTypes>(DynamicLoadObject(Perks[i],Class'Class'));
|
||||
if( V!=None )
|
||||
{
|
||||
LoadPerks[LoadPerks.Length] = V;
|
||||
ImplementPackage(V);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup categories
|
||||
LoadedCategories.Length = WeaponCategories.Length;
|
||||
for( i=0; i<WeaponCategories.Length; ++i )
|
||||
{
|
||||
S = WeaponCategories[i];
|
||||
j = InStr(S,":");
|
||||
if( j==-1 )
|
||||
{
|
||||
LoadedCategories[i].Name = S;
|
||||
LoadedCategories[i].PerkIndex = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadedCategories[i].Name = Mid(S,j+1);
|
||||
LoadedCategories[i].PerkIndex = int(Left(S,j));
|
||||
}
|
||||
}
|
||||
if( LoadedCategories.Length==0 )
|
||||
{
|
||||
LoadedCategories.Length = 1;
|
||||
LoadedCategories[0].Name = "All";
|
||||
LoadedCategories[0].PerkIndex = 255;
|
||||
}
|
||||
|
||||
// Init rules
|
||||
foreach AllActors(class'KFLevelRules',R)
|
||||
break;
|
||||
if( R==None && KFGT!=None )
|
||||
{
|
||||
R = KFGT.KFLRules;
|
||||
if( R==None )
|
||||
{
|
||||
R = Spawn(class'KFLevelRules');
|
||||
KFGT.KFLRules = R;
|
||||
}
|
||||
}
|
||||
if( R!=None )
|
||||
{
|
||||
// Empty all stock weapons first.
|
||||
R.MediItemForSale.Length = 0;
|
||||
R.SuppItemForSale.Length = 0;
|
||||
R.ShrpItemForSale.Length = 0;
|
||||
R.CommItemForSale.Length = 0;
|
||||
R.BersItemForSale.Length = 0;
|
||||
R.FireItemForSale.Length = 0;
|
||||
R.DemoItemForSale.Length = 0;
|
||||
R.NeutItemForSale.Length = 0;
|
||||
}
|
||||
|
||||
// Load up trader inventory.
|
||||
for( i=0; i<TraderInventory.Length; i++ )
|
||||
{
|
||||
S = TraderInventory[i];
|
||||
j = InStr(S,":");
|
||||
if( j>0 )
|
||||
{
|
||||
Cat = Min(int(Left(S,j)),LoadedCategories.Length-1);
|
||||
S = Mid(S,j+1);
|
||||
}
|
||||
else Cat = 0;
|
||||
P = class<Pickup>(DynamicLoadObject(S,Class'Class'));
|
||||
if( P!=None )
|
||||
{
|
||||
// Inform bots.
|
||||
if( R!=None )
|
||||
R.MediItemForSale[R.MediItemForSale.Length] = P;
|
||||
|
||||
LoadInventory[LoadInventory.Length] = P;
|
||||
LoadInvCategory[LoadInvCategory.Length] = Cat;
|
||||
if( P.Outer.Name!='KFMod' )
|
||||
ImplementPackage(P);
|
||||
}
|
||||
}
|
||||
|
||||
// Load custom chars.
|
||||
for( i=0; i<CustomCharacters.Length; ++i )
|
||||
{
|
||||
// Separate group from actual skin.
|
||||
S = CustomCharacters[i];
|
||||
j = InStr(S,":");
|
||||
if( j>=0 )
|
||||
S = Mid(S,j+1);
|
||||
PR = class<PlayerRecordClass>(DynamicLoadObject(S$"Mod."$S,class'Class',true));
|
||||
if( PR!=None )
|
||||
{
|
||||
if( PR.Default.MeshName!="" ) // Add mesh package.
|
||||
ImplementPackage(DynamicLoadObject(PR.Default.MeshName,class'Mesh',true));
|
||||
if( PR.Default.BodySkinName!="" ) // Add skin package.
|
||||
ImplementPackage(DynamicLoadObject(PR.Default.BodySkinName,class'Material',true));
|
||||
ImplementPackage(PR);
|
||||
}
|
||||
}
|
||||
|
||||
// Load chat icons
|
||||
if( bEnabledEmoIcons )
|
||||
{
|
||||
j = 0;
|
||||
for( i=0; i<SmileyTags.Length; ++i )
|
||||
{
|
||||
if( SmileyTags[i].IconTexture=="" || SmileyTags[i].IconTag=="" )
|
||||
continue;
|
||||
T = Texture(DynamicLoadObject(SmileyTags[i].IconTexture,class'Texture',true));
|
||||
if( T==None )
|
||||
continue;
|
||||
ImplementPackage(T);
|
||||
SmileyMsgs.Length = j+1;
|
||||
SmileyMsgs[j].SmileyTex = T;
|
||||
if( SmileyTags[i].bCaseInsensitive )
|
||||
SmileyMsgs[j].SmileyTag = Caps(SmileyTags[i].IconTag);
|
||||
else SmileyMsgs[j].SmileyTag = SmileyTags[i].IconTag;
|
||||
SmileyMsgs[j].bInCAPS = SmileyTags[i].bCaseInsensitive;
|
||||
++j;
|
||||
}
|
||||
bEnabledEmoIcons = (j!=0);
|
||||
}
|
||||
|
||||
Log("Adding"@AddedServerPackages.Length@"additional serverpackages",Class.Outer.Name);
|
||||
for( i=0; i<AddedServerPackages.Length; i++ )
|
||||
AddToPackageMap(string(AddedServerPackages[i]));
|
||||
AddedServerPackages.Length = 0;
|
||||
|
||||
if( bUseEnhancedScoreboard || (Level.Game.HUDType~=string(SRHudType)) )
|
||||
AddToPackageMap("CountryFlagsTex");
|
||||
|
||||
if( bFixGrenadeExploit )
|
||||
Class'Frag'.Default.FireModeClass[0] = Class'FragFireFix';
|
||||
|
||||
if( bUseRemoteDatabase )
|
||||
{
|
||||
Log("Using remote database:"@RemoteDatabaseURL$":"$RemotePort,Class.Outer.Name);
|
||||
RespawnNetworkLink();
|
||||
}
|
||||
}
|
||||
|
||||
function Tick( float Delta )
|
||||
{
|
||||
Disable('Tick');
|
||||
if( bEnableWebAdmin && Level.NetMode!=NM_StandAlone )
|
||||
InitWebServer();
|
||||
}
|
||||
function InitWebServer()
|
||||
{
|
||||
local WebServer W;
|
||||
local int i;
|
||||
local UTServerAdmin U;
|
||||
|
||||
// Must increase the limit size.
|
||||
class'WebConnection'.default.MaxValueLength = Max(class'WebConnection'.default.MaxValueLength,9999);
|
||||
class'WebConnection'.default.MaxLineLength = Max(class'WebConnection'.default.MaxLineLength,10100);
|
||||
|
||||
foreach DynamicActors(class'WebServer',W)
|
||||
{
|
||||
for( i=0; i<10; ++i )
|
||||
{
|
||||
U = UTServerAdmin(W.ApplicationObjects[i]);
|
||||
if( U!=None )
|
||||
{
|
||||
for( i=0; i<U.QueryHandlers.Length; ++i )
|
||||
if( U.QueryHandlers[i].Class==Class'ServerPerkWebAdmin' )
|
||||
return; // Already implemented.
|
||||
U.QueryHandlers.Length = i+1;
|
||||
U.QueryHandlers[i] = New(U)Class'ServerPerkWebAdmin';
|
||||
U.QueryHandlers[i].Init();
|
||||
return;
|
||||
}
|
||||
}
|
||||
Log("ServerPerks WebAdmin interface failed to init: Missing UTServerAdmin application.",Class.Outer.Name);
|
||||
return;
|
||||
}
|
||||
Log("ServerPerks WebAdmin interface failed to init: Missing WebServer object.",Class.Outer.Name);
|
||||
}
|
||||
|
||||
function RespawnNetworkLink()
|
||||
{
|
||||
if( Link!=None )
|
||||
Link.Destroy();
|
||||
if( !bUseFTPLink )
|
||||
{
|
||||
Link = Spawn(Class'DatabaseUdpLink');
|
||||
DatabaseUdpLink(Link).Mut = Self;
|
||||
}
|
||||
else
|
||||
{
|
||||
Link = Spawn(Class'FTPTcpLink');
|
||||
FTPTcpLink(Link).Mut = Self;
|
||||
}
|
||||
Link.BeginEvent();
|
||||
}
|
||||
|
||||
function Mutate(string MutateString, PlayerController Sender)
|
||||
{
|
||||
if( MutateString~="SPHelp" )
|
||||
Sender.ClientMessage("ServerPerksMut mutate CMDs: EditStats, SetPerk, Debug, GetID");
|
||||
if( Sender.PlayerReplicationInfo.bAdmin || Sender.PlayerReplicationInfo.bSilentAdmin || Viewport(Sender.Player)!=None )
|
||||
{
|
||||
if( bAdminEditStats && MutateString~="EditStats" )
|
||||
Spawn(Class'AdminMenuHandle',Sender).MutatorOwner = Self;
|
||||
else if( MutateString~="GetID" )
|
||||
ListID(Sender);
|
||||
else if( Left(MutateString,7)~="SetPerk" )
|
||||
AdminChangePerk(Sender,Mid(MutateString,8));
|
||||
}
|
||||
if( NextCheckTimer<Level.TimeSeconds && MutateString~="Debug" ) // Allow developer to lookup bugs.
|
||||
{
|
||||
NextCheckTimer = Level.TimeSeconds+0.25;
|
||||
Sender.ClientMessage("Debug info: "$Sender.SteamStatsAndAchievements);
|
||||
if( ServerStStats(Sender.SteamStatsAndAchievements)!=None )
|
||||
{
|
||||
Sender.ClientMessage("Ready:"@ServerStStats(Sender.SteamStatsAndAchievements).bStatsReadyNow@ServerStStats(Sender.SteamStatsAndAchievements).bStatsChecking);
|
||||
Sender.ClientMessage("MyStatsObject:"@ServerStStats(Sender.SteamStatsAndAchievements).MyStatsObject);
|
||||
Sender.ClientMessage("Timer:"@Sender.SteamStatsAndAchievements.TimerCounter@Sender.SteamStatsAndAchievements.TimerRate);
|
||||
}
|
||||
Sender.ClientMessage("Perk info:");
|
||||
DebugMessageProgress(Sender);
|
||||
}
|
||||
if ( NextMutator != None )
|
||||
NextMutator.Mutate(MutateString, Sender);
|
||||
}
|
||||
final function AdminChangePerk( PlayerController Sender, string Cmd )
|
||||
{
|
||||
local int i,ID;
|
||||
local Controller C;
|
||||
local class<SRVeterancyTypes> V;
|
||||
local bool bAll;
|
||||
|
||||
i = InStr(Cmd," ");
|
||||
if( i==-1 )
|
||||
{
|
||||
Sender.ClientMessage("Usage: SetPerk <ID/All> <PerkName>");
|
||||
return;
|
||||
}
|
||||
if( Left(Cmd,i)~="All" )
|
||||
bAll = true;
|
||||
else ID = int(Left(Cmd,i));
|
||||
|
||||
Cmd = Mid(Cmd,i+1);
|
||||
for( i=0; i<LoadPerks.Length; ++i )
|
||||
if( string(LoadPerks[i].Name)~=Cmd || LoadPerks[i].Default.VeterancyName~=Cmd )
|
||||
{
|
||||
V = LoadPerks[i];
|
||||
break;
|
||||
}
|
||||
if( V==None )
|
||||
{
|
||||
Sender.ClientMessage("Unknown perk name: "$Cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
for( C=Level.ControllerList; C!=None; C=C.nextController )
|
||||
{
|
||||
if( C.bIsPlayer && C.PlayerReplicationInfo!=None && (bAll || C.PlayerReplicationInfo.PlayerID==ID) && xPlayer(C)!=None && ServerStStats(xPlayer(C).SteamStatsAndAchievements)!=None )
|
||||
{
|
||||
ServerStStats(xPlayer(C).SteamStatsAndAchievements).ForcePerkChange(V);
|
||||
xPlayer(C).ClientMessage("An admin has forced to change your perk to "$V.Default.VeterancyName);
|
||||
if( !bAll )
|
||||
{
|
||||
Sender.ClientMessage("Changed "$C.PlayerReplicationInfo.PlayerName$" perk to: "$V);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( bAll )
|
||||
Sender.ClientMessage("Changed everyones perk to: "$V);
|
||||
}
|
||||
final function ListID( PlayerController PC )
|
||||
{
|
||||
local Controller C;
|
||||
|
||||
PC.ClientMessage("Player IDs:");
|
||||
for( C=Level.ControllerList; C!=None; C=C.nextController )
|
||||
{
|
||||
if( C.bIsPlayer && C.PlayerReplicationInfo!=None && xPlayer(C)!=None && ServerStStats(xPlayer(C).SteamStatsAndAchievements)!=None )
|
||||
PC.ClientMessage("ID="$C.PlayerReplicationInfo.PlayerID$", Name="$C.PlayerReplicationInfo.PlayerName);
|
||||
}
|
||||
}
|
||||
final function DebugMessageProgress( PlayerController PC )
|
||||
{
|
||||
local KFPlayerReplicationInfo PRI;
|
||||
local class<SRVeterancyTypes> VC;
|
||||
local int i,Req,Cur,NumR;
|
||||
local byte Lvl;
|
||||
local ClientPerkRepLink Rep;
|
||||
|
||||
PRI = KFPlayerReplicationInfo(PC.PlayerReplicationInfo);
|
||||
if( PRI==None || Class<SRVeterancyTypes>(PRI.ClientVeteranSkill)==None )
|
||||
return;
|
||||
VC = Class<SRVeterancyTypes>(PRI.ClientVeteranSkill);
|
||||
Lvl = PRI.ClientVeteranSkillLevel+1;
|
||||
|
||||
Rep = Class'SRGameRules'.Static.FindStatsFor(PC);
|
||||
if( Rep==None )
|
||||
return;
|
||||
|
||||
PC.ClientMessage("Perk: "$VC.Default.VeterancyName$" NextLevel: "$Lvl);
|
||||
NumR = VC.Static.GetRequirementCount(Rep,Lvl);
|
||||
for( i=0; i<NumR; ++i )
|
||||
{
|
||||
Cur = VC.Static.GetPerkProgressInt(Rep,Req,Lvl,i);
|
||||
PC.ClientMessage("Requirement '"$i$"' GetPerkProgressInt: Current:"$Cur$" Final:"$Req);
|
||||
VC.Static.GetPerkProgress(Rep,Lvl,i,Cur,Req);
|
||||
PC.ClientMessage("GetPerkProgress: Current:"$Cur$" Final:"$Req);
|
||||
}
|
||||
}
|
||||
final function ImplementPackage( Object O )
|
||||
{
|
||||
local int i;
|
||||
|
||||
if( O==None )
|
||||
return;
|
||||
while( O.Outer!=None )
|
||||
O = O.Outer;
|
||||
if( O.Name=='KFMod' )
|
||||
return;
|
||||
for( i=(AddedServerPackages.Length-1); i>=0; --i )
|
||||
if( AddedServerPackages[i]==O.Name )
|
||||
return;
|
||||
AddedServerPackages[AddedServerPackages.Length] = O.Name;
|
||||
}
|
||||
|
||||
function bool CheckReplacement(Actor Other, out byte bSuperRelevant)
|
||||
{
|
||||
if( PlayerController(Other)!=None )
|
||||
{
|
||||
PendingPlayers[PendingPlayers.Length] = PlayerController(Other);
|
||||
SetTimer(0.1,false);
|
||||
}
|
||||
else if( Bot(Other)!=None && Bot(Other).PawnClass==Class'KFHumanPawn' )
|
||||
{
|
||||
Bot(Other).PawnClass = Class'SRHumanPawn';
|
||||
Bot(Other).PreviousPawnClass = Class'SRHumanPawn';
|
||||
}
|
||||
else if( ServerStStats(Other)!=None )
|
||||
SetServerPerks(ServerStStats(Other));
|
||||
else if( ClientPerkRepLink(Other)!=None )
|
||||
SetupRepLink(ClientPerkRepLink(Other));
|
||||
|
||||
return true;
|
||||
}
|
||||
function SetServerPerks( ServerStStats Stat )
|
||||
{
|
||||
local int i;
|
||||
|
||||
Stat.MutatorOwner = Self;
|
||||
Stat.Rep.ServerWebSite = ServerNewsURL;
|
||||
Stat.Rep.MinimumLevel = MinPerksLevel+1;
|
||||
Stat.Rep.MaximumLevel = MaxPerksLevel+1;
|
||||
Stat.Rep.RequirementScaling = RequirementScaling;
|
||||
Stat.Rep.CachePerks.Length = LoadPerks.Length;
|
||||
for( i=0; i<LoadPerks.Length; i++ )
|
||||
Stat.Rep.CachePerks[i].PerkClass = LoadPerks[i];
|
||||
}
|
||||
function SetupRepLink( ClientPerkRepLink R )
|
||||
{
|
||||
local int i;
|
||||
|
||||
R.bMinimalRequirements = bUseLowestRequirements;
|
||||
R.bBWZEDTime = bBWZEDTime;
|
||||
R.bNoStandardChars = bForceCustomChars;
|
||||
|
||||
R.ShopInventory.Length = LoadInventory.Length;
|
||||
for( i=0; i<LoadInventory.Length; ++i )
|
||||
{
|
||||
R.ShopInventory[i].PC = LoadInventory[i];
|
||||
R.ShopInventory[i].CatNum = LoadInvCategory[i];
|
||||
}
|
||||
R.ShopCategories = LoadedCategories;
|
||||
R.CustomChars = CustomCharacters;
|
||||
if( bEnabledEmoIcons )
|
||||
R.SmileyTags = SmileyMsgs;
|
||||
}
|
||||
|
||||
function GetServerDetails( out GameInfo.ServerResponseLine ServerState )
|
||||
{
|
||||
local int i,l;
|
||||
|
||||
Super.GetServerDetails( ServerState );
|
||||
l = ServerState.ServerInfo.Length;
|
||||
ServerState.ServerInfo.Length = l+1;
|
||||
ServerState.ServerInfo[l].Key = "SP: Version";
|
||||
ServerState.ServerInfo[l].Value = string(VersionNumber);
|
||||
l++;
|
||||
ServerState.ServerInfo.Length = l+1;
|
||||
ServerState.ServerInfo[l].Key = "SP: Min perk level";
|
||||
ServerState.ServerInfo[l].Value = string(MinPerksLevel);
|
||||
l++;
|
||||
ServerState.ServerInfo.Length = l+1;
|
||||
ServerState.ServerInfo[l].Key = "SP: Max perk level";
|
||||
ServerState.ServerInfo[l].Value = string(MaxPerksLevel);
|
||||
l++;
|
||||
ServerState.ServerInfo.Length = l+1;
|
||||
ServerState.ServerInfo[l].Key = "SP: Num trader weapons";
|
||||
ServerState.ServerInfo[l].Value = string(LoadInventory.Length);
|
||||
l++;
|
||||
For( i=0; i<LoadPerks.Length; i++ )
|
||||
{
|
||||
ServerState.ServerInfo.Length = l+1;
|
||||
ServerState.ServerInfo[l].Key = "SP: Perk "$(i+1);
|
||||
ServerState.ServerInfo[l].Value = LoadPerks[i].Default.VeterancyName;
|
||||
l++;
|
||||
}
|
||||
}
|
||||
function Timer()
|
||||
{
|
||||
local int i;
|
||||
|
||||
for( i=(PendingPlayers.Length-1); i>=0; --i )
|
||||
{
|
||||
if( KFPCServ(PendingPlayers[i])!=None )
|
||||
KFPCServ(PendingPlayers[i]).bUseAdvBehindview = bEnhancedShoulderView;
|
||||
if( PendingPlayers[i]!=None && PendingPlayers[i].Player!=None && ServerStStats(PendingPlayers[i].SteamStatsAndAchievements)==None )
|
||||
{
|
||||
if( PendingPlayers[i].SteamStatsAndAchievements!=None )
|
||||
PendingPlayers[i].SteamStatsAndAchievements.Destroy();
|
||||
PendingPlayers[i].SteamStatsAndAchievements = Spawn(Class'ServerStStats',PendingPlayers[i]);
|
||||
PendingPlayers[i].PlayerReplicationInfo.SteamStatsAndAchievements = PendingPlayers[i].SteamStatsAndAchievements;
|
||||
}
|
||||
}
|
||||
PendingPlayers.Length = 0;
|
||||
}
|
||||
|
||||
final function string GetPlayerID( PlayerController PC )
|
||||
{
|
||||
if( bUsePlayerNameAsID )
|
||||
return PC.PlayerReplicationInfo.PlayerName;
|
||||
return PC.GetPlayerIDHash();
|
||||
}
|
||||
function StatsObject GetStatsForPlayer( PlayerController PC )
|
||||
{
|
||||
local StatsObject S;
|
||||
local string SId;
|
||||
local int i;
|
||||
|
||||
if( Level.Game.bGameEnded )
|
||||
return None;
|
||||
SId = GetPlayerID(PC);
|
||||
for( i=0; i<ActiveStats.Length; ++i )
|
||||
if( string(ActiveStats[i].Name)~=SId )
|
||||
{
|
||||
S = ActiveStats[i];
|
||||
break;
|
||||
}
|
||||
if( S==None )
|
||||
{
|
||||
S = new(None,SId) Class'StatsObject';
|
||||
S.bStatsChanged = false;
|
||||
ActiveStats[ActiveStats.Length] = S;
|
||||
}
|
||||
S.PlayerName = PC.PlayerReplicationInfo.PlayerName;
|
||||
S.PlayerIP = PC.GetPlayerNetworkAddress();
|
||||
return S;
|
||||
}
|
||||
|
||||
function SaveStats()
|
||||
{
|
||||
local int i;
|
||||
local ClientPerkRepLink CP;
|
||||
|
||||
if( bNoSavingProgress )
|
||||
return;
|
||||
|
||||
Log("*** Saving "$ActiveStats.Length$" stat objects ***",Class.Outer.Name);
|
||||
foreach DynamicActors(Class'ClientPerkRepLink',CP)
|
||||
if( CP.StatObject!=None && ServerStStats(CP.StatObject).MyStatsObject!=None )
|
||||
ServerStStats(CP.StatObject).MyStatsObject.SetCustomValues(CP.CustomLink);
|
||||
|
||||
if( bUseRemoteDatabase )
|
||||
{
|
||||
SaveAllStats();
|
||||
return;
|
||||
}
|
||||
for( i=0; i<ActiveStats.Length; ++i )
|
||||
if( ActiveStats[i].bStatsChanged )
|
||||
{
|
||||
ActiveStats[i].bStatsChanged = false;
|
||||
ActiveStats[i].SaveConfig();
|
||||
}
|
||||
}
|
||||
function CheckWinOrLose()
|
||||
{
|
||||
local bool bWin;
|
||||
local Controller P;
|
||||
local PlayerController Player;
|
||||
|
||||
bWin = (KFGameReplicationInfo(Level.GRI)!=None && KFGameReplicationInfo(Level.GRI).EndGameType==2);
|
||||
for ( P = Level.ControllerList; P != none; P = P.nextController )
|
||||
{
|
||||
Player = PlayerController(P);
|
||||
|
||||
if ( Player != none )
|
||||
{
|
||||
if ( ServerStStats(Player.SteamStatsAndAchievements)!=None )
|
||||
ServerStStats(Player.SteamStatsAndAchievements).WonLostGame(bWin);
|
||||
}
|
||||
}
|
||||
}
|
||||
function InitNextWave()
|
||||
{
|
||||
if( ++WaveCounter>=MidGameSaveWaves )
|
||||
{
|
||||
WaveCounter = 0;
|
||||
SaveStats();
|
||||
}
|
||||
}
|
||||
|
||||
Auto state EndGameTracker
|
||||
{
|
||||
Begin:
|
||||
if( bUploadAllStats && Level.NetMode==NM_StandAlone )
|
||||
{
|
||||
Sleep(1.f);
|
||||
FTPTcpLink(Link).FullUpload();
|
||||
while( true )
|
||||
{
|
||||
if( KFGT!=None )
|
||||
KFGT.WaveCountDown = 60;
|
||||
Sleep(1.f);
|
||||
}
|
||||
}
|
||||
while( !Level.Game.bGameEnded )
|
||||
{
|
||||
Sleep(1.f);
|
||||
if( MidGameSaveWaves>0 && KFGT!=None && KFGT.WaveNum!=LastSavedWave )
|
||||
{
|
||||
LastSavedWave = KFGT.WaveNum;
|
||||
InitNextWave();
|
||||
}
|
||||
if( Level.bLevelChange )
|
||||
{
|
||||
SaveStats();
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
CheckWinOrLose();
|
||||
SaveStats();
|
||||
}
|
||||
|
||||
static final function string GetSafeName( string S )
|
||||
{
|
||||
S = Repl(S,"=","-");
|
||||
S = Repl(S,Chr(10),""); // LF
|
||||
S = Repl(S,Chr(13),""); // CR
|
||||
S = Repl(S,"\"","'"); // " -> '
|
||||
return S;
|
||||
}
|
||||
|
||||
delegate SaveAllStats();
|
||||
delegate RequestStats( ServerStStats Other );
|
||||
|
||||
static function FillPlayInfo(PlayInfo PlayInfo)
|
||||
{
|
||||
Super.FillPlayInfo(PlayInfo);
|
||||
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"MinPerksLevel","Min Perk Level",1,0, "Text", "4;-1:254");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"MaxPerksLevel","Max Perk Level",1,0, "Text", "4;0:254");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"RequirementScaling","Req Scaling",1,0, "Text", "6;0.01:4.00");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"bForceGivePerk","Force perks",1,0, "Check");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"bNoSavingProgress","No saving",1,0, "Check");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"bAllowAlwaysPerkChanges","Unlimited perk changes",1,0, "Check");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"bNoPerkChanges","No perk changes",1,0, "Check");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"bUseRemoteDatabase","Use remote database",1,0, "Check");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"bUseFTPLink","Use FTP remote database",1,0, "Check");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"RemoteDatabaseURL","Remote database URL",1,1,"Text","64");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"RemotePort","Remote database port",1,0, "Text", "5;0:65535");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"RemotePassword","Remote database password",1,0, "Text", "64");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"RemoteFTPUser","Remote database user",1,0, "Text", "64");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"RemoteFTPDir","Remote database dir",1,0, "Text", "64");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"FTPKeepAliveSec","FTP Keep alive sec",1,0, "Text", "6;0:600");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"MidGameSaveWaves","MidGame Save Waves",1,0, "Text", "5;0:10");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"ServerNewsURL","Newspage URL",1,0, "Text", "64");
|
||||
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"bUsePlayerNameAsID","Use PlayerName as ID",1,0, "Check");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"bMessageAnyPlayerLevelUp","Notify any levelup",1,0, "Check");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"bUseLowestRequirements","Use lowest req",1,0, "Check");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"bBWZEDTime","BW ZED-time",1,0, "Check");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"bUseEnhancedScoreboard","Enhanced scoreboard",1,0, "Check");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"bForceCustomChars","Force Custom Chars",1,0, "Check");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"bEnableChatIcons","Enable chat icons",1,0, "Check");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"bEnhancedShoulderView","Shoulder view",1,0, "Check");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"bFixGrenadeExploit","No Grenade Exploit",1,0, "Check");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"bAdminEditStats","Admin edit stats",1,0, "Check");
|
||||
PlayInfo.AddSetting(default.ServerPerksGroup,"bEnableWebAdmin","SP WebAdmin",1,0, "Check");
|
||||
}
|
||||
|
||||
static event string GetDescriptionText(string PropName)
|
||||
{
|
||||
switch (PropName)
|
||||
{
|
||||
case "MinPerksLevel": return "Minimum perk level players can have.";
|
||||
case "MaxPerksLevel": return "Maximum perk level players can have.";
|
||||
case "RequirementScaling": return "Perk requirements scaling.";
|
||||
case "bForceGivePerk": return "Force all players to get at least a random perk if they have none selected.";
|
||||
case "bNoSavingProgress": return "Server shouldn't save perk progression.";
|
||||
case "bUseRemoteDatabase": return "Instead of storing perk data locally on server, use remote data storeage server.";
|
||||
case "bUseFTPLink": return "Use FTP transmission for remote database.";
|
||||
case "RemoteDatabaseURL": return "URL of the remote database.";
|
||||
case "RemotePort": return "Port of the remote database.";
|
||||
case "RemotePassword": return "Password for server to access the remote database.";
|
||||
case "RemoteFTPUser": return "User name for server to access the remote database (only for FTP mode).";
|
||||
case "MidGameSaveWaves": return "Between how many waves should it mid-game save stats.";
|
||||
case "bUsePlayerNameAsID": return "Use PlayerName's as ID instead of ID Hash.";
|
||||
case "bMessageAnyPlayerLevelUp": return "Broadcast a global message anytime someone gains a perk upgrade.";
|
||||
case "bUseLowestRequirements": return "Use lowest form of requirements for perks.";
|
||||
case "bBWZEDTime": return "Make screen go black and white during ZED-time.";
|
||||
case "bUseEnhancedScoreboard": return "Should use serverperk's own scoreboard.";
|
||||
case "bAllowAlwaysPerkChanges": return "Allow unlimited perk changes.";
|
||||
case "bForceCustomChars": return "Force players to use specified custom characters.";
|
||||
case "bEnableChatIcons": return "Should enable chat icons to replace specific tags in chat.";
|
||||
case "bEnhancedShoulderView": return "Should enable a more enhanced on shoulder behindview.";
|
||||
case "bFixGrenadeExploit": return "Should fix unlimited grenades glitch/exploit.";
|
||||
case "bAdminEditStats": return "Allow admins edit stats through an admin menu.";
|
||||
case "ServerNewsURL": return "Server newspage menu URL for page contents.";
|
||||
case "RemoteFTPDir": return "Remote FTP database data storage directory.";
|
||||
case "FTPKeepAliveSec": return "Keep FTP database connection alive with this many sec interval.";
|
||||
case "bEnableWebAdmin": return "Enable additional webserver interface.";
|
||||
case "bNoPerkChanges": return "Never allow players change perk during match.";
|
||||
}
|
||||
return Super.GetDescriptionText(PropName);
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
Perks(0)="ServerPerksP.SRVetSupportSpec"
|
||||
Perks(1)="ServerPerksP.SRVetBerserker"
|
||||
Perks(2)="ServerPerksP.SRVetCommando"
|
||||
Perks(3)="ServerPerksP.SRVetFieldMedic"
|
||||
Perks(4)="ServerPerksP.SRVetFirebug"
|
||||
Perks(5)="ServerPerksP.SRVetSharpshooter"
|
||||
Perks(6)="ServerPerksP.SRVetDemolitions"
|
||||
TraderInventory(0)="5:KFMod.MP7MPickup"
|
||||
TraderInventory(1)="5:KFMod.BlowerThrowerPickup"
|
||||
TraderInventory(2)="5:KFMod.MP5MPickup"
|
||||
TraderInventory(3)="5:KFMod.M7A3MPickup"
|
||||
TraderInventory(4)="5:KFMod.KrissMPickup"
|
||||
TraderInventory(5)="2:KFMod.ShotgunPickup"
|
||||
TraderInventory(6)="2:KFMod.KSGPickup"
|
||||
TraderInventory(7)="2:KFMod.BoomStickPickup"
|
||||
TraderInventory(8)="2:KFMod.BenelliPickup"
|
||||
TraderInventory(9)="2:KFMod.AA12Pickup"
|
||||
TraderInventory(10)="2:KFMod.NailGunPickup"
|
||||
TraderInventory(11)="2:KFMod.SPShotGunPickup"
|
||||
TraderInventory(12)="1:KFMod.DualiesPickup"
|
||||
TraderInventory(13)="1:KFMod.MK23Pickup"
|
||||
TraderInventory(14)="1:KFMod.DualMK23Pickup"
|
||||
TraderInventory(15)="1:KFMod.Magnum44Pickup"
|
||||
TraderInventory(16)="1:KFMod.Dual44MagnumPickup"
|
||||
TraderInventory(17)="1:KFMod.DeaglePickup"
|
||||
TraderInventory(18)="1:KFMod.DualDeaglePickup"
|
||||
TraderInventory(19)="3:KFMod.WinchesterPickup"
|
||||
TraderInventory(20)="3:KFMod.CrossbowPickup"
|
||||
TraderInventory(21)="3:KFMod.M14EBRPickup"
|
||||
TraderInventory(22)="3:KFMod.M99Pickup"
|
||||
TraderInventory(23)="3:KFMod.SPSniperPickup"
|
||||
TraderInventory(24)="4:KFMod.BullpupPickup"
|
||||
TraderInventory(25)="4:KFMod.AK47Pickup"
|
||||
TraderInventory(26)="4:KFMod.MKb42Pickup"
|
||||
TraderInventory(27)="4:KFMod.M4Pickup"
|
||||
TraderInventory(28)="4:KFMod.SCARMK17Pickup"
|
||||
TraderInventory(29)="4:KFMod.FNFAL_ACOG_Pickup"
|
||||
TraderInventory(30)="4:KFMod.ThompsonPickup"
|
||||
TraderInventory(31)="4:KFMod.SPThompsonPickup"
|
||||
TraderInventory(32)="4:KFMod.ThompsonDrumPickup"
|
||||
TraderInventory(33)="0:KFMod.MachetePickup"
|
||||
TraderInventory(34)="0:KFMod.AxePickup"
|
||||
TraderInventory(35)="0:KFMod.ChainsawPickup"
|
||||
TraderInventory(36)="0:KFMod.KatanaPickup"
|
||||
TraderInventory(37)="0:KFMod.ClaymoreSwordPickup"
|
||||
TraderInventory(38)="0:KFMod.CrossbuzzsawPickup"
|
||||
TraderInventory(39)="0:KFMod.ScythePickup"
|
||||
TraderInventory(40)="0:KFMod.DwarfAxePickup"
|
||||
TraderInventory(41)="7:KFMod.FlameThrowerPickup"
|
||||
TraderInventory(42)="2:KFMod.TrenchgunPickup"
|
||||
TraderInventory(43)="1:KFMod.FlareRevolverPickup"
|
||||
TraderInventory(44)="1:KFMod.DualFlareRevolverPickup"
|
||||
TraderInventory(45)="4:KFMod.MAC10Pickup"
|
||||
TraderInventory(46)="7:KFMod.HuskGunPickup"
|
||||
TraderInventory(47)="6:KFMod.PipeBombPickup"
|
||||
TraderInventory(48)="6:KFMod.M79Pickup"
|
||||
TraderInventory(49)="6:KFMod.M32Pickup"
|
||||
TraderInventory(50)="4:KFMod.M4203Pickup"
|
||||
TraderInventory(51)="6:KFMod.SPGrenadePickup"
|
||||
TraderInventory(52)="6:KFMod.LAWPickup"
|
||||
TraderInventory(53)="6:KFMod.SealSquealPickup"
|
||||
TraderInventory(54)="6:KFMod.SeekerSixPickup"
|
||||
TraderInventory(55)="8:KFMod.ZEDGunPickup"
|
||||
TraderInventory(56)="8:KFMod.ZEDMKIIPickup"
|
||||
TraderInventory(57)="2:KFMod.GoldenAA12Pickup"
|
||||
TraderInventory(58)="4:KFMod.GoldenAK47Pickup"
|
||||
TraderInventory(59)="2:KFMod.GoldenBenelliPickup"
|
||||
TraderInventory(60)="0:KFMod.GoldenChainsawPickup"
|
||||
TraderInventory(61)="1:KFMod.GoldenDeaglePickup"
|
||||
TraderInventory(62)="1:KFMod.GoldenDualDeaglePickup"
|
||||
TraderInventory(63)="7:KFMod.GoldenFTPickup"
|
||||
TraderInventory(64)="0:KFMod.GoldenKatanaPickup"
|
||||
TraderInventory(65)="6:KFMod.GoldenM79Pickup"
|
||||
TraderInventory(66)="4:KFMod.CamoMP5MPickup"
|
||||
TraderInventory(67)="2:KFMod.CamoShotgunPickup"
|
||||
TraderInventory(68)="4:KFMod.CamoM4Pickup"
|
||||
TraderInventory(69)="6:KFMod.CamoM32Pickup"
|
||||
TraderInventory(70)="4:KFMod.NeonAK47Pickup"
|
||||
TraderInventory(71)="5:KFMod.NeonKrissMPickup"
|
||||
TraderInventory(72)="2:KFMod.NeonKSGPickup"
|
||||
TraderInventory(73)="4:KFMod.NeonSCARMK17Pickup"
|
||||
WeaponCategories(0)="4:Melee"
|
||||
WeaponCategories(1)="2:Pistol"
|
||||
WeaponCategories(2)="1:Shotgun"
|
||||
WeaponCategories(3)="2:Sniper"
|
||||
WeaponCategories(4)="3:Machine Gun"
|
||||
WeaponCategories(5)="0:Medic Gun"
|
||||
WeaponCategories(6)="6:Explosive"
|
||||
WeaponCategories(7)="5:Flame Thrower"
|
||||
WeaponCategories(8)="7:Misc"
|
||||
MaxPerksLevel=6
|
||||
RemotePort=5000
|
||||
RequirementScaling=1.000000
|
||||
RemoteDatabaseURL="192.168.1.33"
|
||||
RemotePassword="Pass"
|
||||
RemoteFTPUser="User"
|
||||
SmileyTags(0)=(iconTexture="ServerPerks.I_Mad",IconTag=">:(")
|
||||
SmileyTags(1)=(iconTexture="ServerPerks.I_Frown",IconTag=":(")
|
||||
SmileyTags(2)=(iconTexture="ServerPerks.I_GreenLickB",IconTag=":)")
|
||||
SmileyTags(3)=(iconTexture="ServerPerks.I_Tongue",IconTag=":P",bCaseInsensitive=True)
|
||||
SmileyTags(4)=(iconTexture="ServerPerks.I_GreenLick",IconTag=":d")
|
||||
SmileyTags(5)=(iconTexture="ServerPerks.I_BigGrin",IconTag=":D")
|
||||
SmileyTags(6)=(iconTexture="ServerPerks.I_Indiffe",IconTag=":|")
|
||||
SmileyTags(7)=(iconTexture="ServerPerks.I_Ohwell",IconTag=":/")
|
||||
SmileyTags(8)=(iconTexture="ServerPerks.I_RedFace",IconTag=":*")
|
||||
SmileyTags(9)=(iconTexture="ServerPerks.I_RedFace",IconTag=":-*")
|
||||
SmileyTags(10)=(iconTexture="ServerPerks.I_Ban",IconTag="Ban?",bCaseInsensitive=True)
|
||||
SmileyTags(11)=(iconTexture="ServerPerks.I_Cool",IconTag="B)")
|
||||
SmileyTags(12)=(iconTexture="ServerPerks.I_Hmm",IconTag="Hmm")
|
||||
SmileyTags(13)=(iconTexture="ServerPerks.I_Scream",IconTag="XD")
|
||||
SmileyTags(14)=(iconTexture="ServerPerks.I_Spam",IconTag="SPAM")
|
||||
VersionNumber=750
|
||||
ServerPerksGroup="Server Perks"
|
||||
SRScoreboardType=Class'ServerPerks.SRScoreBoard'
|
||||
SRHudType=Class'ServerPerks.SRHUDKillingFloor'
|
||||
SRMenuType=Class'ServerPerks.SRInvasionLoginMenu'
|
||||
SRControllerType=Class'ServerPerks.KFPCServ'
|
||||
bUseEnhancedScoreboard=True
|
||||
bEnableWebAdmin=True
|
||||
bEnableChatIcons=True
|
||||
bEnhancedShoulderView=True
|
||||
bFixGrenadeExploit=True
|
||||
bAdminEditStats=True
|
||||
GroupName="KF-Stats"
|
||||
FriendlyName="Server Veterancy Handler V7"
|
||||
Description="Use perks as privately on this server config instead of getting from global steam stats."
|
||||
}
|
||||
681
kf_sources/ServerPerksMut/Classes/ServerStStats.uc
Normal file
681
kf_sources/ServerPerksMut/Classes/ServerStStats.uc
Normal file
|
|
@ -0,0 +1,681 @@
|
|||
// Written by .:..: (2009)
|
||||
Class ServerStStats extends SRStatsBase;
|
||||
|
||||
var StatsObject MyStatsObject;
|
||||
var ServerPerksMut MutatorOwner;
|
||||
var byte SelectingIndex;
|
||||
var bool bHasChanged,bStatsChecking,bStHasInit,bHadSwitchedVet,bSwitchIsOKNow;
|
||||
|
||||
var class<SRVeterancyTypes> SelectingPerk;
|
||||
|
||||
function int GetID()
|
||||
{
|
||||
return MyStatsObject.ID;
|
||||
}
|
||||
function SetID( int ID )
|
||||
{
|
||||
MyStatsObject.ID = ID;
|
||||
}
|
||||
function PreBeginPlay()
|
||||
{
|
||||
local LinkedReplicationInfo L;
|
||||
|
||||
PlayerOwner = KFPlayerController(Owner);
|
||||
if( Rep==None )
|
||||
{
|
||||
Rep = Spawn(Class'ClientPerkRepLink',Owner);
|
||||
Rep.StatObject = Self;
|
||||
|
||||
if( PlayerOwner.PlayerReplicationInfo.CustomReplicationInfo==None )
|
||||
PlayerOwner.PlayerReplicationInfo.CustomReplicationInfo = Rep;
|
||||
else
|
||||
{
|
||||
for( L=PlayerOwner.PlayerReplicationInfo.CustomReplicationInfo; L!=None; L=L.NextReplicationInfo )
|
||||
if( L.NextReplicationInfo==None )
|
||||
{
|
||||
L.NextReplicationInfo = Rep;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Super.PreBeginPlay();
|
||||
}
|
||||
function PostBeginPlay()
|
||||
{
|
||||
if( Rep!=None )
|
||||
Rep.SpawnCustomLinks();
|
||||
|
||||
bStatsReadyNow = MutatorOwner.bNoSavingProgress || !MutatorOwner.bUseRemoteDatabase;
|
||||
MyStatsObject = MutatorOwner.GetStatsForPlayer(PlayerOwner);
|
||||
if( MyStatsObject!=None && MyStatsObject.bStatsChanged )
|
||||
bStatsReadyNow = true; // Server has already the most fresh stats for this client.
|
||||
KFPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).ClientVeteranSkill = None;
|
||||
if( !bStatsReadyNow )
|
||||
{
|
||||
Timer();
|
||||
SetTimer(1+FRand(),true);
|
||||
return;
|
||||
}
|
||||
bSwitchIsOKNow = true;
|
||||
if( MyStatsObject!=None )
|
||||
{
|
||||
// Apply selected character.
|
||||
if( MyStatsObject.SelectedChar!="" )
|
||||
ApplyCharacter(MyStatsObject.SelectedChar);
|
||||
else if( Rep.bNoStandardChars && Rep.CustomChars.Length>0 )
|
||||
{
|
||||
MyStatsObject.SelectedChar = Rep.PickRandomCustomChar();
|
||||
ApplyCharacter(MyStatsObject.SelectedChar);
|
||||
}
|
||||
|
||||
RepCopyStats();
|
||||
bHasChanged = true;
|
||||
CheckPerks(true);
|
||||
SelectingIndex = MyStatsObject.PerkIndex;
|
||||
if( MutatorOwner.bNoPerkChanges && MyStatsObject.ChosenPerk!=None )
|
||||
ServerSelectPerk(MyStatsObject.ChosenPerk);
|
||||
else ServerSelectPerkName(MyStatsObject.GetSelectedPerk());
|
||||
SelectingIndex = 255;
|
||||
}
|
||||
else CheckPerks(true);
|
||||
if( MutatorOwner.bForceGivePerk && KFPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).ClientVeteranSkill==None )
|
||||
ServerSelectPerk(Rep.PickRandomPerk());
|
||||
bSwitchIsOKNow = false;
|
||||
bHadSwitchedVet = false;
|
||||
SetTimer(0.1,false);
|
||||
}
|
||||
function ApplyCharacter( string CN )
|
||||
{
|
||||
PlayerOwner.PawnSetupRecord = class'xUtil'.static.FindPlayerRecord(CN);
|
||||
if( PlayerOwner.PawnSetupRecord.VoiceClassName!="" )
|
||||
PlayerOwner.PlayerReplicationInfo.SetCharacterVoice(PlayerOwner.PawnSetupRecord.VoiceClassName);
|
||||
PlayerOwner.PlayerReplicationInfo.SetCharacterName(CN);
|
||||
}
|
||||
function ChangeCharacter( string CN )
|
||||
{
|
||||
local bool bCustom;
|
||||
|
||||
bCustom = Rep.IsCustomCharacter(CN);
|
||||
if( !bCustom )
|
||||
{
|
||||
if( Rep.bNoStandardChars && Rep.CustomChars.Length>0 ) // Prevent from switching to a standard character.
|
||||
{
|
||||
CN = Rep.PickRandomCustomChar();
|
||||
bCustom = true;
|
||||
}
|
||||
else CN = Class'KFGameType'.Static.GetValidCharacter(CN); // Make sure client doesn't chose some invalid character.
|
||||
}
|
||||
|
||||
ApplyCharacter(CN);
|
||||
|
||||
if( !bCustom ) // Was not a custom character, don't save client char on server.
|
||||
CN = "";
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.SetSelectedChar(CN);
|
||||
}
|
||||
|
||||
function GetData( string D )
|
||||
{
|
||||
bStatsReadyNow = true;
|
||||
MyStatsObject.SetSaveData(D);
|
||||
RepCopyStats();
|
||||
bHasChanged = true;
|
||||
bSwitchIsOKNow = true;
|
||||
|
||||
// Apply selected character.
|
||||
if( MyStatsObject.SelectedChar!="" )
|
||||
ApplyCharacter(MyStatsObject.SelectedChar);
|
||||
else if( Rep.bNoStandardChars && Rep.CustomChars.Length>0 )
|
||||
{
|
||||
MyStatsObject.SelectedChar = Rep.PickRandomCustomChar();
|
||||
ApplyCharacter(MyStatsObject.SelectedChar);
|
||||
}
|
||||
|
||||
CheckPerks(true);
|
||||
SelectingIndex = MyStatsObject.PerkIndex;
|
||||
ServerSelectPerkName(MyStatsObject.GetSelectedPerk());
|
||||
SelectingIndex = 255;
|
||||
Rep.SendClientPerks();
|
||||
if( MutatorOwner.bForceGivePerk && KFPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).ClientVeteranSkill==None )
|
||||
ServerSelectPerk(Rep.PickRandomPerk());
|
||||
bHadSwitchedVet = false;
|
||||
bSwitchIsOKNow = false;
|
||||
SetTimer(0.1,false);
|
||||
}
|
||||
function Timer()
|
||||
{
|
||||
if( !bStatsReadyNow )
|
||||
{
|
||||
MutatorOwner.RequestStats(Self);
|
||||
return;
|
||||
}
|
||||
if( !bStHasInit )
|
||||
{
|
||||
if( PlayerOwner.SteamStatsAndAchievements!=None && PlayerOwner.SteamStatsAndAchievements!=Self )
|
||||
PlayerOwner.SteamStatsAndAchievements.Destroy();
|
||||
PlayerOwner.SteamStatsAndAchievements = Self;
|
||||
PlayerOwner.PlayerReplicationInfo.SteamStatsAndAchievements = Self;
|
||||
bStHasInit = true;
|
||||
Rep.SendClientPerks();
|
||||
}
|
||||
if( bStatsChecking )
|
||||
{
|
||||
bStatsChecking = false;
|
||||
CheckPerks(false);
|
||||
}
|
||||
}
|
||||
function RepCopyStats()
|
||||
{
|
||||
// Copy all stats from data object for client replication
|
||||
Rep.RDamageHealedStat = MyStatsObject.DamageHealedStat;
|
||||
Rep.RWeldingPointsStat = MyStatsObject.WeldingPointsStat;
|
||||
Rep.RShotgunDamageStat = MyStatsObject.ShotgunDamageStat;
|
||||
Rep.RHeadshotKillsStat = MyStatsObject.HeadshotKillsStat;
|
||||
Rep.RStalkerKillsStat = MyStatsObject.StalkerKillsStat;
|
||||
Rep.RBullpupDamageStat = MyStatsObject.BullpupDamageStat;
|
||||
Rep.RMeleeDamageStat = MyStatsObject.MeleeDamageStat;
|
||||
Rep.RFlameThrowerDamageStat = MyStatsObject.FlameThrowerDamageStat;
|
||||
Rep.RSelfHealsStat = MyStatsObject.SelfHealsStat;
|
||||
Rep.RSoleSurvivorWavesStat = MyStatsObject.SoleSurvivorWavesStat;
|
||||
Rep.RCashDonatedStat = MyStatsObject.CashDonatedStat;
|
||||
Rep.RFeedingKillsStat = MyStatsObject.FeedingKillsStat;
|
||||
Rep.RBurningCrossbowKillsStat = MyStatsObject.BurningCrossbowKillsStat;
|
||||
Rep.RGibbedFleshpoundsStat = MyStatsObject.GibbedFleshpoundsStat;
|
||||
Rep.RStalkersKilledWithExplosivesStat = MyStatsObject.StalkersKilledWithExplosivesStat;
|
||||
Rep.RGibbedEnemiesStat = MyStatsObject.GibbedEnemiesStat;
|
||||
Rep.RBloatKillsStat = MyStatsObject.BloatKillsStat;
|
||||
Rep.RTotalZedTimeStat = MyStatsObject.TotalZedTimeStat;
|
||||
Rep.RSirenKillsStat = MyStatsObject.SirenKillsStat;
|
||||
Rep.RKillsStat = MyStatsObject.KillsStat;
|
||||
Rep.RExplosivesDamageStat = MyStatsObject.ExplosivesDamageStat;
|
||||
Rep.TotalPlayTime = MyStatsObject.TotalPlayTime;
|
||||
Rep.WinsCount = MyStatsObject.WinsCount;
|
||||
Rep.LostsCount = MyStatsObject.LostsCount;
|
||||
MyStatsObject.GetCustomValues(Rep.CustomLink);
|
||||
}
|
||||
|
||||
final function ForcePerkChange( Class<SRVeterancyTypes> VetType )
|
||||
{
|
||||
bSwitchIsOKNow = true;
|
||||
ServerSelectPerk(VetType);
|
||||
bSwitchIsOKNow = false;
|
||||
}
|
||||
function ServerSelectPerkName( name N )
|
||||
{
|
||||
local byte i,Index;
|
||||
|
||||
if( N=='' )
|
||||
return;
|
||||
|
||||
Index = 255;
|
||||
for( i=0; i<Rep.CachePerks.Length; i++ )
|
||||
{
|
||||
if( Rep.CachePerks[i].PerkClass.Name==N )
|
||||
{
|
||||
ServerSelectPerk(Rep.CachePerks[i].PerkClass);
|
||||
return;
|
||||
}
|
||||
else if( Rep.CachePerks[i].PerkClass.Default.PerkIndex==SelectingIndex )
|
||||
Index = i;
|
||||
}
|
||||
if( Index!=255 )
|
||||
ServerSelectPerk(Rep.CachePerks[Index].PerkClass); // Fallback to using saved index.
|
||||
}
|
||||
function ServerSelectPerk( Class<SRVeterancyTypes> VetType )
|
||||
{
|
||||
local byte i;
|
||||
|
||||
if( !bStatsReadyNow )
|
||||
return;
|
||||
if( VetType==None || !SelectionOK(VetType) )
|
||||
{
|
||||
if( !bSwitchIsOKNow )
|
||||
PlayerOwner.ClientMessage("Your desired perk is unavailable.");
|
||||
return;
|
||||
}
|
||||
else if( KFPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).ClientVeteranSkill==VetType )
|
||||
{
|
||||
if( SelectingPerk!=None )
|
||||
{
|
||||
SelectingPerk = None;
|
||||
PlayerOwner.ClientMessage("You will remain the same perk now.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if( MyStatsObject!=None )
|
||||
{
|
||||
MyStatsObject.ChosenPerk = VetType;
|
||||
MyStatsObject.SetSelectedPerk(VetType.Name);
|
||||
MyStatsObject.PerkIndex = VetType.Default.PerkIndex;
|
||||
}
|
||||
if( !Level.Game.bWaitingToStartMatch && !bSwitchIsOKNow && !MutatorOwner.bAllowAlwaysPerkChanges )
|
||||
{
|
||||
if( MutatorOwner.bNoPerkChanges && KFPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).ClientVeteranSkill!=None )
|
||||
{
|
||||
PlayerOwner.ClientMessage("You are not allowed to change perk during game.");
|
||||
return;
|
||||
}
|
||||
if( PlayerOwner.Pawn!=None )
|
||||
{
|
||||
if( KFGameReplicationInfo(Level.GRI).bWaveInProgress || bHadSwitchedVet )
|
||||
i = 1;
|
||||
else
|
||||
{
|
||||
bHadSwitchedVet = true;
|
||||
i = 0;
|
||||
}
|
||||
if( i==1 )
|
||||
{
|
||||
PlayerOwner.ClientMessage(Repl(PlayerOwner.YouWillBecomePerkString, "%Perk%", VetType.Default.VeterancyName));
|
||||
SelectingPerk = VetType;
|
||||
PlayerOwner.SelectedVeterancy = VetType; // Force KFGameType update this.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
SelectingPerk = None;
|
||||
for( i=0; i<Rep.CachePerks.Length; i++ )
|
||||
{
|
||||
if( Rep.CachePerks[i].PerkClass==VetType )
|
||||
{
|
||||
if( Rep.CachePerks[i].CurrentLevel==0 )
|
||||
return;
|
||||
PlayerOwner.SelectedVeterancy = VetType;
|
||||
KFPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).ClientVeteranSkill = VetType;
|
||||
KFPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).ClientVeteranSkillLevel = Rep.CachePerks[i].CurrentLevel-1;
|
||||
if( KFHumanPawn(PlayerOwner.Pawn)!=None )
|
||||
{
|
||||
KFHumanPawn(PlayerOwner.Pawn).VeterancyChanged();
|
||||
DropToCarryLimit(KFHumanPawn(PlayerOwner.Pawn));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function DropToCarryLimit( KFHumanPawn P )
|
||||
{
|
||||
local byte c;
|
||||
local Inventory I;
|
||||
|
||||
while( P.CurrentWeight>P.MaxCarryWeight && ++c<6 )
|
||||
{
|
||||
for ( I = P.Inventory; I != none; I = I.Inventory )
|
||||
{
|
||||
if ( KFWeapon(I) != none && !KFWeapon(I).bKFNeverThrow )
|
||||
{
|
||||
I.Velocity = P.Velocity;
|
||||
I.DropFrom(P.Location + VRand() * 10);
|
||||
break; // Drop weapons until player is capable of carrying them all.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function bool SelectionOK( Class<SRVeterancyTypes> VetType )
|
||||
{
|
||||
local byte i;
|
||||
|
||||
for( i=0; i<Rep.CachePerks.Length; i++ )
|
||||
{
|
||||
if( Rep.CachePerks[i].PerkClass==VetType )
|
||||
return (Rep.CachePerks[i].CurrentLevel>0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function CheckPerks( bool bInit )
|
||||
{
|
||||
local byte i,NewLevel;
|
||||
|
||||
if( !bStatsReadyNow )
|
||||
return;
|
||||
if( bInit )
|
||||
{
|
||||
for( i=0; i<Rep.CachePerks.Length; i++ )
|
||||
Rep.CachePerks[i].CurrentLevel = Rep.CachePerks[i].PerkClass.Static.PerkIsAvailable(Rep);
|
||||
return;
|
||||
}
|
||||
for( i=0; i<Rep.CachePerks.Length; i++ )
|
||||
{
|
||||
NewLevel = Rep.CachePerks[i].CurrentLevel;
|
||||
while( NewLevel<Rep.MaximumLevel && Rep.CachePerks[i].PerkClass.Static.LevelIsFinished(Rep,NewLevel) )
|
||||
++NewLevel;
|
||||
if( NewLevel>Rep.CachePerks[i].CurrentLevel )
|
||||
{
|
||||
if( KFPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).ClientVeteranSkill==Rep.CachePerks[i].PerkClass )
|
||||
KFPlayerReplicationInfo(PlayerOwner.PlayerReplicationInfo).ClientVeteranSkillLevel = NewLevel-1;
|
||||
Rep.CachePerks[i].CurrentLevel = NewLevel;
|
||||
Rep.ClientPerkLevel(i,NewLevel);
|
||||
if( MutatorOwner.bMessageAnyPlayerLevelUp )
|
||||
BroadcastLocalizedMessage(Class'KFVetEarnedMessagePL',(NewLevel-1),PlayerOwner.PlayerReplicationInfo,,Rep.CachePerks[i].PerkClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final function DelayedStatCheck()
|
||||
{
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.bStatsChanged = true;
|
||||
if( bStatsChecking || !bStatsReadyNow )
|
||||
return;
|
||||
bStatsChecking = true;
|
||||
SetTimer(1,false);
|
||||
}
|
||||
function NotifyStatChanged()
|
||||
{
|
||||
bHasChanged = true;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
|
||||
function MatchEnded()
|
||||
{
|
||||
}
|
||||
function AddDamageHealed(int Amount, optional bool bMP7MHeal, optional bool bMP5MHeal)
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RDamageHealedStat+=Amount;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.DamageHealedStat+=Amount;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
function AddWeldingPoints(int Amount)
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RWeldingPointsStat+=Amount;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.WeldingPointsStat+=Amount;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
function AddShotgunDamage(int Amount)
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RShotgunDamageStat+=Amount;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.ShotgunDamageStat+=Amount;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
function AddHeadshotKill(bool bLaserSightedEBRHeadshot)
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RHeadshotKillsStat++;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.HeadshotKillsStat++;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
function AddStalkerKill()
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RStalkerKillsStat++;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.StalkerKillsStat++;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
function AddBullpupDamage(int Amount)
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RBullpupDamageStat+=Amount;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.BullpupDamageStat+=Amount;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
|
||||
function AddMeleeDamage(int Amount)
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RMeleeDamageStat+=Amount;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.MeleeDamageStat+=Amount;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
|
||||
function AddFlameThrowerDamage(int Amount)
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RFlameThrowerDamageStat+=Amount;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.FlameThrowerDamageStat+=Amount;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
function WaveEnded()
|
||||
{
|
||||
if( SelectingPerk!=None )
|
||||
{
|
||||
bSwitchIsOKNow = true;
|
||||
ServerSelectPerk(SelectingPerk);
|
||||
bSwitchIsOKNow = false;
|
||||
bHadSwitchedVet = true;
|
||||
}
|
||||
else bHadSwitchedVet = false;
|
||||
}
|
||||
function MatchStarting()
|
||||
{
|
||||
bHadSwitchedVet = false;
|
||||
}
|
||||
|
||||
function AddKill(bool bLaserSightedEBRM14Headshotted, bool bMeleeKill, bool bZEDTimeActive, bool bM4Kill, bool bBenelliKill, bool bRevolverKill, bool bMK23Kill, bool bFNFalKill, bool bBullpupKill, string MapName)
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RKillsStat++;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.KillsStat++;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
function AddBloatKill(bool bWithBullpup)
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RBloatKillsStat++;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.BloatKillsStat++;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
|
||||
function AddSirenKill(bool bLawRocketImpact)
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RSirenKillsStat++;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.SirenKillsStat++;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
|
||||
function AddStalkerKillWithExplosives()
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RStalkersKilledWithExplosivesStat++;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.StalkersKilledWithExplosivesStat++;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
|
||||
function AddFireAxeKill();
|
||||
function AddChainsawScrakeKill();
|
||||
|
||||
function AddBurningCrossbowKill()
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RBurningCrossbowKillsStat++;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.BurningCrossbowKillsStat++;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
|
||||
function AddFeedingKill()
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RFeedingKillsStat++;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.FeedingKillsStat++;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
|
||||
function OnGrenadeExploded();
|
||||
function AddGrenadeKill();
|
||||
function OnShotHuntingShotgun();
|
||||
function AddHuntingShotgunKill();
|
||||
function KilledEnemyWithBloatAcid();
|
||||
function KilledFleshpound(bool bWithMeleeAttack, bool bWithAA12, bool bWithKnife, bool bWithClaymore);
|
||||
function AddMedicKnifeKill();
|
||||
|
||||
function AddGibKill(bool bWithM79)
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RGibbedEnemiesStat++;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.GibbedEnemiesStat++;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
|
||||
function AddFleshpoundGibKill()
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RGibbedFleshpoundsStat++;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.GibbedFleshpoundsStat++;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
|
||||
function AddSelfHeal()
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RSelfHealsStat++;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.SelfHealsStat++;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
|
||||
function AddOnlySurvivorOfWave()
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RSoleSurvivorWavesStat++;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.SoleSurvivorWavesStat++;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
|
||||
function AddDonatedCash(int Amount)
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RCashDonatedStat+=Amount;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.CashDonatedStat+=Amount;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
|
||||
function AddZedTime(float Amount)
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RTotalZedTimeStat+=Amount;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.TotalZedTimeStat+=Amount;
|
||||
}
|
||||
|
||||
function AddExplosivesDamage(int Amount)
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RExplosivesDamageStat+=Amount;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.ExplosivesDamageStat+=Amount;
|
||||
}
|
||||
|
||||
function AddHeadshotKills(int Amount)
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RHeadshotKillsStat+= Amount;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.HeadshotKillsStat+= Amount;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
function AddStalkerKills(int Amount)
|
||||
{
|
||||
bHasChanged = true;
|
||||
Rep.RStalkerKillsStat+=Amount;
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.StalkerKillsStat+= Amount;
|
||||
DelayedStatCheck();
|
||||
}
|
||||
|
||||
function WonLostGame( bool bDidWin )
|
||||
{
|
||||
if( bDidWin )
|
||||
{
|
||||
++Rep.WinsCount;
|
||||
if( MyStatsObject!=None )
|
||||
++MyStatsObject.WinsCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
++Rep.LostsCount;
|
||||
if( MyStatsObject!=None )
|
||||
++MyStatsObject.LostsCount;
|
||||
}
|
||||
bHasChanged = true;
|
||||
DelayedStatCheck();
|
||||
GoToState('');
|
||||
}
|
||||
|
||||
// Allow no default functionality with the stats.
|
||||
function OnStatsAndAchievementsReady();
|
||||
function PostNetBeginPlay();
|
||||
function InitializeSteamStatInt(int Index, int Value);
|
||||
function SetSteamAchievementCompleted(int Index);
|
||||
event SetLocalAchievementCompleted(int Index);
|
||||
function ServerSteamStatsAndAchievementsInitialized();
|
||||
function UpdateAchievementProgress();
|
||||
function int GetAchievementCompletedCount();
|
||||
event OnPerkAvailable();
|
||||
function WonLongGame(string MapName, float Difficulty);
|
||||
function AddDemolitionsPipebombKill();
|
||||
function AddSCARKill();
|
||||
function AddCrawlerKilledInMidair();
|
||||
function Killed8ZedsWithGrenade();
|
||||
function Killed10ZedsWithPipebomb();
|
||||
function KilledHusk(bool bDamagedFriendly);
|
||||
function AddMac10BurnDamage(int Amount);
|
||||
function AddGorefastBackstab();
|
||||
function ScrakeKilledByFire();
|
||||
function KilledCrawlerWithCrossbow();
|
||||
function OnLARReloaded();
|
||||
function AddStalkerKillWithLAR();
|
||||
function KilledHuskWithPistol();
|
||||
function AddDroppedTier3Weapon();
|
||||
function Survived10SecondsAfterVomit();
|
||||
function CheckChristmasAchievementsCompleted();
|
||||
function PlayerDied();
|
||||
function KilledPatriarch(bool bPatriarchHealed, bool bKilledWithLAW, bool bSuicidalDifficulty, bool bOnlyUsedCrossbows, bool bClaymore, string MapName);
|
||||
function WonGame(string MapName, float Difficulty, bool bLong);
|
||||
|
||||
function Destroyed()
|
||||
{
|
||||
if( Rep!=None )
|
||||
{
|
||||
if( MyStatsObject!=None )
|
||||
MyStatsObject.SetCustomValues(Rep.CustomLink);
|
||||
Rep.Destroy();
|
||||
Rep = None;
|
||||
}
|
||||
if( PlayerOwner!=None && !PlayerOwner.bDeleteMe )
|
||||
{
|
||||
// Was destroyed mid-game for random reason, respawn.
|
||||
MutatorOwner.PendingPlayers[MutatorOwner.PendingPlayers.Length] = PlayerOwner;
|
||||
MutatorOwner.SetTimer(0.1,false);
|
||||
}
|
||||
Super.Destroyed();
|
||||
}
|
||||
|
||||
Auto state PlaytimeTimer
|
||||
{
|
||||
Begin:
|
||||
while( true )
|
||||
{
|
||||
Sleep(1.f);
|
||||
if( bStatsReadyNow && !PlayerOwner.PlayerReplicationInfo.bOnlySpectator )
|
||||
{
|
||||
++Rep.TotalPlayTime;
|
||||
if( MyStatsObject!=None )
|
||||
++MyStatsObject.TotalPlayTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
SelectingIndex=255
|
||||
}
|
||||
20
kf_sources/ServerPerksMut/Classes/ServerTempStats.uc
Normal file
20
kf_sources/ServerPerksMut/Classes/ServerTempStats.uc
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// Because this is most likely going to fail on init, spawn the real stats actor here...
|
||||
Class ServerTempStats extends KFSteamStatsAndAchievements;
|
||||
|
||||
function PostBeginPlay()
|
||||
{
|
||||
local KFPlayerController PlayerOwner;
|
||||
|
||||
PlayerOwner = KFPlayerController(Owner);
|
||||
if( PlayerOwner.Player==None )
|
||||
return; // very bad...
|
||||
Spawn(Class'ServerStStats',PlayerOwner);
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
bUsedCheats=True
|
||||
RemoteRole=ROLE_None
|
||||
LifeSpan=0.100000
|
||||
bNetNotify=False
|
||||
}
|
||||
132
kf_sources/ServerPerksMut/Classes/StatConvert.uc
Normal file
132
kf_sources/ServerPerksMut/Classes/StatConvert.uc
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
class StatConvert extends Commandlet;
|
||||
|
||||
const MagicNumber="76561197960265728";
|
||||
const MagicLength=12;
|
||||
|
||||
function int Main( string Parms )
|
||||
{
|
||||
local array<string> List;
|
||||
local int i,j,z;
|
||||
local StatsObject A,B;
|
||||
local string NewID;
|
||||
|
||||
List = GetPerObjectNames("ServerPerksStat","StatsObject",9999999);
|
||||
for( i=0; i<List.Length; ++i )
|
||||
{
|
||||
if( !IsLinuxID(List[i]) )
|
||||
{
|
||||
Log("Skip "$List[i],'Log');
|
||||
continue;
|
||||
}
|
||||
NewID = ToWindowsID(List[i]);
|
||||
if( NewID=="" )
|
||||
{
|
||||
Log("Skip Unknown ID "$List[i],'Log');
|
||||
continue;
|
||||
}
|
||||
A = new(None,List[i]) Class'StatsObject';
|
||||
B = new(None,NewID) Class'StatsObject';
|
||||
Log("Port "$List[i]$" ("$A.PlayerName$") -> "$NewID$" ("$B.PlayerName$")",'Log');
|
||||
if( B.PlayerName=="" )
|
||||
{
|
||||
B.PlayerName = A.PlayerName;
|
||||
B.PlayerIP = A.PlayerIP;
|
||||
B.SelectedVeterancy = A.SelectedVeterancy;
|
||||
B.SelectedChar = A.SelectedChar;
|
||||
}
|
||||
B.DamageHealedStat+=A.DamageHealedStat;
|
||||
B.WeldingPointsStat+=A.WeldingPointsStat;
|
||||
B.ShotgunDamageStat+=A.ShotgunDamageStat;
|
||||
B.HeadshotKillsStat+=A.HeadshotKillsStat;
|
||||
B.StalkerKillsStat+=A.StalkerKillsStat;
|
||||
B.BullpupDamageStat+=A.BullpupDamageStat;
|
||||
B.MeleeDamageStat+=A.MeleeDamageStat;
|
||||
B.FlameThrowerDamageStat+=A.FlameThrowerDamageStat;
|
||||
B.SelfHealsStat+=A.SelfHealsStat;
|
||||
B.SoleSurvivorWavesStat+=A.SoleSurvivorWavesStat;
|
||||
B.CashDonatedStat+=A.CashDonatedStat;
|
||||
B.FeedingKillsStat+=A.FeedingKillsStat;
|
||||
B.BurningCrossbowKillsStat+=A.BurningCrossbowKillsStat;
|
||||
B.GibbedFleshpoundsStat+=A.GibbedFleshpoundsStat;
|
||||
B.StalkersKilledWithExplosivesStat+=A.StalkersKilledWithExplosivesStat;
|
||||
B.GibbedEnemiesStat+=A.GibbedEnemiesStat;
|
||||
B.BloatKillsStat+=A.BloatKillsStat;
|
||||
B.SirenKillsStat+=A.SirenKillsStat;
|
||||
B.KillsStat+=A.KillsStat;
|
||||
B.ExplosivesDamageStat+=A.ExplosivesDamageStat;
|
||||
B.TotalPlayTime+=A.TotalPlayTime;
|
||||
B.WinsCount+=A.WinsCount;
|
||||
B.LostsCount+=A.LostsCount;
|
||||
B.TotalZedTimeStat+=A.TotalZedTimeStat;
|
||||
// Merge custom stats.
|
||||
for( j=(A.CC.Length-1); j>=0; --j )
|
||||
{
|
||||
for( z=(B.CC.Length-1); z>=0; --z )
|
||||
if( B.CC[z].N==A.CC[j].N )
|
||||
break;
|
||||
if( z==-1 )
|
||||
{
|
||||
z = B.CC.Length;
|
||||
B.CC.Length = z+1;
|
||||
B.CC[z].N = A.CC[j].N;
|
||||
B.CC[z].V = A.CC[j].V;
|
||||
}
|
||||
else if( IsDigitStr(B.CC[z].V) && IsDigitStr(A.CC[j].V) )
|
||||
B.CC[z].V = string(int(B.CC[z].V) + int(A.CC[j].V));
|
||||
else B.CC[z].V = A.CC[j].V;
|
||||
}
|
||||
A.ClearConfig();
|
||||
B.SaveConfig();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static final function bool IsLinuxID( string S )
|
||||
{
|
||||
return (Len(S)<MagicLength);
|
||||
}
|
||||
static final function string ToWindowsID( string S )
|
||||
{
|
||||
local int i,la,lb,rest,p;
|
||||
local string Result;
|
||||
|
||||
la = Len(S);
|
||||
lb = Len(MagicNumber);
|
||||
for( i=1; i<=lb; ++i )
|
||||
{
|
||||
if( i<=la )
|
||||
{
|
||||
if( !IsDigit(Asc(Mid(S,la-i,1))) ) // Not a SteamID, something else here.
|
||||
return "";
|
||||
p = int(Mid(S,la-i,1));
|
||||
}
|
||||
else p = 0;
|
||||
p += rest + int(Mid(MagicNumber,lb-i,1));
|
||||
if( p>=10 )
|
||||
{
|
||||
rest = p/10;
|
||||
p -= rest*10;
|
||||
}
|
||||
else rest = 0;
|
||||
Result = string(p)$Result;
|
||||
}
|
||||
if( rest>0 )
|
||||
Result = string(rest)$Result;
|
||||
return Result;
|
||||
}
|
||||
static final function bool IsDigit( int S )
|
||||
{
|
||||
return (S>=48 && S<=57);
|
||||
}
|
||||
static final function bool IsDigitStr( string S )
|
||||
{
|
||||
return (string(int(S))==S);
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
HelpCmd="Convert ServerPerks stats LinuxID to WindowsID."
|
||||
HelpUsage="Run UCC.exe ServerPerksMut.StatConvert /norunaway"
|
||||
HelpWebLink="http://forums.tripwireinteractive.com/showthread.php?t=36065"
|
||||
IsServer=False
|
||||
IsClient=False
|
||||
}
|
||||
203
kf_sources/ServerPerksMut/Classes/StatsObject.uc
Normal file
203
kf_sources/ServerPerksMut/Classes/StatsObject.uc
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
// Written by .:..: (2009)
|
||||
Class StatsObject extends Object
|
||||
PerObjectConfig
|
||||
Config(ServerPerksStat);
|
||||
|
||||
struct FCustomConfig
|
||||
{
|
||||
var config name N;
|
||||
var config string V;
|
||||
};
|
||||
|
||||
var config array<FCustomConfig> CC;
|
||||
var config string PlayerName,PlayerIP,SelectedVeterancy,SelectedChar;
|
||||
var config int DamageHealedStat, WeldingPointsStat, ShotgunDamageStat, HeadshotKillsStat,
|
||||
StalkerKillsStat, BullpupDamageStat, MeleeDamageStat, FlameThrowerDamageStat,
|
||||
SelfHealsStat, SoleSurvivorWavesStat, CashDonatedStat, FeedingKillsStat,
|
||||
BurningCrossbowKillsStat, GibbedFleshpoundsStat, StalkersKilledWithExplosivesStat,
|
||||
GibbedEnemiesStat, BloatKillsStat, SirenKillsStat, KillsStat, ExplosivesDamageStat, TotalPlayTime, WinsCount, LostsCount;
|
||||
var config byte PerkIndex;
|
||||
var config float TotalZedTimeStat;
|
||||
var transient class<SRVeterancyTypes> ChosenPerk;
|
||||
|
||||
var name StrToNameProp;
|
||||
var int ID;
|
||||
var bool bStatsChanged;
|
||||
|
||||
final function name StringToName( string S )
|
||||
{
|
||||
if( S=="" )
|
||||
return '';
|
||||
SetPropertyText("StrToNameProp",S);
|
||||
return StrToNameProp;
|
||||
}
|
||||
final function SetCustomValues( SRCustomProgress L )
|
||||
{
|
||||
local int i,c;
|
||||
|
||||
if( Class'ServerPerksMut'.Default.bOverrideUnusedCustomStats )
|
||||
CC.Length = 0;
|
||||
|
||||
c = CC.Length;
|
||||
for( L=L; L!=None; L=L.NextLink )
|
||||
{
|
||||
// Look for excisting entry.
|
||||
for( i=0; i<c; ++i )
|
||||
if( CC[i].N==L.Class.Name )
|
||||
{
|
||||
CC[i].V = L.GetProgress();
|
||||
break;
|
||||
}
|
||||
|
||||
// Add new entry.
|
||||
if( i==c )
|
||||
{
|
||||
CC.Length = c+1;
|
||||
CC[c].N = L.Class.Name;
|
||||
CC[c].V = L.GetProgress();
|
||||
++c;
|
||||
}
|
||||
}
|
||||
}
|
||||
final function GetCustomValues( SRCustomProgress L )
|
||||
{
|
||||
local int i,c;
|
||||
|
||||
c = CC.Length;
|
||||
for( L=L; L!=None; L=L.NextLink )
|
||||
{
|
||||
for( i=0; i<c; ++i )
|
||||
if( CC[i].N==L.Class.Name )
|
||||
{
|
||||
L.SetProgress(CC[i].V);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final function SetSelectedChar( string S )
|
||||
{
|
||||
SelectedChar = S;
|
||||
bStatsChanged = true;
|
||||
}
|
||||
final function SetSelectedPerk( name S )
|
||||
{
|
||||
SelectedVeterancy = string(S);
|
||||
}
|
||||
final function name GetSelectedPerk()
|
||||
{
|
||||
local int i;
|
||||
|
||||
i = InStr(SelectedVeterancy,".");
|
||||
if( i>=0 )
|
||||
SelectedVeterancy = Mid(SelectedVeterancy,i+1);
|
||||
return StringToName(SelectedVeterancy);
|
||||
}
|
||||
|
||||
final function string GetSaveData()
|
||||
{
|
||||
local string Result;
|
||||
|
||||
Result = SelectedVeterancy$":"$PerkIndex$","$DamageHealedStat$","$WeldingPointsStat$","$ShotgunDamageStat$","$HeadshotKillsStat$","$StalkerKillsStat;
|
||||
Result = Result$","$BullpupDamageStat$","$MeleeDamageStat$","$FlameThrowerDamageStat$","$SelfHealsStat$","$SoleSurvivorWavesStat;
|
||||
Result = Result$","$CashDonatedStat$","$FeedingKillsStat$","$BurningCrossbowKillsStat$","$GibbedFleshpoundsStat$","$StalkersKilledWithExplosivesStat;
|
||||
Result = Result$","$GibbedEnemiesStat$","$BloatKillsStat$","$SirenKillsStat$","$KillsStat$","$ExplosivesDamageStat;
|
||||
Result = Result$","$int(TotalZedTimeStat)$","$TotalPlayTime$","$WinsCount$","$LostsCount$",'"$SelectedChar$"'";
|
||||
Result = Result$","$GetPropertyText("CC");
|
||||
return Result;
|
||||
}
|
||||
static final function int GetNextValue( out string S )
|
||||
{
|
||||
local int i,Result;
|
||||
|
||||
i = InStr(S,",");
|
||||
if( i==-1 )
|
||||
{
|
||||
Result = int(S);
|
||||
S = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = int(Left(S,i));
|
||||
S = Mid(S,i+1);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
static final function string GetNextStrValue( out string S )
|
||||
{
|
||||
local int i;
|
||||
local string Result;
|
||||
|
||||
i = InStr(S,",");
|
||||
if( i==-1 )
|
||||
{
|
||||
if( Left(S,1)=="'" )
|
||||
Result = Mid(S,1,Len(S)-2);
|
||||
//else bad string.
|
||||
S = "";
|
||||
}
|
||||
else if( Left(S,1)=="'" && Mid(S,i-1,1)=="'" )
|
||||
{
|
||||
Result = Mid(S,1,i-2);
|
||||
S = Mid(S,i+1);
|
||||
}
|
||||
else // bad string again.
|
||||
{
|
||||
S = Mid(S,i+1);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
final function SetSaveData( string S )
|
||||
{
|
||||
local int i;
|
||||
|
||||
i = InStr(S,",");
|
||||
if( i==-1 )
|
||||
return;
|
||||
SelectedVeterancy = Left(S,i);
|
||||
S = Mid(S,i+1);
|
||||
i = InStr(SelectedVeterancy,":");
|
||||
if( i==-1 )
|
||||
PerkIndex = 255;
|
||||
else
|
||||
{
|
||||
PerkIndex = int(Mid(SelectedVeterancy,i+1));
|
||||
SelectedVeterancy = Left(SelectedVeterancy,i);
|
||||
}
|
||||
|
||||
DamageHealedStat = GetNextValue(S);
|
||||
WeldingPointsStat = GetNextValue(S);
|
||||
ShotgunDamageStat = GetNextValue(S);
|
||||
HeadshotKillsStat = GetNextValue(S);
|
||||
StalkerKillsStat = GetNextValue(S);
|
||||
BullpupDamageStat = GetNextValue(S);
|
||||
MeleeDamageStat = GetNextValue(S);
|
||||
FlameThrowerDamageStat = GetNextValue(S);
|
||||
SelfHealsStat = GetNextValue(S);
|
||||
SoleSurvivorWavesStat = GetNextValue(S);
|
||||
CashDonatedStat = GetNextValue(S);
|
||||
FeedingKillsStat = GetNextValue(S);
|
||||
BurningCrossbowKillsStat = GetNextValue(S);
|
||||
GibbedFleshpoundsStat = GetNextValue(S);
|
||||
StalkersKilledWithExplosivesStat = GetNextValue(S);
|
||||
GibbedEnemiesStat = GetNextValue(S);
|
||||
BloatKillsStat = GetNextValue(S);
|
||||
SirenKillsStat = GetNextValue(S);
|
||||
KillsStat = GetNextValue(S);
|
||||
ExplosivesDamageStat = GetNextValue(S);
|
||||
TotalZedTimeStat = GetNextValue(S);
|
||||
TotalPlayTime = GetNextValue(S);
|
||||
WinsCount = GetNextValue(S);
|
||||
LostsCount = GetNextValue(S);
|
||||
SelectedChar = GetNextStrValue(S);
|
||||
|
||||
CC.Length = 0;
|
||||
if( Len(S)>0 )
|
||||
SetPropertyText("CC",S);
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
PerkIndex=255
|
||||
id=-1
|
||||
}
|
||||
18
kf_sources/ServerPerksMut/Classes/index.html
Normal file
18
kf_sources/ServerPerksMut/Classes/index.html
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<html>
|
||||
<head><title>Index of /kf_sources/ServerPerksMut/Classes/</title></head>
|
||||
<body>
|
||||
<h1>Index of /kf_sources/ServerPerksMut/Classes/</h1><hr><pre><a href="../">../</a>
|
||||
<a href="AdminMenuHandle.uc">AdminMenuHandle.uc</a> 06-Oct-2019 10:31 27582
|
||||
<a href="DatabaseUdpLink.uc">DatabaseUdpLink.uc</a> 06-Oct-2019 10:31 4557
|
||||
<a href="FTPDataConnection.uc">FTPDataConnection.uc</a> 06-Oct-2019 10:31 759
|
||||
<a href="FTPTcpLink.uc">FTPTcpLink.uc</a> 06-Oct-2019 10:31 15614
|
||||
<a href="FragFireFix.uc">FragFireFix.uc</a> 06-Oct-2019 10:31 281
|
||||
<a href="SRGameRules.uc">SRGameRules.uc</a> 06-Oct-2019 10:31 1638
|
||||
<a href="ServerPerkWebAdmin.uc">ServerPerkWebAdmin.uc</a> 06-Oct-2019 10:31 8657
|
||||
<a href="ServerPerksMut.uc">ServerPerksMut.uc</a> 06-Oct-2019 10:31 30591
|
||||
<a href="ServerStStats.uc">ServerStStats.uc</a> 06-Oct-2019 10:31 18774
|
||||
<a href="ServerTempStats.uc">ServerTempStats.uc</a> 06-Oct-2019 10:31 495
|
||||
<a href="StatConvert.uc">StatConvert.uc</a> 06-Oct-2019 10:31 3572
|
||||
<a href="StatsObject.uc">StatsObject.uc</a> 06-Oct-2019 10:31 5094
|
||||
</pre><hr></body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue