Class AdminMenuHandle extends Info; var bool bMainMenuOpened,bSendCat,bSendWep,bConfigDirty; var KFPlayerController PlayerOwner; var UI_Replication Rep; var array 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 StatNames,NewStatValues; struct FSettingType { var byte Type; var string ExtraValue,Name,PropName; }; var array 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=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=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=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 WC; WC = Class(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 WC; local string S; if( EditingIndex>0 && !bSendWep && EditingIndex<=MutatorOwner.TraderInventory.Length ) { WC = Class(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=0 && !bSendCat && EditingCategory=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(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=0 && !bSendCat && EditingCategory(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=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") }